Dos elementos HTML con el mismo atributo de identificación: ¿Qué tan malo es realmente?

122

Simplemente navega por el código fuente de google maps. En su encabezado, tienen 2 divs con id = "search" uno contiene el otro, y también tiene el atributo jstrack = "1". Hay una forma que los separa así:

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

Como se trata de Google, supongo que no es un error.

Entonces, ¿qué tan malo puede ser realmente violar esta regla? Siempre y cuando tenga cuidado en su selección de CSS y DOM, ¿por qué no reutilizar las clases como id? ¿Alguien hace esto a propósito, y si es así, por qué?

danludwig
fuente
102
"Como se trata de Google, supongo que no es un error". -> Google no es infalible. Cometen errores como el resto de nosotros.
Joeri Sebrechts
43
en realidad, los chicos de google tienen SEARCH atornillado en sus mentes para que no puedan pensar en ninguna otra identificación: P
Pankaj Upadhyay
10
Tengo la sensación de que esa página se representa desde diferentes fragmentos html, por lo que un desarrollador en un fragmento usó esa identificación, y lo mismo sucedió con otro desarrollador en el otro fragmento.
Luciano
10
Toda la pregunta de "qué tan malo es realmente" solo me recuerda esto: xkcd.com/292
Daniel Roseman
3
@DanielRoseman xkcd también lo hace: what-if.xkcd.com/23/#question
SQB

Respuestas:

140

La especificación dice ÚNICO

La especificación HTML 4.01 dice que la ID debe ser única en todo el documento.

La especificación HTML 5 dice lo mismo pero en otras palabras. Dice que la ID debe ser única en su subárbol de inicio , que es básicamente el documento si leemos la definición del mismo .

Evitar duplicaciones

Pero dado que los renderizadores HTML son muy indulgentes cuando se trata de renderizar HTML, permiten identificaciones duplicadas. Esto debe evitarse si es posible y estrictamente evitado cuando se accede a elementos mediante programación mediante ID en JavaScript. No estoy seguro de qué getElementByIdfunción debería volver cuando se encuentran varios elementos coincidentes. Deberia:

  • devolver un error?
  • devolver el primer elemento coincidente?
  • devolver el último elemento coincidente?
  • devolver un conjunto de elementos coincidentes?
  • no devuelve nada?

Pero incluso si los navegadores funcionan de manera confiable en estos días, nadie puede garantizar este comportamiento en el futuro ya que esto va en contra de las especificaciones. Es por eso que le recomiendo que nunca duplique ID dentro del mismo documento.

Robert Koritnik
fuente
1
@missingno: agregué un enlace a la especificación HTML 5 que habla de lo mismo pero con una redacción diferente.
Robert Koritnik
66
Según la especificación DOM , "Si más de un elemento tiene un atributo ID con ese valor, lo que se devuelve no está definido" (lo que significa que no hay un resultado "correcto" definido, en lugar del valor real undefined). Rara vez es una buena idea confiar en un comportamiento indefinido.
lonesomeday
1
Vale la pena señalar con HTML5, el data-atributo es útil para cuando uno se siente tentado a asignar varias cosas a la misma ID. Esto le permite tener muchas ID diferentes con un data-somethingatributo común en común. Aún así, todos los navegadores que conozco ignoran los atributos desconocidos, por lo que probablemente estén seguros en casi todos los navegadores modernos que carecen de soporte HTML completo.
Tim Post
2
@JoachimSauer: cuando usa atributos de datos, puede tener pares clave-valor, lo que no es cierto cuando usa clases CSS. En ese caso, todos son como propiedades booleanas. Un elemento tiene una clase CSS o no. Si desea valores con clases CSS, de alguna manera tendría que combinarlos en el nombre de la clase CSS y analizarlos luego. Espero que ahora pueda ver los beneficios del uso de dataatributos. Y también son compatibles directamente con jQuery cuando simplemente hace referencia al data-something="123"atributo con $(elem).data("something").
Robert Koritnik
1
@RobertKoritnik: ¡Por supuesto! No pensé en ese caso de uso. Solo pensé en el caso de id="search".
Joachim Sauer
30

Usted preguntó "qué tan malo". Así que para dar un poco de respuesta a Robertbertoritnik (completamente precisa) ...

Ese código es incorrecto. Incorrecto no viene en tonos de gris. Este código viola el estándar y, por lo tanto, es incorrecto. Fallaría la verificación de validación, y debería.

