Два HTML-элемента с одинаковым атрибутом id: насколько это плохо на самом деле?


122

Просто просмотрите исходный код Google Maps. В заголовке у них есть 2 div с id = "search", один содержит другой, а также имеет атрибут jstrack = "1". Есть форма, разделяющая их так:

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

Поскольку это Google, я предполагаю, что это не ошибка.

Так как же плохо на самом деле нарушать это правило? Пока вы осторожны в выборе css и dom, почему бы не использовать id как классы? Кто-нибудь делает это нарочно, и если да, то почему?


102
«Поскольку это Google, я предполагаю, что это не ошибка». -> Google не безошибочен. Они делают ошибки, как и все мы.
Джори Себрехтс

43
на самом деле, ребята из Google имеют в своем уме ПОИСК, поэтому они не могут думать ни о каких других идентификаторах: P
Pankaj Upadhyay

10
У меня такое ощущение, что эта страница отображается из разных фрагментов HTML, поэтому один разработчик в одном фрагменте использовал этот идентификатор, и то же самое произошло с другим разработчиком в другом фрагменте.
Лучано

10
Весь вопрос о том, «насколько это плохо на самом деле», просто напоминает мне об этом: xkcd.com/292
Даниэль

3
@DanielRoseman xkcd делает то же самое
SQB

Ответы:


140

Спецификация говорит, что УНИКАЛЬНО

Спецификация HTML 4.01 говорит, что ID должен быть уникальным для всего документа.

Спецификация HTML 5 говорит то же самое, но другими словами. В нем говорится, что ID должен быть уникальным в своем домашнем поддереве , которое в основном является документом, если мы прочитаем его определение .

Избегайте дублирования

Но поскольку средства визуализации HTML очень просты, когда речь идет об отображении HTML, они допускают дублирование идентификаторов. Этого следует избегать, если это вообще возможно, и строго избегать при программном доступе к элементам по идентификаторам в JavaScript. Я не уверен, что getElementByIdфункция должна возвращать, когда найдено несколько соответствующих элементов? Если это:

  • вернуть ошибку?
  • вернуть первый соответствующий элемент?
  • вернуть последний соответствующий элемент?
  • вернуть набор совпадающих элементов?
  • ничего не вернуть?

Но даже если браузеры работают надежно в наши дни, никто не может гарантировать такое поведение в будущем, поскольку это противоречит спецификации. Вот почему я рекомендую вам никогда не дублировать идентификаторы в одном документе.


1
@missingno: я добавил ссылку на спецификацию HTML 5, в которой говорится об одном и том же, но в другой редакции.
Роберт Коритник

6
Согласно спецификации DOM , «если более одного элемента имеют атрибут ID с этим значением, то возвращаемое значение не определено» (что означает, что нет определенного «правильного» результата, а не фактического значения undefined). Редко хорошая идея полагаться на неопределенное поведение.
одинокий

1
Стоит отметить, что в HTML5 этот data-атрибут пригодится, когда можно поддаться искушению присвоить нескольким вещам один и тот же идентификатор. Это позволяет вам иметь много разных идентификаторов с одним общим data-somethingатрибутом. Тем не менее, все известные мне браузеры игнорируют неизвестные атрибуты, поэтому они, вероятно, безопасны практически во всех современных браузерах, в которых отсутствует полная поддержка HTML.
Тим Пост

2
@JoachimSauer: при использовании атрибутов данных у вас могут быть пары ключ-значение, что неверно при использовании классов CSS. В этом случае они все похожи на логические свойства. Элемент либо имеет класс CSS, либо нет. Если вам нужны значения с классами CSS, вам нужно как-то объединить их в имя класса CSS и проанализировать их впоследствии. Я надеюсь, что теперь вы можете увидеть преимущества использования dataатрибутов. И они также поддерживаются прямо из коробки jQuery, когда вы просто ссылаетесь на data-something="123"атрибут с помощью $(elem).data("something").
Роберт Коритник

1
@RobertKoritnik: Конечно! Я не думал об этом сценарии использования. Я думал только о случае id="search".
Йоахим Зауэр

30

Вы спросили "как плохо". Таким образом, чтобы конкретизировать ответ @ RobertKoritnik (полностью точный) немного ...

