Attributi personalizzati - Sì o no?


254

Di recente ho letto sempre di più su persone che usano attributi personalizzati nei loro tag HTML, principalmente allo scopo di incorporare alcuni bit extra di dati da utilizzare nel codice javascript.

Speravo di raccogliere un feedback sull'utilizzo o meno di attributi personalizzati è una buona pratica, e anche quali sono alcune alternative.

Sembra che possa davvero semplificare sia il lato server sia il codice lato client, ma non è conforme al W3C.

Dovremmo utilizzare attributi HTML personalizzati nelle nostre app Web? Perché o perché no?

Per coloro che pensano che gli attributi personalizzati siano una buona cosa: quali sono alcune cose da tenere a mente quando le si utilizza?

Per coloro che pensano che gli attributi personalizzati siano una cosa negativa: quali alternative usi per realizzare qualcosa di simile?

Aggiornamento: sono principalmente interessato al ragionamento alla base dei vari metodi, nonché ai punti sul perché un metodo è migliore di un altro. Penso che tutti possiamo trovare 4-5 modi diversi per ottenere la stessa cosa. (elementi nascosti, script incorporati, classi extra, analisi delle informazioni dagli ID, ecc.).

Aggiornamento 2: sembra che la data-caratteristica dell'attributo HTML 5 abbia molto supporto qui (e tendo a concordare, sembra un'opzione solida). Finora non ho visto molto in termini di confutazioni per questo suggerimento. Ci sono problemi / insidie ​​di cui preoccuparsi nell'utilizzare questo approccio? O è semplicemente una invalidazione "innocua" delle attuali specifiche del W3C?


Onestamente, la mia posizione iniziale è che sono non una cosa negativa, che può essere piuttosto controversa con i puristi. Sento che ho davvero bisogno di sedermi e valutare tutte le opzioni disponibili per eseguire correttamente il backup, quindi la necessità di scrivere il lungo saggio.
Paolo Bergantino,

Per fare ciò potresti aver bisogno solo di alcuni contro-esempi: di cosa stai cercando di implementare, di come sia conveniente farlo con attributi personalizzati e perché quella soluzione sia migliore e non peggiore di altre soluzioni senza attributi personalizzati.
ChrisW,

@ChrisW Chiedo principalmente per interesse, non per qualche applicazione specifica.
TM.

Bene, ci sono molte opzioni per portare i dati sul lato client: campi di input nascosti, elenchi di definizioni nascoste, classi, plugin di metadati, un enorme dizionario Javascript (oggetto) con tutti i dati mappati separatamente, attributi personalizzati, attributi dei dati ( HTML5), ecc. Voglio esplorare tutti questi aspetti, considerare i loro meriti, le loro insidie ​​e infine giungere a una conclusione. Questo post mi ha fatto finalmente iniziare a scrivere questo. :) Dovrebbe essere fatto prima del 2010.
Paolo Bergantino,

2
@Paolo non puoi semplicemente dire di aver scritto un saggio rispondendo a questa domanda senza darci il link. Non fico.
Connell,

Risposte:


253

HTML 5 consente esplicitamente attributi personalizzati che iniziano con data. Quindi, per esempio, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p>è valido. Dal momento che è ufficialmente supportato da uno standard, penso che questa sia l'opzione migliore per gli attributi personalizzati. E non richiede di sovraccaricare altri attributi con gli hack, quindi il tuo HTML può rimanere semantico.

Fonte: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes


Questo è un buon approccio .. Ma dubito che funzionerà con te per supportare IE 6 e altri vecchi browser.
cllpse

8
Sono abbastanza sicuro che funziona con i browser più vecchi; gli attributi vengono aggiunti al DOM, da cui è possibile accedervi.
Ms2ger,

12
Funziona perfettamente con tutti i browser che utilizzano il metodo getAttribute () su un HTMLElement. Inoltre, man mano che il supporto del set di dati HTML5 aumenta, puoi facilmente aggiungerlo.
ajm

1
@Chuck apparentemente puoi aggiungere Attributi al DOCTYPE: rodsdot.com/html/… - non che penso sia una buona idea, ma sembra standardizzato.
Michael Stum

2
@Wahnfrieden: w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8 che è il metodo approvato, conforme agli standard. Che è ben descritto e dimostrato qui: rodsdot.com/html/… Come precedentemente pubblicato da altri.
rdivilbiss,

95

Ecco una tecnica che ho usato di recente:

<div id="someelement">

    <!-- {
        someRandomData: {a:1,b:2},
        someString: "Foo"
    } -->

    <div>... other regular content...</div>
</div>