Dicho esto, ningún navegador actualmente en el mercado se quejaría o tendría algún problema. Los navegadores tendrían derecho a quejarse al respecto, pero ninguna de las versiones actuales de ninguno de ellos lo hace actualmente. Lo que no significa que las versiones futuras no traten mal este código.

Su comportamiento al tratar de usar esa ID como selector, ya sea en CSS o JavaScript, es incuestionable y probablemente varía de un navegador a otro. Supongo que se podría hacer un estudio para ver cómo reacciona cada navegador a eso. Creo que en el mejor de los casos, lo trataría como "clase =" y seleccionaría la lista de ellos. (Sin embargo, eso podría confundir a las bibliotecas de JavaScript; si yo fuera el autor de jQuery, podría haber optimizado mi código de selector para que si vienes a mí con un selector que comienza con "#", espero un solo objeto y obtengo un la lista podría molestarme por completo).

También puede seleccionar el primero, o posiblemente el último, o no seleccionar ninguno de ellos, o bloquear el navegador por completo. No hay forma de saberlo sin probarlo.

"Qué tan malo" depende entonces de cuán estrictamente un navegador en particular implemente la especificación HTML y lo que haga cuando se enfrente a una violación de esa especificación.

EDITAR: Acabo de encontrar esto hoy. Extraigo varios componentes de los formularios de búsqueda en varios tipos de entidades para producir una gran utilidad de informes todo en uno para este sitio, estoy cargando los formularios de búsqueda de las páginas remotas en divs ocultos y los inserto en mi generador de informes cuando se selecciona el tipo de entidad apropiado como la fuente del informe. Entonces, hay una versión oculta del formulario y una versión que se muestra en el generador de informes. El JavaScript que viene con, en todos los casos, se refiere a elementos por ID, de los cuales ahora hay DOS en la página: el oculto y el que se muestra.

Lo que parece estar haciendo jQuery es seleccionarme el PRIMERO, que en todos los casos es exactamente el que NO quiero.

Estoy trabajando en esto escribiendo selectores para especificar la región de la página en la que quiero obtener mi campo (es decir: $ ('# containerDiv #specificElement')). Pero hay una respuesta a su pregunta: jQuery en Chrome definitivamente se comporta de una manera particular cuando se enfrenta a esta violación de especificaciones.

Dan Ray
fuente
... una pregunta relacionada: stackoverflow.com/q/29295824/287948 sobre la obligación de las ID en un perfil rápido de CSS.
Peter Krauss
3
"Incorrecto no viene en tonos de gris". Lo veo mucho y es una de esas cosas que es técnicamente correcto pero no "verdadero" en la vida o en la programación. Usted indirectamente cubre eso bastante bien en su respuesta y podría exponerlo, pero esta escena de The Big Bang Theory hace un trabajo tan bueno que lo dejaré hablar por mí y espero hacer reír a alguien ... Stuart vs Sheldon youtube.com/ watch? v = F_1zoX5Ax9U
Night Owl
Esta es una respuesta de 8 años, pero creo que es muy desequilibrado cómo exageras en la pregunta de OP, pero no te quejas mucho sobre el comportamiento permisivo y peligroso de los navegadores sobre los ID repetidos, que es mucho peor de lo que OP está tratando de hacer.
erandros
20

¿Qué tan grave es en realidad?

  1. Me hace llorar
  2. Es invalido
  3. Muchas bibliotecas javascript no funcionarán como se esperaba
  4. Hace que su código sea confuso

La experiencia dice que getElementById en los principales navegadores devolverá el primer elemento coincidente en el documento. Pero esto puede no ser siempre el caso en el futuro.

Cuando jQuery recibe una identificación, por ejemplo, #foo, usa getElementById e imita ese comportamiento. Si tiene que solucionar esto (es triste), puede usar $ (" * #foo") que convencerá a jQuery de usar getElementsByTagName y devolverá una lista de todos los elementos coincidentes.

A menudo tengo que escribir código para otros sitios, y tengo que solucionar esto. En un mundo justo, no tendría que rediseñar las funciones para comenzar comprobando si una ID es única. Las identificaciones siempre deben ser únicas. El mundo es cruel y por eso lloro.

ColBeseder
fuente
55
Esta respuesta me hizo llorar ... de risa!
A1rPun
8