Этот код неверен. Неправильно не входит в оттенки серого. Этот код нарушает стандарт и поэтому является неправильным. Это провалило бы проверку правильности, и это должно.

Тем не менее, ни один браузер в настоящее время на рынке не будет жаловаться или иметь какие-либо проблемы с ним вообще. Браузеры могут жаловаться на это, но ни одна из текущих версий ни одной из них в настоящее время не делает. Что не означает, что будущие версии могут плохо относиться к этому коду.

Ваше поведение, когда вы пытаетесь использовать этот идентификатор в качестве селектора в CSS или JavaScript, невозможно угадать и, вероятно, варьируется от браузера к браузеру. Я полагаю, можно провести исследование, чтобы увидеть, как каждый браузер реагирует на это. Я думаю, что в лучшем случае это будет восприниматься как «класс =» и выбирать список из них. (Однако это может сбить с толку библиотеки JavaScript - если бы я был автором jQuery, я мог бы оптимизировать мой код селектора, чтобы, если вы пришли ко мне с селектором, начинающимся с «#», я ожидал один объект и получил список может полностью меня лишить.)

Он также может выбрать первый или, возможно, последний, или выбрать ни один из них, или полностью вызвать сбой браузера. Невозможно сказать, не пытаясь это сделать.

«Как плохо» полностью зависит от того, насколько строго конкретный браузер реализует спецификацию HTML и что он делает, когда сталкивается с нарушением этой спецификации.

РЕДАКТИРОВАТЬ: Я просто случайно столкнулся с этим сегодня. Я добавляю различные компоненты из форм поиска на различные типы объектов, чтобы создать большую большую универсальную утилиту для создания отчетов для этого сайта, загружаю формы поиска удаленных страниц в скрытые элементы и делю их на свои Генератор отчетов, когда в качестве источника отчета выбран соответствующий тип объекта. Таким образом, есть скрытая версия формы и версия, отображаемая в генераторе отчетов. JavaScript, который прилагается, во всех случаях относится к элементам по идентификатору, которых на странице теперь двое - скрытый и отображаемый.

Кажется, что jQuery делает то, что выбрал меня ПЕРВЫМ, что во всех случаях именно то, что я НЕ хочу.

Я работаю над этим, написав селекторы, чтобы указать регион страницы, в который я хочу получить свое поле (т. Е. $ ('# ContainerDiv #specificElement')). Но есть один ответ на ваш вопрос - jQuery в Chrome определенно ведет себя определенным образом, когда сталкивается с этим нарушением спецификации.


... связанный вопрос: stackoverflow.com/q/29295824/287948 об обязательстве идентификаторов в быстром профиле CSS.
Питер Краусс

3
«Неправильно не входит в оттенки серого». Я часто вижу это, и это одна из тех вещей, которые технически правильны, но не «верны» в жизни или в программировании. Вы косвенно освещаете это довольно подробно в своем ответе, и я могу объяснить, но эта сцена из «Теории большого взрыва» делает такую ​​хорошую работу, что я позволю ей говорить за меня и, надеюсь, рассмешить кого-то ... Стюарт против Шелдона youtube.com/ смотреть? v = F_1zoX5Ax9U
Ночная сова

Это 8-летний ответ, но я думаю, что он очень несбалансирован в том, как вы гипербола в вопросе OP, но не жалуетесь на разрешающее и опасное поведение браузеров в отношении повторяющихся идентификаторов, что намного хуже, чем то, что пытается сделать OP.
эрандрос

20

Насколько это плохо на самом деле?

  1. Это заставляет меня плакать
  2. Это недействительно
  3. Многие библиотеки JavaScript не будут работать, как ожидалось
  4. Это делает ваш код запутанным

Опыт показывает, что getElementById в основных браузерах возвращает первый соответствующий элемент в документе. Но это не всегда может иметь место в будущем.

Когда jQuery присваивается идентификатор, например #foo, он использует getElementById и имитирует это поведение. Если вам нужно обойти это (это печально), вы можете использовать $ (" * #foo"), который убедит jQuery использовать getElementsByTagName и вернет список всех соответствующих элементов.

Мне часто приходится писать код для других сайтов, и я должен обойти это. В справедливом мире мне не пришлось бы перепроектировать функции, чтобы начать с проверки уникальности идентификатора. Идентификаторы всегда должны быть уникальными. Мир жесток, и поэтому я плачу.


5
Этот ответ заставил меня плакать ... от смеха!
A1rPun

8

Вы можете сделать очень много вещей - но это не значит, что вы должны.

Как программист (вообще говоря), мы строим свою жизнь на точности и следовании правилам - вот простое правило, которому нужно следовать, которое является фундаментальным для того, что мы делаем, - нам нравятся (зависят от) уникальные идентификаторы в данной области ...

Нарушение правила - это то, что мы можем сделать, потому что браузер слишком приспособлен - но на самом деле нам всем было бы лучше, если бы браузеры строго требовали правильного и корректного HTML, небольшая боль, которую это вызвало бы, давно бы был погашен!

Так действительно ли это плохо? Как программист, как вы можете даже спросить? Это преступление против цивилизации (-:


Приложение:

Вы пишете, что браузеры слишком вежливы, как будто это плохо

Я делаю, потому что это - мы не говорим о сложных правилах, мы в основном говорим о том, чтобы сделать вещи правильно сформированными и в противном случае применять правила, которые могут быть проверены механически и которые, в свою очередь, облегчают механическую обработку результата. Если бы браузеры были строгими, тогда инструменты очень быстро адаптировались бы для поддержки этого - это было не так, не так, а некоторые в той степени, в которой они используют этот сбой. Подумайте об этом - электронная почта была бы намного приятнее, если бы MS и Netscape не облажались, допустив неограниченный HTML, когда гораздо менее сложный «язык разметки электронной почты» с явной поддержкой цитируемого текста дал бы нам гораздо лучший инструмент ... но этот корабль плыл и так же мы можемдолжен был ) но мы не можем


Вы пишете, что браузеры слишком вежливы, как будто это плохо, но наверняка вы в это не верите?
KaptajnKold

4
Я не могу говорить за Мёрфа, но я наверняка думаю, что это действительно плохо. Опять же, без этого уровня прощения у сети, возможно, не было бы импульса расти, как мы его знаем.
Андреа

1
@ Андреа: Интернет не вырос бы, как мы его знаем. Это росло бы медленнее. Но у этого также было бы более твердое основание того, что является и не является правильным кодом. Быстро, но неаккуратно, но я предпочитаю медленнее, но правильнее. Тем более, что мы не будем говорить о пару лет роста или около того.
Николь Болас

3
@ Андреа, держу пари, что он вырос бы почти так же быстро - инструменты просто развились бы, чтобы справиться с проблемой. В то время как во многих случаях инструменты были основной причиной плохой разметки. Дело в том, что люди, как правило, делают наименее необходимое - шаг к «хорошо сформированному» является относительно небольшим и достаточно легким для проверки и применения, и люди могли бы справиться с этим без значительного стресса
Мерф

1
Это не ужасно, что браузеры любезны. Это ужасно, что все они по-разному приспосабливаются .
Дэн Рэй

7

В сценариях: getElementByIDвернется только первый матч. В CSS: #idповлияет на ВСЕ элементы с этим идентификатором. В браузере рендер не будет иметь никакого эффекта.

Это поведение стандарта w3c. Это невозможно, это факт, определенный.

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


7
Это одно из возможных действий. getElementByIdможет отлично вернуть любой элемент или даже нулевой объект. Эффект CSS может быть на любых элементах или на всех или на всех. Или браузер может зависнуть. Нестандартное поведение не определено
rds

2
Это не вне стандарта, потому что стандарт определяет, что делать в таких ситуациях. Так что нет, getElementById не может вернуть какой-либо элемент, стандарт прямо говорит, что я верну первое совпадение. Я согласен, что поведение вне стандарта не определено, но вы не понимаете, что все эти случаи являются частью стандарта.
Барт Каликсто

1
Этот ответ был бы несколько лучше, если бы он действительно включал в качестве ссылки цитату соответствующей части стандарта (или, по крайней мере, номер раздела).
yoniLavi

2
@yoniLavi обновлен.
Барт Каликсто

2
Спасибо @Bart. Вы абсолютно правы :) Стандарт гласит: «Возвращает первый элемент в потомках узла, чей ID это elementId».
yoniLavi
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.