Attributs personnalisés - Oui ou non?


254

Récemment, j'ai lu de plus en plus sur les personnes utilisant des attributs personnalisés dans leurs balises HTML, principalement dans le but d'incorporer des bits de données supplémentaires à utiliser dans le code javascript.

J'espérais recueillir des commentaires sur la question de savoir si l'utilisation d'attributs personnalisés est une bonne pratique, ainsi que sur certaines alternatives.

Il semble que cela peut vraiment simplifier à la fois côté serveur et le code côté client, mais il est pas conforme aux normes W3C.

Devrions-nous utiliser des attributs HTML personnalisés dans nos applications Web? Pourquoi ou pourquoi pas?

Pour ceux qui pensent que les attributs personnalisés sont une bonne chose: quelles sont les choses à garder à l'esprit lors de leur utilisation?

Pour ceux qui pensent que les attributs personnalisés sont une mauvaise chose: quelles alternatives utilisez-vous pour accomplir quelque chose de similaire?

Mise à jour: Je suis principalement intéressé par le raisonnement derrière les différentes méthodes, ainsi que par les raisons pour lesquelles une méthode est meilleure qu'une autre. Je pense que nous pouvons tous trouver 4-5 façons différentes d'accomplir la même chose. (éléments cachés, scripts en ligne, classes supplémentaires, analyse des informations à partir des identifiants, etc.).

Mise à jour 2: Il semble que la data-fonction d'attribut HTML 5 ait beaucoup de support ici (et j'ai tendance à être d'accord, cela ressemble à une option solide). Jusqu'à présent, je n'ai pas vu grand-chose de réfutations pour cette suggestion. Y a-t-il des problèmes / écueils à craindre en utilisant cette approche? Ou s'agit-il simplement d'une invalidation «inoffensive» des spécifications actuelles du W3C?


Honnêtement, ma position initiale est que ce n'est pas une si mauvaise chose, ce qui peut être assez controversé avec les puristes. Je sens que j'ai vraiment besoin de m'asseoir et d'évaluer toutes les options disponibles pour soutenir correctement cela, cependant, d'où la nécessité d'écrire le long essai.
Paolo Bergantino

Pour ce faire, vous n'aurez peut-être besoin que de quelques contre-exemples: ce que vous essayez d'implémenter, comment il est pratique de le faire avec des attributs personnalisés et pourquoi cette solution est meilleure et pas pire que d'autres solutions sans attributs personnalisés.
ChrisW

@ChrisW Je demande surtout par intérêt, pas par application spécifique.
TM.

Eh bien, il existe de nombreuses options pour obtenir les données côté client: champs de saisie masqués, listes de définitions masquées, classes, plugins de métadonnées, avoir un énorme dictionnaire Javascript (objet) avec tous les mappages de données séparément, attributs personnalisés, attributs de données ( HTML5), etc. Je veux explorer tout cela, considérer leurs mérites, leurs pièges et enfin parvenir à une conclusion. Ce message m'a finalement permis de commencer à écrire ceci. :) Devrait être fait avant 2010.
Paolo Bergantino

2
@Paolo, vous ne pouvez pas simplement dire que vous avez écrit un essai répondant à cette question sans nous donner le lien. Pas cool.
Connell

Réponses:


253

HTML 5 autorise explicitement les attributs personnalisés qui commencent par data. Ainsi, par exemple, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p>est valide. Puisqu'il est officiellement pris en charge par une norme, je pense que c'est la meilleure option pour les attributs personnalisés. Et cela ne vous oblige pas à surcharger d'autres attributs avec des hacks, donc votre HTML peut rester sémantique.

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


C'est une bonne approche .. Mais je doute que cela fonctionne si vous devez prendre en charge IE 6 et d'autres anciens navigateurs.
cllpse le

8
Je suis presque sûr que cela fonctionne avec les anciens navigateurs; les attributs sont ajoutés au DOM, où vous pouvez y accéder.
Ms2ger

12
Il fonctionne parfaitement avec tous les navigateurs utilisant la méthode getAttribute () sur un HTMLElement. De plus, à mesure que la prise en charge des
jeux de

