Dois elementos HTML com o mesmo atributo de ID: quão ruim é realmente?

122

Basta navegar no código fonte do google maps. No cabeçalho, eles têm 2 divs com id = "search", um contém o outro e também tem o atributo jstrack = "1". Existe um formulário que os separa assim:

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

Como esse é o google, suponho que não seja um erro.

Então, quão ruim pode ser realmente violar essa regra? Contanto que você tenha cuidado na seleção de css e dom, por que não reutilizar as ids como classes? Alguém faz isso de propósito e, se sim, por quê?

danludwig
fonte
102
"Como esse é o google, suponho que não seja um erro." -> Google não é infalível. Eles cometem erros como o resto de nós.
Joeri Sebrechts
43
na verdade, os caras do Google têm SEARCH trancada em suas mentes que eles não podem pensar em outras id: P
Pankaj Upadhyay
10
Tenho a sensação de que essa página é renderizada a partir de diferentes fragmentos html, de modo que um desenvolvedor em um fragmento usou essa identificação e o mesmo aconteceu com outro desenvolvedor no outro fragmento.
Luciano
10
Toda a questão de "como é que é ruim realmente" só me faz lembrar disto: xkcd.com/292
Daniel Roseman
3
@DanielRoseman xkcd faz isso também: what-if.xkcd.com/23/#question
SQB

Respostas:

140

Especificação diz UNIQUE

A especificação HTML 4.01 diz que o ID deve ser único em todo o documento.

A especificação do HTML 5 diz a mesma coisa, mas em outras palavras. Ele diz que o ID deve ser único em sua subárvore inicial , que é basicamente o documento se lermos a definição dele .

Evitar duplicação

Porém, como os renderizadores de HTML são muito tolerantes no que diz respeito à renderização de HTML, eles permitem IDs duplicados. Isso deve ser evitado se possível e estritamente evitado ao acessar elementos de programação por IDs em JavaScript. Não tenho certeza de qual getElementByIdfunção deve retornar quando vários elementos correspondentes são encontrados? Deveria:

  • retornou um erro?
  • retornar o primeiro elemento correspondente?
  • retornar o último elemento correspondente?
  • retornar um conjunto de elementos correspondentes?
  • retornar nada?

Mas, mesmo que os navegadores funcionem de maneira confiável atualmente, ninguém poderá garantir esse comportamento no futuro, pois isso é contra a especificação. É por isso que eu recomendo que você nunca duplique IDs no mesmo documento.

Robert Koritnik
fonte
1
@missingno: adicionei um link para a especificação HTML 5 que fala sobre a mesma coisa, mas com palavras diferentes.
Robert Koritnik
6
De acordo com a especificação do DOM , "Se mais de um elemento tiver um atributo de ID com esse valor, o que é retornado será indefinido" (pelo que significa que não há resultado "correto" definido, em vez do valor real undefined). Raramente é uma boa ideia confiar em comportamentos indefinidos.
Loneomeday
1
Vale ressaltar que, em HTML5, o data-atributo é útil para quando alguém pode ser tentado a atribuir várias coisas ao mesmo ID. Isso permite que você tenha muitos IDs diferentes com um data-somethingatributo comum em comum. Ainda assim, todos os navegadores que eu conheço ignoram atributos desconhecidos; portanto, eles provavelmente são seguros em praticamente todos os navegadores modernos sem suporte HTML completo.
Tim Post
2
@JoachimSauer: Quando você usa atributos de dados, pode ter pares de valores-chave, o que não é verdade quando você usa classes CSS. Nesse caso, todos são como propriedades booleanas. Um elemento tem uma classe CSS ou não. Se você quiser valores com classes CSS, precisará combiná-los de alguma forma no nome da classe CSS e analisá-los posteriormente. Espero que agora você possa ver os benefícios do uso de dataatributos. E eles também são suportados diretamente pelo jQuery quando você se refere ao data-something="123"atributo with $(elem).data("something").
Robert Koritnik
1
@RobertKoritnik: Claro! Eu não pensei nesse caso de uso. Eu só pensei no caso de id="search".
Joachim Sauer
30

Você perguntou "quão ruim". Então, para esclarecer um pouco a resposta (inteiramente precisa) de RobertKoritnik ...

