Deux éléments HTML avec le même attribut id: Quelle est leur gravité?

122

Il suffit de parcourir le code source de Google Maps. Dans leur en-tête, ils ont 2 divs avec id = "search", l'un contient l'autre, ainsi que l'attribut jstrack = "1". Il y a un formulaire qui les sépare comme ceci:

<div id="search" jstrack="1">
    <form action="/maps" id="...rest isn't important">
        ...
        <div id="search">...

Depuis que c'est Google, je suppose que ce n'est pas une erreur.

Alors, à quel point peut-il vraiment être contraire à cette règle? Tant que vous faites attention dans votre sélection de css et de dom, pourquoi ne pas réutiliser les identifiants comme les classes? Est-ce que quelqu'un le fait exprès, et si oui, pourquoi?

Danludwig
la source
102
"Puisque c'est google, je suppose que ce n'est pas une erreur." -> Google ne sont pas infaillibles. Ils font des erreurs comme le reste d'entre nous.
Joeri Sebrechts
43
En fait, les gars de Google ont cherché RECHERCHE dans leur esprit, ils ne peuvent donc penser à aucun autre identifiant: P
Pankaj Upadhyay
10
J'ai le sentiment que cette page est rendue à partir de différents fragments HTML, de sorte qu'un développeur dans un fragment a utilisé cet identifiant, et la même chose s'est produite avec un autre développeur dans l'autre fragment.
Luciano
10
Toute la question de "comment est-il vraiment mauvais" me rappelle juste ceci: xkcd.com/292
Daniel Roseman
3
@DanielRoseman xkcd le fait aussi: what-if.xkcd.com/23/#question
SQB

Réponses:

140

Spécification dit unique

La spécification HTML 4.01 indique que l'ID doit être unique pour l'ensemble du document.

La spécification HTML 5 dit la même chose mais en d’autres termes. Il dit que l'ID doit être unique dans sa sous - arborescence de base , qui est fondamentalement le document si on en lit la définition .

Éviter la duplication

Mais comme les rendus HTML sont très indulgents en matière de rendu HTML, ils permettent les identifiants en double. Cela devrait être évité autant que possible et strictement évité lors de l'accès programmé à des éléments par des identifiants en JavaScript. Je ne suis pas sûr de la getElementByIdfonction à renvoyer lorsque plusieurs éléments correspondants sont trouvés. Devrait-il:

  • renvoyer une erreur?
  • retourner le premier élément correspondant?
  • retourner le dernier élément correspondant?
  • renvoyer un ensemble d'éléments correspondants?
  • ne retourne rien?

Mais même si les navigateurs fonctionnent de manière fiable de nos jours, personne ne peut garantir ce comportement à l'avenir, car cela va à l'encontre des spécifications. C'est pourquoi je vous recommande de ne jamais dupliquer les identifiants dans le même document.

Robert Koritnik
la source
1
@missingno: j'ai ajouté un lien vers la spécification HTML 5 qui parle de la même chose mais dans des termes différents.
Robert Koritnik
6
Selon la spécification DOM , "Si plusieurs éléments ont un attribut ID avec cette valeur, ce qui est renvoyé est indéfini" (ce qui signifie qu'il n'y a pas de résultat "correct" défini, plutôt que la valeur réelle undefined). C'est rarement une bonne idée de s'appuyer sur un comportement indéfini.
Lonesomeday
1
Il convient de noter avec HTML5, l' data-attribut est pratique pour quand on peut être tenté d'attribuer le même ID à plusieurs choses. Cela vous permet d'avoir plusieurs identifiants différents avec un data-somethingattribut commun en commun. Néanmoins, tous les navigateurs que je connais ignorent les attributs inconnus, ils sont donc probablement protégés dans presque tous les navigateurs modernes sans support HTML complet.
Tim Post
2
@ JoachimSauer: lorsque vous utilisez des attributs de données, vous pouvez avoir des paires clé-valeur, ce qui n'est pas le cas lorsque vous utilisez des classes CSS. Dans ce cas, ils ressemblent tous à des propriétés booléennes. Un élément a une classe CSS ou non. Si vous voulez des valeurs avec des classes CSS, vous devez les combiner d'une manière ou d'une autre dans le nom de la classe CSS et les analyser ensuite. J'espère que vous pouvez maintenant voir les avantages de l'utilisation d' dataattributs. Et ils sont également pris en charge directement par jQuery dès que vous faites simplement référence à data-something="123"attribut with $(elem).data("something").
Robert Koritnik
1
@RobertKoritnik: Bien sûr! Je n'ai pas pensé à ce cas d'utilisation. Je n'ai pensé qu'au cas de id="search".
Joachim Sauer
30

Vous avez demandé "comment mauvais". Donc, pour étoffer dehors @ RobertKoritnik (tout à fait exact) répondre un peu ...