L'oggetto commento si lega all'elemento genitore (es. #Someelement).

Ecco il parser: http://pastie.org/511358

Per ottenere i dati per qualsiasi elemento particolare, è sufficiente chiamare parseDatacon un riferimento a quell'elemento passato come unico argomento:

var myElem = document.getElementById('someelement');

var data = parseData( myElem );

data.someRandomData.a; // <= Access the object staight away

Può essere più succinto di così:

<li id="foo">
    <!--{specialID:245}-->
    ... content ...
</li>

Accedi ad esso:

parseData( document.getElementById('foo') ).specialID; // <= 245

L'unico svantaggio di utilizzare questo è che non può essere utilizzato con elementi a chiusura automatica (ad es. <img/>), Poiché i commenti devono essere all'interno dell'elemento per essere considerati come i dati di tale elemento.


MODIFICA :

Notevoli benefici di questa tecnica:

  • Facile da implementare
  • Fa non invalidate HTML / XHTML
  • Facile da usare / comprendere (notazione JSON di base)
  • Discreto e semanticamente più pulito della maggior parte delle alternative

Ecco il codice parser (copiato dal http://pastie.org/511358 collegamento ipertestuale sopra, nel caso in cui non fosse mai disponibile su pastie.org):

var parseData = (function(){

    var getAllComments = function(context) {

            var ret = [],
                node = context.firstChild;

            if (!node) { return ret; }

            do {
                if (node.nodeType === 8) {
                    ret[ret.length] = node;
                }
                if (node.nodeType === 1) {
                    ret = ret.concat( getAllComments(node) );
                }
            } while( node = node.nextSibling );

            return ret;

        },
        cache = [0],
        expando = 'data' + +new Date(),
        data = function(node) {

            var cacheIndex = node[expando],
                nextCacheIndex = cache.length;

            if(!cacheIndex) {
                cacheIndex = node[expando] = nextCacheIndex;
                cache[cacheIndex] = {};
            }

            return cache[cacheIndex];

        };

    return function(context) {

        context = context || document.documentElement;

        if ( data(context) && data(context).commentJSON ) {
            return data(context).commentJSON;
        }

        var comments = getAllComments(context),
            len = comments.length,
            comment, cData;

        while (len--) {
            comment = comments[len];
            cData = comment.data.replace(/\n|\r\n/g, '');
            if ( /^\s*?\{.+\}\s*?$/.test(cData) ) {
                try {
                    data(comment.parentNode).commentJSON =
                        (new Function('return ' + cData + ';'))();
                } catch(e) {}
            }
        }

        return data(context).commentJSON || true;

    };

})();

2
Per curiosità, quale metodo usi per i tag a chiusura automatica? In genere ho bisogno di usare qualcosa di simile su <input> elementi (per aiutare nelle regole di convalida lato client). Quale alternativa prendi in quella situazione?
TM.

2
Probabilmente userei una tecnica simile, invece dei dati del commento che si legano al "parentNode" potrebbe legarsi al "precedenteSibling" del commento ... Quindi potresti avere il commento immediatamente dopo <input /> e lavoro: <input /> <! - {data: 123} ->
James,

7
qualcuno dovrebbe renderlo un plugin jquery
SeanDowney,

10
I commenti dovrebbero poter essere modificati / eliminati senza interrompere nulla. Questo è il punto. Quindi è una cattiva idea inserire nei commenti qualcosa di importante per il markup o il codice. I futuri sviluppatori potrebbero facilmente pensare di essere commenti ed eliminarli. Abbiamo già una vera soluzione a questa domanda: attributi personalizzati con prefisso "data-". Questo approccio non dovrebbe mai essere usato.
MGOwen,

6
Vorrei rafforzare l'affermazione di @MGOwen: non usare i commenti per aggiungere funzionalità. Specialmente in HTML. Non stai usando i minificatori? Non sarai in grado di rimuovere i commenti senza rompere il codice. Questo significa anche che non puoi più aggiungere commenti reali.
Olivictor,

15

Puoi creare qualsiasi attributo se specifichi uno schema per la tua pagina.

Per esempio:

Aggiungi questo

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:addthis="http://www.addthis.com/help/api-spec">
...
<a addthis:title="" addthis:url="" ...>

Facebook (anche i tag)

<html xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml">
...
<fb:like href="http://developers.facebook.com/" width="450" height="80"/>

10

Il modo più semplice per evitare l'uso di attributi personalizzati è utilizzare gli attributi esistenti.

utilizzare nomi di classe significativi e pertinenti.
Ad esempio, fai qualcosa del tipo: type='book'e type='cd', per rappresentare libri e cd. Le lezioni sono molto migliori per rappresentare ciò che è qualcosa .

per esempio class='book'

Ho usato attributi personalizzati in passato, ma onestamente, non è davvero necessario per loro se si utilizzano gli attributi esistenti in modo semanticamente significativo.

Per fare un esempio più concreto, supponiamo che tu abbia un sito che fornisce collegamenti a diversi tipi di negozi. È possibile utilizzare quanto segue:

<a href='wherever.html' id='bookstore12' class='book store'>Molly's books</a>
<a href='whereverelse.html' id='cdstore3' class='cd store'>James' Music</a>

lo stile CSS può usare classi come:

.store { }
.cd.store { }
.book.store { }

Nell'esempio sopra vediamo che entrambi sono collegamenti a negozi (al contrario degli altri collegamenti non correlati sul sito) e uno è un negozio di cd, e l'altro è un negozio di libri.


4
Un buon punto, ma per essere onesti, "type" è valido solo su alcuni tag e quando è un attributo valido, ha anche un elenco di valori validi, quindi non sei ancora veramente conforme a w3c.
TM.

1
il punto era che NON dovresti usare il tag type per questo. quindi il Se tu fossi ... allora dovresti ... Modificherò per renderlo più chiaro
Jonathan Fingland

Tendo a rendere i miei attributi di "classe" con sapori facendo in modo che alcuni di essi vengano aggiunti con un qualche tipo di "qualificatore". per i div relativi solo al layout, vorrei che la sua classe fosse "layout-xxx", o per i div interni che circondano una parte importante, come un libro o un negozio, avrei un content-book o content-store . quindi nel mio JavaScript, ho una funzione che antepone quelle cose sul tag in base a ciò che sto cercando. aiuta a mantenere le cose pulite e organizzate per me, ma richiede un certo livello di disciplina e pre-organizzazione.
Ape-inago,

2
@Jonathan la cosa di doppia classe funziona alla grande, tranne nei casi in cui i "valori" non sono noti. Ad esempio, se si tratta di una sorta di ID intero, non possiamo selezionare molto bene per ogni possibile caso. Ci viene quindi lasciato analizzare manualmente l'attributo class che è sicuramente fattibile, ma non così chiaro nel codice, e in alcuni casi potrebbe essere molto lento (se ci sono molti elementi candidati da analizzare).
TM.

2
purtroppo, scrivere selettori CSS per due classi contemporaneamente (.ab notate lo spazio vuoto mancante) non funziona in IE. funziona su Firefox e altri browser però. tuttavia, usare le classi è un ottimo modo per incorporare un ulteriore significato semantico nel tuo markup
knittl

6

Incorporare i dati nel dom e utilizzare i metadati per jQuery .

Tutti i buoni plug-in supportano il plug-in dei metadati (consentendo le opzioni per tag).

Consente inoltre strutture dati / dati infinitamente complesse, nonché coppie chiave-valore.

<li class="someclass {'some': 'random,'json':'data'} anotherclass">...</li>

O

<li class="someclass" data="{'some':'random', 'json': 'data'}">...</li>

O

<li class="someclass"><script type="data">{"some":"random","json":"data"}</script> ...</li>

Quindi ottenere i dati in questo modo:

var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');

22
La corruzione dell'attributo class quando esiste un modo approvato dal W3C per specificare gli attributi personalizzati è probabilmente il motivo per cui sei stato votato verso il basso.
rdivilbiss,

2
corrompere l'attributo class è solo uno dei modi per usare il plugin; non è l' unico modo.
antony.trupe,

1
Un altro motivo per cui sei stato votato è suggerire un plug-in in cui non è necessario alcun plug-in.
meandre,

4

Non vedo alcun problema nell'uso delle funzionalità XHTML esistenti senza interrompere nulla o estendere lo spazio dei nomi. Diamo un'occhiata a un piccolo esempio:

<div id="some_content">
 <p>Hi!</p>
</div>

Come aggiungere ulteriori informazioni a some_content senza attributi aggiuntivi? Che ne dici di aggiungere un altro tag come il seguente?

<div id="some_content">
 <div id="some_content_extended" class="hidden"><p>Some alternative content.</p></div>
 <p>Hi!</p>
</div>

Mantiene la relazione tramite un id / estensione ben definito "_extended" di tua scelta e dalla sua posizione nella gerarchia. Uso spesso questo approccio insieme a jQuery e senza usare effettivamente tecniche simili ad Ajax.


2
Il problema con l'aggiunta di tag nidificati come questo è che tende a creare codice lato server MOLTO ingombrante e brutto (JSP / ASP / DTL ecc.)
TM.

3

Anzi. Prova invece qualcosa del genere:

<div id="foo"/>

<script type="text/javascript">
  document.getElementById('foo').myProperty = 'W00 H00! I can add JS properties to DOM nodes without using custom attributes!';
</script>

1
Preferisci quindi scrivere un sacco di tag di script extra su tutto il tuo documento per pagine dinamiche? Userei le assegnazioni manuali di javascript quando le informazioni vengono aggiunte sul lato client, ma questo problema riguarda principalmente cosa rendere sul server. Inoltre, jQuery.data () è molto meglio del tuo metodo.
TM.

La risposta sopra è un esempio indipendente dal framework per dimostrare la funzionalità. Potresti facilmente espandere l'essenza di esso per rendere il codice abbastanza conciso. Ad esempio, <div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <script type = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', bar : 'ecc.', baz: 3.14159}); </script> Se stai usando jQuery (non che tu l'abbia menzionato nella tua domanda originale), usa sicuramente il metodo data - ecco a cosa serve. In caso contrario, il passaggio di dati tra i livelli architetturali è un uso perfettamente valido dei tag di script incorporati.
Anon,

È sicuramente un'opzione ovvia e valida. A mio avviso, ingombra il codice molto più di molte altre alternative che non usano attributi personalizzati. E per essere chiari, non sto cercando di essere combattivo o maleducato, sto solo cercando di convincere alcuni dei tuoi ragionamenti sul perché preferisci questo metodo. Hai fornito un'alternativa ma non è proprio di questo che si tratta.
TM.

1
Non penso che ci sia un problema con questo approccio alla rottura dei browser. Microsoft utilizza questo meccanismo esatto come meccanismo preferito nelle pagine ASP.NET. (chiamando RegisterExpandoAttribute sul lato server). La domanda sembra focalizzata sul client e non sul server, ma sul lato server tutti questi approcci potrebbero essere (dovrebbero essere?) Astratti.
Adrian,

3
I pro di questo approccio: - Produce un markup valido (anche con browser / specifiche precedenti). - Rende chiaro l'intento dei dati (che saranno consumati da JS). - È coerente con l'elemento senza fare un uso intelligente di altre funzionalità (come i commenti). - Non richiede analisi speciali. Dal punto di vista del server, puoi pensarlo come un RPC.
piroscafo25

2

Non sto usando gli attributi personalizzati, perché sto eseguendo l'output di XHTML, perché voglio che i dati siano leggibili meccanicamente da software di terze parti (anche se, se lo volessi, potrei estendere lo schema XHTML).

In alternativa agli attributi personalizzati, principalmente trovo sufficienti gli attributi id e class (ad es. Come menzionato in altre risposte).

Inoltre, considera questo:

  • Se i dati aggiuntivi devono essere leggibili dall'uomo e leggibili automaticamente, devono essere codificati utilizzando tag e testo HTML (visibili) anziché come attributi personalizzati.

  • Se non è necessario che sia leggibile dall'uomo, forse può essere codificato utilizzando tag e testo HTML invisibili .

Alcune persone fanno un'eccezione: consentono attributi personalizzati, aggiunti al DOM da Javascript sul lato client in fase di esecuzione. Ritengono che sia OK: poiché gli attributi personalizzati vengono aggiunti al DOM solo in fase di esecuzione, l'HTML non contiene attributi personalizzati.


1

Abbiamo creato un editor basato sul Web che comprende un sottoinsieme di HTML, un sottoinsieme molto rigoroso (compreso quasi universalmente dai client di posta). Dobbiamo esprimere cose come <td width="@INSWIDTH_42@">nel database, ma non possiamo averlo nel DOM, altrimenti il ​​browser in cui viene eseguito l'editor, impazzisce (o è più probabile che impazzisca di quanto sia probabile che impazzisca per gli attributi personalizzati) . Volevamo il trascinamento della selezione, quindi inserirlo esclusivamente nel DOM era fuori, così come quello di jquery .data()(i dati extra non venivano copiati correttamente). Probabilmente avevamo anche bisogno dei dati extra per il passaggio .html(). Alla fine abbiamo deciso di utilizzare <td width="1234" rs-width="@INSWIDTH_42@">durante il processo di modifica, e quindi quando POST tutto, rimuoviamo widthe facciamo una ricerca e distruzione di regex s/rs-width=/width=/g.

All'inizio il ragazzo che scriveva la maggior parte di questo era il nazista della convalida su questo problema e provava di tutto per evitare il nostro attributo personalizzato, ma alla fine acconsentì quando nient'altro sembrava funzionare per TUTTI i nostri requisiti. Aiutò quando si rese conto che l'attributo personalizzato non sarebbe mai apparso in una e-mail. Abbiamo preso in considerazione la possibilità di codificare i nostri dati extra class, ma abbiamo deciso che sarebbe stato il maggiore dei due mali.

Personalmente, preferisco avere le cose pulite e passare validatori, ecc., Ma come dipendente dell'azienda devo ricordare che la mia responsabilità principale è far avanzare la causa dell'azienda (fare più soldi il più rapidamente possibile), non quella del mio desiderio egoistico di purezza tecnica. Gli strumenti dovrebbero funzionare per noi; non noi per loro.


1

So che le persone sono contrarie, ma ho trovato una soluzione super breve per questo. Se si desidera utilizzare un attributo personalizzato come "mio", ad esempio:

<a href="test.html" mine-one="great" mine-two="awesome">Test</a>

Quindi è possibile eseguire questo codice per recuperare un oggetto proprio come fa jquery.data ().

var custom_props = {} ;
$.each($(".selector")[0].attributes, function(i,x) {
    if (this.specified && x.name.indexOf("mine-") !== -1) 
        self.new_settings[x.name.replace("modal-","")] = x.value;
});

0

Spec: Crea un controllo TextBox ASP.NET che formatta dinamicamente il testo come numero, in base alle proprietà "DecimalSeparator" e "ThousandsSeparator", utilizzando JavaScript.


Un modo per trasferire queste proprietà dal controllo a JavaScript è fare in modo che il controllo esegua il rendering delle proprietà personalizzate:

<input type="text" id="" decimalseparator="." thousandsseparator="," />

Le proprietà personalizzate sono facilmente accessibili tramite JavaScript. E mentre una pagina che utilizza elementi con proprietà personalizzate non verrà convalidata , il rendering di quella pagina non sarà influenzato.


Ho solo utilizzare questo approccio quando voglio associare tipi semplici come stringhe e numeri interi in elementi HTML da utilizzare con JavaScript. Se voglio semplificare l'identificazione degli elementi HTML, farò uso delle proprietà class e id .


0

Per le app Web complesse, trascino attributi personalizzati ovunque.

Per altre pagine pubbliche, utilizzo l'attributo "rel" e trasferisco tutti i miei dati lì in JSON e poi li decodifico con MooTools o jQuery:

<a rel="{color:red, awesome:true, food: tacos}">blah</a>

Sto provando a rimanere con l'attributo di dati HTML 5 ultimamente solo per "preparare", ma non è stato ancora naturale.


-1

Uso sempre campi personalizzati, ad esempio <ai = "" .... Quindi riferimento a i con jquery. HTML non valido, sì. Funziona bene, sì.


Qualcosa sembra mancare qui. Il tuo tag è stato completo, qui?
Stuart Siegler,

Come si può capire questo? Per favore completa la tua risposta.
Rahul Raj,

-2

A mio modesto parere, gli attributi personalizzati non dovrebbero essere usati in quanto non convalidati. In alternativa a ciò, puoi definire molte classi per un singolo elemento come:

<div class='class1 class2 class3'>
    Lorem ipsum
</div>

10
personalmente, penso che questo sia un terribile esempio. i tuoi nomi di classe definiscono l'aspetto, non lo scopo. Pensa a quando vuoi cambiare tutti i div simili ... dovresti andare e cambiarli tutti in span-11 o simili. le classi dovrebbero definire ciò che È. i fogli di stile dovrebbero definire l'aspetto di quelle cose
Jonathan Fingland,

Come useresti questo metodo per specificare più di un semplice flag? Tendo a concordare con la tua posizione e non utilizzo attributi personalizzati (sebbene lo stia prendendo in considerazione). Il vantaggio di avere una coppia chiave / valore sembra un po 'più utile della semplice aggiunta di un'altra classe.
TM.

@Jonathan Fingland: se si utilizza Compass, non è necessario impostare qui i nomi delle classi. Puoi semplicemente specificarli nel file .sass e il tuo markup sarà pulito.
Alan Haggai Alavi,

@Jonathan Fingland, l' classattributo non è assolutamente riservato ai "look". Un altro uso è "elaborazione generica da parte degli interpreti". Di questo parla la specifica: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup

@npup: interessante scelta di citazioni. Come ho affermato più di un anno fa, i fogli di stile definiscono come dovrebbero apparire queste cose (come fa l'attributo di stile, aggiungerò) e l'attributo class viene usato per definire lo scopo dell'elemento. Cioè, è specificamente utilizzato per definire ciò che È, e non come appare. Penso che potresti aver semplicemente letto male quello che ho detto, dato che siamo d'accordo per quanto posso dire.
Jonathan Fingland,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.