1
@Chuck, apparemment, vous pouvez ajouter des attributs au DOCTYPE: rodsdot.com/html/… - pas que je pense que c'est une bonne idée, mais cela semble standardisé.
Michael Stum

2
@Wahnfrieden: w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8 qui est la méthode approuvée et conforme aux normes. Ce qui est bien décrit et démontré ici: rodsdot.com/html/… Comme précédemment publié par d'autres.
rdivilbiss

95

Voici une technique que j'ai utilisée récemment:

<div id="someelement">

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

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

L'objet commentaire est lié à l'élément parent (c'est-à-dire #someelement).

Voici l'analyseur: http://pastie.org/511358

Pour obtenir les données d'un élément particulier, appelez simplement parseDataavec une référence à cet élément passé comme seul argument:

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

var data = parseData( myElem );

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

Cela peut être plus succinct que cela:

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

Y accéder:

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

Le seul inconvénient de cette utilisation est qu'elle ne peut pas être utilisée avec des éléments à fermeture automatique (par exemple <img/>), car les commentaires doivent être à l' intérieur de l'élément pour être considérés comme les données de cet élément.


MODIFIER :

Avantages notables de cette technique:

  • Facile à mettre en œuvre
  • N'invalide pas HTML / XHTML
  • Facile à utiliser / comprendre (notation JSON de base)
  • Discret et sémantiquement plus propre que la plupart des alternatives

Voici le code de l'analyseur (copié à partir du lien hypertexte http://pastie.org/511358 ci-dessus, au cas où il deviendrait indisponible sur 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
Par curiosité, quelle méthode utilisez-vous pour les balises à fermeture automatique? J'ai généralement besoin d'utiliser quelque chose comme ça sur les éléments <input> (pour faciliter les règles de validation côté client). Quelle alternative prenez-vous dans cette situation?
TM.

2
J'utiliserais probablement une technique similaire, au lieu de lier les données de commentaire au "parentNode", cela pourrait être lié au "previousSibling" du commentaire ... Ensuite, vous pourriez avoir le commentaire immédiatement après le <input /> et ce serait work: <input /> <! - {data: 123} ->
James

7
quelqu'un devrait en faire un plugin jquery
SeanDowney

10
Les commentaires doivent pouvoir être modifiés / supprimés sans rien casser. Exactement. C'est donc une mauvaise idée de mettre quelque chose d'important dans le balisage ou le code dans les commentaires. Les futurs développeurs pourraient facilement penser qu'il s'agit de commentaires et les supprimer. Nous avons déjà une vraie solution à cette question: des attributs personnalisés préfixés de "data-". Cette approche ne doit jamais être utilisée.
MGOwen

6
Permettez-moi de renforcer la déclaration de @MGOwen: n'utilisez pas de commentaires pour ajouter des fonctionnalités. Surtout dans le HTML. N'utilisez-vous pas des minificateurs? Vous ne pourrez pas supprimer les commentaires sans casser votre code. Cela signifie également que vous ne pouvez plus ajouter de vrais commentaires.
Olivictor

15

Vous pouvez créer n'importe quel attribut si vous spécifiez un schéma pour votre page.

Par exemple:

Ajoute ça

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

Facebook (même les tags)

<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

La manière la plus simple d'éviter l'utilisation d'attributs personnalisés consiste à utiliser des attributs existants.

utiliser des noms de classe significatifs et pertinents.
Par exemple, faites quelque chose comme: type='book'et type='cd', pour représenter des livres et des CD. Les classes sont bien meilleures pour représenter ce que quelque chose EST .

par exemple class='book'

J'ai utilisé des attributs personnalisés dans le passé, mais honnêtement, il n'y en a vraiment pas besoin si vous utilisez les attributs existants de manière sémantiquement significative.

Pour donner un exemple plus concret, supposons que vous ayez un site donnant des liens vers différents types de magasins. Vous pouvez utiliser les éléments suivants:

<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>

le style css pourrait utiliser des classes comme:

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

Dans l'exemple ci-dessus, nous voyons que les deux sont des liens vers des magasins (par opposition aux autres liens non liés sur le site) et l'un est un magasin de CD et l'autre est une librairie.


4
Bon point, mais pour être honnête, "type" n'est valide que sur certaines balises, et quand il s'agit d'un attribut valide, il a également une liste de valeurs valides, donc vous n'êtes toujours pas vraiment conforme au w3c.
TM.

1
mon point était que vous ne devriez PAS utiliser la balise type pour cela. d'où le Si vous étiez ... alors vous devriez ... Je vais éditer pour que ce soit plus clair
Jonathan Fingland

J'ai tendance à rendre mes attributs "classe" avec des saveurs en ayant certains d'entre eux avec un certain type de "qualificatif-". pour les divs liés à la mise en page uniquement, je voudrais que sa classe soit "layout-xxx", ou pour les divs internes qui entourent une partie importante, comme un livre ou un magasin, j'aurais un content-book ou content-store . puis dans mon JavaScript, j'ai une fonction qui ajoute ces éléments à la balise en fonction de ce que je recherche. cela aide à garder les choses propres et organisées pour moi, mais nécessite un certain niveau de discipline et de pré-organisation.
Ape-inago

2
@Jonathan, la fonction de double classe fonctionne très bien, sauf dans les cas où les «valeurs» ne sont pas connues. Par exemple, s'il s'agit d'une sorte d'ID entier, nous ne pouvons pas très bien sélectionner pour chaque cas possible. Il nous reste ensuite à analyser manuellement l'attribut de classe, ce qui est certainement réalisable, mais pas aussi clair dans le code, et dans certains cas, pourrait être très lent (s'il y a beaucoup d'éléments candidats à analyser).
TM.

2
malheureusement, l'écriture de sélecteurs css pour deux classes en même temps (.ab remarque le blanc manquant) ne fonctionne pas dans IE. cela fonctionne cependant dans Firefox et dans d'autres navigateurs. toujours, utiliser des classes est un excellent moyen d'intégrer une signification sémantique supplémentaire à votre balisage
knittl

6

Intégrez les données dans le dom et utilisez les métadonnées pour jQuery .

Tous les bons plug-ins prennent en charge le plug-in de métadonnées (autorisant les options par balise).

Il permet également des structures données / données infiniment complexes, ainsi que des paires clé-valeur.

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

OU

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

OU

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

Ensuite, obtenez les données comme suit:

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

22
La corruption de l'attribut de classe lorsqu'il existe un moyen approuvé par le W3C de spécifier des attributs personnalisés est probablement la raison pour laquelle vous avez été rejeté.
rdivilbiss

2
corrompant l'attribut de classe est seulement l' une des façons d'utiliser le plug - in; ce n'est pas le seul moyen.
antony.trupe

1
Une autre raison pour laquelle vous avez été rejeté est de proposer un plugin où aucun plugin n'est nécessaire.
meandre

4

Je ne vois aucun problème à utiliser les fonctionnalités XHTML existantes sans casser quoi que ce soit ou étendre votre espace de noms. Jetons un coup d'œil à un petit exemple:

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

Comment ajouter des informations supplémentaires à some_content sans attributs supplémentaires? Qu'en est-il de l'ajout d'une autre balise comme la suivante?

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

Il conserve la relation via un identifiant / extension bien défini "_extended" de votre choix et par sa position dans la hiérarchie. J'utilise souvent cette approche avec jQuery et sans réellement utiliser des techniques similaires à Ajax.


2
Le problème avec l'ajout de balises imbriquées comme celle-ci est qu'il a tendance à créer un code côté serveur TRÈS lourd et laid (JSP / ASP / DTL, etc.)
TM.

3

Non. Essayez plutôt quelque chose comme ceci:

<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
Vous préférez donc écrire beaucoup de balises de script supplémentaires sur tout votre document pour les pages dynamiques? J'utiliserais des affectations javascript manuelles lorsque les informations sont ajoutées du côté client, mais ce problème concerne principalement le rendu sur le serveur. De plus, jQuery.data () est bien meilleur que votre méthode.
TM.

La réponse ci-dessus est un exemple élaboré et indépendant du cadre pour démontrer la fonctionnalité. Vous pouvez facilement développer l'essentiel pour rendre le code assez concis. Par exemple, <div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <script type = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', bar : «etc.», baz: 3.14159}); </script> Si vous utilisez jQuery (pas que vous l'ayez mentionné dans votre question d'origine), utilisez certainement la méthode des données - c'est à cela que ça sert. Sinon, le passage de données entre les couches architecturales est une utilisation parfaitement valide des balises de script en ligne.
Anon