Ce code est incorrect. Incorrect ne vient pas en nuances de gris. Ce code enfreint la norme et est donc incorrect. Cela échouerait dans la vérification de validation, et cela devrait être le cas

Cela dit, aucun navigateur actuellement sur le marché ne s'en plaindrait ou n'aurait de problème avec cela. Les navigateurs auraient le droit de se plaindre à ce sujet, mais aucune de leurs versions actuelles ne le fait actuellement. Ce qui ne veut pas dire que les versions futures pourraient ne pas traiter ce code de manière inappropriée.

Votre comportement en essayant d'utiliser cet ID en tant que sélecteur, en css ou en javascript, est indiscutable et varie probablement d'un navigateur à l'autre. Je suppose qu'une étude pourrait être faite pour voir comment chaque navigateur réagit à cela. Je pense que dans le meilleur des cas, il le traiterait comme "class =" et en sélectionnerait la liste. Cela risquerait de confondre les bibliothèques JavaScript. Si j’étais l'auteur de jQuery, j'aurais peut-être optimisé le code de mon sélecteur afin que, si vous me présentez avec un sélecteur commençant par "#", j'attends un seul objet, et obtenir un cette liste pourrait me casser complètement.)

Il peut également sélectionner le premier, ou éventuellement le dernier, ou n'en sélectionner aucun, ou bloquer complètement le navigateur. Pas moyen de le savoir sans l'essayer.

"Quelle est la gravité" dépend alors entièrement de la rigueur avec laquelle un navigateur particulier applique la spécification HTML et de ce qu'il fait lorsqu'il est confronté à une violation de cette spécification.

EDIT: Je viens de tomber sur cela aujourd'hui. J'insère divers composants à partir de formulaires de recherche sur différents types d'entités afin de produire un très grand utilitaire de reporting tout-en-un pour ce site. Je charge les formulaires de recherche des pages distantes dans des div cachés et les insère dans mon générateur de rapport lorsque le type d’entité approprié est sélectionné comme source pour le rapport. Il existe donc une version cachée du formulaire et une version affichée dans le générateur de rapports. Le code JavaScript fourni avec, dans tous les cas, fait référence aux éléments par ID, dont il y a maintenant DEUX sur la page - celui qui est caché et celui qui est affiché.

Ce que jQuery semble faire, c'est de me choisir le PREMIER, qui est dans tous les cas exactement celui que je ne veux pas.

Je travaille autour de cela en écrivant des sélecteurs pour spécifier la région de la page dans laquelle je veux obtenir mon champ (par exemple: $ ('# containerDiv #specificElement')). Mais il y a une réponse à votre question: jQuery sur Chrome se comporte vraiment de manière particulière lorsqu'il est confronté à cette violation des spécifications.

Dan Ray
la source
... une question connexe: stackoverflow.com/q/29295824/287948 à propos de l'obligation des ID dans un profil rapide CSS.
Peter Krauss
3
"Incorrect ne vient pas en nuances de gris." Je le vois souvent et c'est une de ces choses qui est techniquement correcte mais qui n'est pas "vraie" dans la vie ou dans la programmation. Vous couvrez indirectement cela assez complètement dans votre réponse et je pourrais expliquer mais cette scène de The Big Bang Theory fait un si bon travail que je la laisserai parler pour moi et, espérons-le, faire rire quelqu'un ... Stuart vs Sheldon youtube.com/ watch? v = F_1zoX5Ax9U
Night Owl
C'est une réponse vieille de 8 ans, mais je pense que la façon dont vous hyperbolez sur la question de OP est très déséquilibrée, mais ne vous plaignez pas beaucoup du comportement permissif et dangereux des navigateurs face aux identifiants répétés, ce qui est bien pire que ce que OP tente de faire.
erandros
20

Est-il si mal que ca?

  1. Ça me fait pleurer
  2. C'est invalide
  3. De nombreuses bibliothèques javascript ne fonctionneront pas comme prévu
  4. Cela rend votre code déroutant

L’expérience montre que getElementById dans les principaux navigateurs renvoie le premier élément correspondant du document. Mais cela ne sera peut-être pas toujours le cas à l'avenir.

Lorsque jQuery reçoit un identifiant, par exemple #foo, il utilise getElementById et imite ce comportement. Si vous devez contourner ce problème (c'est triste), vous pouvez utiliser $ (" * #foo") pour convaincre jQuery d'utiliser getElementsByTagName et renvoyer une liste de tous les éléments correspondants.

Je dois souvent écrire du code pour d'autres sites et je dois contourner ce problème. Dans un monde juste, je n'aurais pas besoin de repenser les fonctions pour commencer par vérifier si un identifiant est unique. Les identifiants doivent toujours être uniques. Le monde est cruel et c'est pourquoi je pleure.