Esse código está incorreto. Incorreto não vem em tons de cinza. Este código viola o padrão e, portanto, está incorreto. Falharia na verificação da validação, e deveria.

Dito isto, nenhum navegador atualmente no mercado reclamaria ou teria qualquer problema com ele. Os navegadores teriam o direito de reclamar, mas nenhuma das versões atuais de nenhum deles o faz atualmente. O que não significa que versões futuras podem não tratar mal esse código.

Seu comportamento ao tentar usar esse ID como seletor, tanto em css quanto em javascript, é inquestionável e provavelmente varia de navegador para navegador. Suponho que um estudo possa ser feito para ver como cada navegador reage a isso. Eu acho que, na melhor das hipóteses, trataria isso como "class =" e selecione a lista deles. (Porém, isso pode confundir as bibliotecas JavaScript - se eu fosse o autor do jQuery, poderia ter otimizado meu código do seletor para que, se você me encontrar com um seletor começando com "#", espere um único objeto e obtenha um A lista pode estar completamente diferente.)

Ele também pode selecionar o primeiro, ou possivelmente o último, ou não selecionar nenhum deles, ou travar completamente o navegador. Não há como saber sem tentar.

"Quão ruim" depende inteiramente de quão rigorosamente um navegador específico implementa a especificação HTML e o que ele faz quando confrontado com uma violação dessa especificação.

EDIT: Acabei de me deparar com isso hoje. Estou usando vários componentes de formulários de pesquisa em vários tipos de entidades para produzir um grande utilitário de relatórios completo para este site. Estou carregando os formulários de pesquisa das páginas remotas em divs ocultos e colocando-os no meu gerador de relatórios quando o tipo de entidade apropriado é selecionado como a origem do relatório. Portanto, há uma versão oculta do formulário e uma versão exibida no gerador de relatórios. O JavaScript que acompanha o produto, em todos os casos, refere-se a elementos por ID, dos quais agora existem DOIS na página - o oculto e o exibido.

O que o jQuery parece estar fazendo é me escolher o PRIMEIRO, que em todos os casos é exatamente o que NÃO QUERO.

Estou trabalhando nisso, escrevendo seletores para especificar a região da página em que quero obter meu campo (por exemplo: $ ('# containerDiv #specificElement')). Mas há uma resposta para sua pergunta: o jQuery no Chrome definitivamente se comporta de uma maneira particular quando confrontado com essa violação de especificação.

Dan Ray
fonte
... uma pergunta relacionada: stackoverflow.com/q/29295824/287948 sobre obrigação de IDs em um perfil rápido de CSS.
Peter Krauss
3
"Incorreto não vem em tons de cinza." Eu vejo muito isso e é uma daquelas coisas tecnicamente corretas, mas não "verdadeiras" na vida ou na programação. Você indiretamente aborda isso muito bem em sua resposta e eu poderia explicar, mas essa cena de The Big Bang Theory faz um trabalho tão bom que eu deixarei falar por mim e espero fazer alguém rir ... Stuart vs Sheldon youtube.com/ watch? v = F_1zoX5Ax9U
Night Owl
essa é uma resposta de 8 anos, mas acho muito desequilibrado o modo como você exagera na pergunta do OP, mas não reclama muito do comportamento permissivo e perigoso dos navegadores em relação a identificações repetidas, o que é muito pior do que o OP está tentando fazer.
erandros
20

Quão ruim é realmente?

  1. Me faz chorar
  2. É inválido
  3. Muitas bibliotecas javascript não funcionarão conforme o esperado
  4. Isso torna seu código confuso

A experiência diz que getElementById nos principais navegadores retornará o primeiro elemento correspondente no documento. Mas isso nem sempre pode ser o caso no futuro.

Quando o jQuery recebe um ID, por exemplo, #foo, ele usa getElementById e imita esse comportamento. Se você precisar solucionar isso (isso é triste), poderá usar $ (" * #foo") que convencerá o jQuery a usar getElementsByTagName e retornará uma lista de todos os elementos correspondentes.

Muitas vezes tenho que escrever código para outros sites e preciso contornar isso. Em um mundo justo, eu não precisaria reprojetar funções para começar verificando se um ID é único. Os IDs devem sempre ser exclusivos. O mundo é cruel e é por isso que eu choro.

ColBeseder
fonte
5
Essa resposta me fez chorar ... de rir!
precisa
8