C'est certainement une option évidente et valable. À mon avis, cela encombre le code beaucoup plus que de nombreuses autres alternatives qui n'utilisent pas d'attributs personnalisés. Et juste pour être clair, je n'essaie pas d'être combatif ou grossier, j'essaie simplement de cajoler certains de vos raisonnements pour expliquer pourquoi vous préférez cette méthode. Vous avez proposé une alternative, mais ce n'est pas vraiment de cela qu'il s'agit.
TM.

1
Je ne pense pas qu'il y ait un problème avec cette approche qui brise les navigateurs. Microsoft utilise ce mécanisme exact comme son mécanisme préféré dans les pages ASP.NET. (en appelant RegisterExpandoAttribute côté serveur). La question semble centrée sur le client et non sur le serveur, mais côté serveur, toutes ces approches pourraient être (devraient être?) Abstraites.
Adrian

3
Les avantages de cette approche: - Elle produit un balisage valide (même sous les anciens navigateurs / spécifications). - Il rend clair l'intention des données (destinées à être utilisées par JS). - Il est cohérent avec l'élément sans faire un usage intelligent d'autres fonctionnalités (telles que les commentaires). - Il ne nécessite pas d'analyse spéciale. Du point de vue du serveur, vous pouvez le considérer comme un RPC.
steamer25