ColBeseder
la source
5
Cette réponse m'a fait pleurer ... de rire!
A1rPun
8

Vous pouvez faire beaucoup de choses - mais cela ne veut pas dire que vous devriez le faire.

En tant que programmeur (en général), nous construisons notre vie en étant précis et en suivant les règles - voici une règle simple à suivre, assez fondamentale pour ce que nous faisons - nous aimons (dépendons) des identifiants uniques dans une portée donnée ...

Casser la règle est une chose que nous pouvons faire parce que les navigateurs sont beaucoup trop accommodants - mais, en réalité, nous en serions tous mieux si les navigateurs demandaient strictement à un code HTML bien formé et valide. été remboursé!

Alors, est-ce vraiment si mauvais? En tant que programmeur, comment pouvez-vous même demander? C'est un crime contre la civilisation (-:


Addenda:

Vous écrivez que les navigateurs sont trop accommodants comme si c'était une mauvaise chose

Parce que c’est - nous ne parlons pas de règles compliquées, nous parlons essentiellement de rendre les choses bien formées et d’appliquer par ailleurs des règles qui peuvent être testées mécaniquement et qui, à leur tour, facilitent le traitement mécanique du résultat. Si les navigateurs avaient été stricts, les outils se seraient très rapidement adaptés pour le supporter - ce n’était pas le cas, certains dans la mesure où ils exploitent cet échec à la place. Pensez simplement à cela - le courrier électronique aurait été un moyen beaucoup plus agréable si MS et Netscape ne l'avaient pas foiré en autorisant le langage HTML illimité alors qu'un "langage de balisage de courrier électronique" bien moins complexe, avec prise en charge explicite du texte cité, nous aurait fourni un outil bien meilleur ... mais ce navire a navigué et de même nous pouvons 'aurait dû ) mais nous ne pouvons pas

Murph
la source
Vous écrivez que les navigateurs sont trop accommodants comme si c'était une mauvaise chose, mais vous n'y croyez sûrement pas?
KaptajnKold
4
Je ne peux pas parler pour Murph, mais je pense que c'est une très mauvaise chose. Là encore, sans ce niveau de pardon, le Web n'aurait peut-être pas eu l'impulsion de se développer comme nous le savons.
Andrea
1
@Andrea: Internet ne se serait pas développé tel que nous le connaissons. Cela aurait poussé plus lentement. Mais il aurait également eu une base plus solide de ce qui est et n’est pas du code correct. Rapide mais désordonné peut fonctionner, mais je préfère de loin le plus lent mais correct. D'autant plus que ce n'est pas comme si nous ne parlions que de quelques années de croissance ou plus.
Nicol Bolas
3
@Andrea Je parierais que cela aurait grandi presque aussi vite - les outils auraient simplement évolué pour traiter le problème. Alors que dans de nombreux cas, les outils étaient à l'origine du faible taux de marge. Le fait est que les gens ont tendance à faire le moins nécessaire - le pas pour "bien formé" est relativement petit et assez facile à tester et à appliquer, et les gens l'auraient accommodé sans stress important
Murph
1
Ce n'est pas horrible que les navigateurs sont accommodants. Il est horrible qu'ils soient tous accommodants de différentes manières .
Dan Ray
7

Dans Scripting: getElementByIDne renverra que le premier match. En CSS: #idaffectera TOUS les éléments portant cet ID. Le rendu du navigateur n'aura aucun effet.

C'est le comportement de la norme W3C. Ce n’est pas possible, c’est celui qui est défini.

https://dom.spec.whatwg.org/#interface-nonelementparentnode

Bart Calixto
la source
7
C'est un comportement possible. getElementByIdpourrait parfaitement renvoyer n'importe quel élément, ou même un objet nul. L'effet CSS peut concerner n'importe quel élément, aucun ou tous les éléments. Ou le navigateur pourrait planter. En dehors de la norme, le comportement n'est pas défini
rds
2
Ce n'est pas hors de la norme parce que la norme spécifie quoi faire dans ces situations. Donc non, getElementById ne peut renvoyer aucun élément, le standard dit explicitement que je renverrai le premier match. Je conviens que le comportement hors norme n'est pas défini, mais ce que vous ne comprenez pas, c'est que tous ces cas font partie de la norme.
Bart Calixto
1
Cette réponse serait un peu meilleure si elle incluait réellement, à titre de référence, une citation de la partie pertinente de la norme (ou au moins un numéro de section).
yoniLavi
2
@yoniLavi mis à jour.
Bart Calixto
2
Merci @Bart. Vous avez absolument raison :) La norme indique "Renvoie le premier élément des descendants du nœud dont l'ID est elementId".
YoniLavi