Usted puede hacer muchas cosas - pero eso no significa que usted debe.

Como programador (en términos generales) construimos nuestras vidas siendo precisos y siguiendo las reglas: aquí hay una regla que es simple de seguir, que es bastante fundamental para lo que hacemos: nos gustan (dependemos) de identificadores únicos dentro de un alcance dado ...

Romper la regla es algo que podemos hacer porque el navegador es demasiado servicial, pero en realidad todos estaríamos mejor si los navegadores fueran estrictos sobre la necesidad de HTML bien formado y válido, la pequeña cantidad de dolor que habría causado habría pasado mucho tiempo ha sido pagado!

Entonces, ¿es realmente tan malo? Como programador, ¿cómo puedes preguntar? Es un crimen contra la civilización (-:


Apéndice:

Escribes que los navegadores son demasiado serviciales como si fuera algo malo

Lo hago, porque es así: no estamos hablando de reglas complicadas, estamos hablando sustancialmente de hacer que las cosas estén bien formadas y de otra manera aplicar reglas que puedan probarse mecánicamente y que a su vez faciliten que el resultado se procese mecánicamente. Si los navegadores hubieran sido estrictos, entonces las herramientas se habrían adaptado muy rápidamente para soportar eso; no fue así, no lo hicieron, algunos en la medida en que explotan esa falla. Solo piense en esto: el correo electrónico habría sido un medio mucho mejor si MS y Netscape no lo hubieran estropeado al permitir HTML sin restricciones cuando un "lenguaje de marcado de correo electrónico" mucho menos complejo con soporte explícito para el texto citado nos hubiera dado una herramienta mucho mejor. ... pero ese barco navegó y de manera similar podemos 'debería tener ) pero no podemos

Murph
fuente
¿Escribes que los navegadores son demasiado serviciales como si fuera algo malo, pero seguramente no lo crees?
KaptajnKold
44
No puedo hablar por Murph, pero seguro que creo que es algo realmente malo. Por otra parte, sin este nivel de perdón, la web podría no haber tenido el impulso de crecer como la conocemos.
Andrea
1
@Andrea: Internet no habría crecido tal como lo conocemos. Habría crecido más lentamente. Pero también habría tenido una base más sólida de lo que es y no es el código correcto. Puede ser rápido pero descuidado, pero prefiero mucho más lento pero correcto. Especialmente porque no es como si solo estuviéramos hablando de un par de años de crecimiento más o menos.
Nicol Bolas
3
@Andrea Apuesto a que habría crecido casi tan rápido: las herramientas simplemente habrían evolucionado para solucionar el problema. Mientras que en muchos casos las herramientas fueron la causa de un marcado deficiente. El hecho es que las personas tienden a hacer lo menos necesario: el paso para "estar bien formado" es relativamente pequeño y lo suficientemente fácil de evaluar y hacer cumplir, y las personas lo habrían acomodado sin un estrés significativo
Murph
1
No es horrible que los navegadores sean complacientes. Es horrible que todos se acomoden de diferentes maneras .
Dan Ray
7

En Scripting: getElementByIDsolo devolverá la primera coincidencia. En CSS: #idafectará a TODOS los elementos con esa ID. En el navegador, el renderizado no tendrá ningún efecto.

Este es el comportamiento del estándar w3c. No es posible, es el hecho definido.

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

Bart Calixto
fuente
77
Este es un comportamiento posible. getElementByIdpodría devolver perfectamente cualquier elemento, o incluso un objeto nulo. El efecto CSS podría estar en cualquier elemento, o en ninguno o en todos. O el navegador podría fallar. Fuera del estándar, el comportamiento no
rds
2
No está fuera del estándar porque el estándar especifica qué hacer en esas situaciones. Entonces no, getElementById no pudo devolver ningún elemento, el estándar dice explícito que devolveré la primera coincidencia. Estoy de acuerdo en que el comportamiento fuera del estándar no está definido, lo que no comprende es que todos esos casos son parte del estándar.
Bart Calixto
1
Esta respuesta sería algo mejor si realmente incluyera, como referencia, una cita de la parte relevante del estándar (o al menos un número de sección).
yoniLavi
2
@yoniLavi actualizado.
Bart Calixto
2
Gracias @Bart. Tienes toda la razón :) El estándar dice "Devuelve el primer elemento dentro de los descendientes del nodo cuyo ID es elementId".
yoniLavi