2

Je n'utilise pas d'attributs personnalisés, car je génère du XHTML, parce que je veux que les données soient lisibles par la machine par un logiciel tiers (bien que je puisse étendre le schéma XHTML si je le voulais).

Comme alternative aux attributs personnalisés, la plupart du temps, je trouve les attributs id et class (par exemple, comme mentionné dans d'autres réponses) suffisants.

Considérez également ceci:

  • Si les données supplémentaires doivent être lisibles par l'homme et lisibles par la machine, elles doivent être codées à l'aide de balises HTML et de texte (visibles) au lieu d'être des attributs personnalisés.

  • S'il n'a pas besoin d'être lisible par l'homme, alors peut-être qu'il peut être codé à l'aide de balises HTML et de texte invisibles .

Certaines personnes font une exception: elles autorisent les attributs personnalisés, ajoutés au DOM par Javascript côté client au moment de l'exécution. Ils estiment que c'est OK: parce que les attributs personnalisés ne sont ajoutés au DOM qu'au moment de l'exécution, le HTML ne contient aucun attribut personnalisé.


1

Nous avons créé un éditeur Web qui comprend un sous-ensemble de HTML - un sous-ensemble très strict (qui est compris presque universellement par les clients de messagerie). Nous devons exprimer des choses comme <td width="@INSWIDTH_42@">dans la base de données, mais nous ne pouvons pas avoir cela dans le DOM, sinon le navigateur où l'éditeur s'exécute, panique (ou est plus susceptible de paniquer que de paniquer sur des attributs personnalisés) . Nous voulions le glisser-déposer, donc le mettre purement dans le DOM était sorti, tout comme jquery .data()(les données supplémentaires n'ont pas été copiées correctement). Nous avions probablement également besoin des données supplémentaires pour nous accompagner .html(). En fin de compte, nous avons décidé de l'utiliser <td width="1234" rs-width="@INSWIDTH_42@">pendant le processus d'édition, puis lorsque nous POSTONS tout, nous supprimons widthet faisons une recherche et destruction regex s/rs-width=/width=/g.

Au début, le gars qui écrivait le plus était la validation-nazie sur ce problème et a tout essayé pour éviter notre attribut personnalisé, mais à la fin, il a acquiescé quand rien d'autre ne semblait fonctionner pour TOUTES nos exigences. Cela a aidé quand il a réalisé que l'attribut personnalisé n'apparaîtrait jamais dans un e-mail. Nous avons envisagé de coder nos données supplémentaires class, mais nous avons décidé que ce serait le plus grand des deux maux.

Personnellement, je préfère avoir des choses propres et passer des validateurs, etc., mais en tant qu'employé de l'entreprise, je dois me rappeler que ma responsabilité principale est de faire avancer la cause de l'entreprise (gagner le plus d'argent possible le plus rapidement possible), pas celle de mon désir égoïste de pureté technique. Les outils devraient fonctionner pour nous; pas nous pour eux.


1

Je sais que les gens sont contre, mais j'ai trouvé une solution super courte pour cela. Si vous souhaitez utiliser un attribut personnalisé comme "le mien", par exemple:

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

Ensuite, vous pouvez exécuter ce code pour récupérer un objet comme le fait 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: créez un contrôle ASP.NET TextBox qui formate automatiquement son texte sous forme de nombre, selon les propriétés "DecimalSeparator" et "ThousandsSeparator", en utilisant JavaScript.


Une façon de transférer ces propriétés du contrôle vers JavaScript consiste à demander au contrôle de restituer les propriétés personnalisées:

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

Les propriétés personnalisées sont facilement accessibles par JavaScript. Et bien qu'une page utilisant des éléments avec des propriétés personnalisées ne soit pas validée , le rendu de cette page ne sera pas affecté.


J'utilise cette approche uniquement lorsque je veux associer des types simples comme des chaînes et des entiers à des éléments HTML à utiliser avec JavaScript. Si je veux faciliter l'identification des éléments HTML, je vais utiliser les propriétés class et id .


0

Pour les applications Web complexes, je laisse tomber des attributs personnalisés partout.

Pour des pages plus accessibles au public, j'utilise l'attribut "rel" et y jette toutes mes données en JSON, puis je les décode avec MooTools ou jQuery:

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

J'essaie de m'en tenir à l'attribut de données HTML 5 récemment juste pour "préparer", mais cela n'est pas encore venu naturellement.


-1

J'utilise des champs personnalisés tout le temps par exemple <ai = "" .... Puis référence à i avec jquery. HTML non valide, oui. Cela fonctionne bien, oui.


Quelque chose semble manquer ici. Votre tag était-il complet, ici?
Stuart Siegler

Comment peut-on comprendre cela? Veuillez compléter votre réponse.
Rahul Raj

-2

Les attributs personnalisés, à mon humble avis, ne doivent pas être utilisés car ils ne valident pas. Alternativement à cela, vous pouvez définir de nombreuses classes pour un seul élément comme:

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

10
personnellement, je pense que c'est un terrible exemple. vos noms de classe définissent à quoi cela ressemble, pas son but. Pensez à quand vous voulez changer toutes les divs similaires ... vous devez aller les changer toutes en span-11 ou similaire. les classes devraient définir ce que c'est. les feuilles de style devraient définir à quoi ces choses ressemblent
Jonathan Fingland

Comment utiliseriez-vous cette méthode pour spécifier plus qu'un simple indicateur? J'ai tendance à être d'accord avec votre position et je n'utilise pas d'attributs personnalisés (bien que j'y réfléchisse). L'avantage d'avoir une paire clé / valeur semble un peu plus pratique que d'ajouter simplement une autre classe.
TM.

@Jonathan Fingland: Si Compass est utilisé, vous n'avez pas besoin de définir les noms de classe ici. Vous pouvez simplement les spécifier dans le fichier .sass et votre balisage sera propre.
Alan Haggai Alavi

@Jonathan Fingland, l' classattribut n'est certainement pas réservé aux "looks" uniquement. Une autre utilisation est le "traitement à usage général par les agents utilisateurs". De cela parle la spécification: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup

@npup: choix intéressant de citations. Comme je l'ai dit il y a plus d'un an, les feuilles de style définissent à quoi ces choses devraient ressembler (tout comme l'attribut style, j'ajouterai), et l'attribut class est utilisé pour définir le but de l'élément. Autrement dit, il est spécifiquement utilisé pour définir ce qu'il EST, et non comment il A l'air. Je pense que vous avez peut-être simplement mal lu ce que j'ai dit, car nous sommes d'accord pour autant que je sache.
Jonathan Fingland
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.