Você pode fazer muitas coisas - mas isso não significa que você deveria.

Como programador (de um modo geral), construímos nossas vidas sendo precisas e seguindo as regras - eis uma regra simples de seguir, que é bastante fundamental para o que fazemos - gostamos (dependemos de) de identificadores exclusivos dentro de um determinado escopo ...

Quebrar a regra é algo que podemos fazer porque o navegador é muito flexível - mas, na verdade, estaríamos melhor se os navegadores fossem rigorosos quanto à necessidade de HTML bem formado e válido, a pequena quantidade de dor que isso causaria teria durado muito tempo. foi pago!

Então, é realmente tão ruim assim? Como programador, como você pode perguntar? É um crime contra a civilização (-:


Termo aditivo:

Você escreve que os navegadores são muito flexíveis, como se fosse uma coisa ruim

Sim, porque é - não estamos falando de regras complicadas, estamos falando substancialmente de tornar as coisas bem formadas e de aplicar regras que podem ser testadas mecanicamente e que, por sua vez, facilitam o processamento mecânico do resultado. Se os navegadores fossem rigorosos, as ferramentas teriam se adaptado muito rapidamente para dar suporte a isso - não foi o que fizeram, algumas na medida em que exploram essa falha. Apenas pense nisto: o email teria sido um meio muito melhor se a MS e o Netscape não o tivessem estragado ao permitir HTML irrestrito quando uma "linguagem de marcação de email" muito menos complexa com suporte explícito ao texto citado nos daria uma ferramenta muito melhor ... mas esse navio navegou e da mesma forma que podemos 'deveria ter ) mas não podemos

Murph
fonte
Você escreve que os navegadores são muito flexíveis como se fosse uma coisa ruim, mas certamente você não acredita nisso?
KaptajnKold
4
Não posso falar por Murph, mas com certeza acho que é uma coisa muito ruim. Por outro lado, sem esse nível de perdão, a web pode não ter tido o impulso de crescer como a conhecemos.
Andrea
1
@ Andrea: A internet não teria crescido como a conhecemos. Teria crescido mais lentamente. Mas também teria uma base mais sólida do que é e do que não é o código correto. Rápido, mas desleixado, pode funcionar, mas eu prefiro muito mais devagar, mas correto. Especialmente porque não é como se estivéssemos falando apenas de alguns anos de crescimento.
Nicol Bolas
3
@Andrea Aposto que teria crescido quase tão rapidamente - as ferramentas simplesmente teriam evoluído para lidar com o problema. Considerando que, em muitos casos, as ferramentas foram a causa raiz da marcação incorreta. O fato é que as pessoas tendem a fazer o menos necessário - o passo para "bem formado" é relativamente pequeno e fácil de testar e aplicar, e as pessoas teriam aceitado isso sem estresse significativo
Murph
1
Não é horrível que os navegadores estejam acomodando. É horrível que todos estejam acomodados de maneiras diferentes .
Dan Ray
7

Em Script: getElementByIDretornará apenas a primeira correspondência. Em CSS: #idafetará TODOS os elementos com esse ID. Na renderização do navegador, não terá nenhum efeito.

Este é o comportamento do padrão w3c. Não é possível, é o fato definido.

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

Bart Calixto
fonte
7
Esse é um comportamento possível. getElementByIdpoderia perfeitamente retornar qualquer elemento, ou mesmo um objeto nulo. O efeito CSS pode estar em qualquer elemento, ou em nenhum ou em todos eles. Ou o navegador pode falhar. Fora do padrão, o comportamento é indefinido
rds 27/12
2
Não está fora do padrão, porque o padrão especifica o que fazer nessas situações. Portanto, não, getElementById não pôde retornar nenhum elemento, o padrão diz explícito que retornarei a primeira correspondência. Concordo que o comportamento fora do padrão é indefinido, o que você não entende é que todos esses casos fazem parte do padrão.
22715 Bart
1
Essa resposta seria um pouco melhor se realmente incluísse, como referência, uma citação da parte relevante da norma (ou pelo menos um número de seção).
yoniLavi
2
@yoniLavi atualizado.
Bart Calixto
2
Obrigado @Bart. Você está absolutamente certo :) O padrão diz "Retorna o primeiro elemento entre os descendentes do nó cujo ID é elementId".
yoniLavi