Два елементи HTML з однаковим атрибутом id: Наскільки це насправді погано?


122

Просто переглядайте вихідний код Google Maps. У своєму заголовку вони мають 2 діви з id = "search", один містить інший, а також має атрибут jstrack = "1". Існує форма, що розділяє їх так:

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

Оскільки це Google, я припускаю, що це не помилка.

Тож як погано може бути насправді порушувати це правило? Поки ви обережні у виборі css і dom, чому б не використовувати повторно подібні класи? Хтось робить це спеціально, і якщо так, то чому?


102
"Оскільки це Google, я припускаю, що це не помилка". -> Google не є непогрішними. Вони роблять помилки, як і решта нас.
Joeri Sebrechts

43
на самому справі хлопці в гуглі вже ПОШУК болтах в їхній свідомості , тому вони не можуть думати ні про які інші ідентифікаторів: P
Панкай Upadhyay

10
У мене таке відчуття, що ця сторінка відображається з різних фрагментів html, тому один розробник в одному фрагменті використовував цей ідентифікатор, і те саме сталося з іншим розробником в іншому фрагменті.
Лучано

10
Ціле питання про те, "як це насправді погано", просто нагадує мені про це: xkcd.com/292
Даніель Роузмен

3
@DanielRoseman xkcd робить це також: what-if.xkcd.com/23/#question
SQB

Відповіді:


140

Специфікація говорить УНІКАЛЬНО

Специфікація HTML 4.01 говорить, що ідентифікатор повинен бути унікальним для документа.

Специфікація 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

Ви запитали "як погано". Тож, щоб чітко визначитись (цілком точна) відповідь Роберта Корітника ...

Цей код невірний. Неправильне не виходить у відтінках сірого. Цей код порушує стандарт і тому є неправильним. Це не вдасться перевірити перевірку, і це повинно.

Однак, жоден веб-переглядач, який зараз є на ринку, не скаржиться на це або не матиме жодних проблем. Веб-браузери мають право скаржитися на це, але жодна з нинішніх версій жодної з них наразі не робить. Що не означає, що майбутні версії можуть не поводитися з цим кодом погано.

Ваша поведінка, намагаючись використовувати цей ідентифікатор як селектор, або в css, або в JavaScript, не може використовуватись і, ймовірно, залежить від браузера до браузера. Я припускаю, що можна провести дослідження, щоб побачити, як кожен браузер реагує на це. Я думаю, що в кращому випадку, він би трактував це так само, як "class =", і вибирав їх список. (Це може заплутати бібліотеки JavaScript, - якби я був автором jQuery, я міг би оптимізувати свій селекторний код, так що якщо ви прийдете до мене з селектором, що починається з "#", я очікую на один об'єкт і отримаю список міг би мене повністю перевантажити.)

Він також може вибрати перший, або, можливо, останній, або вибрати жоден з них, або повне збої браузера. Немає способу сказати, не намагаючись.

"Наскільки погано", то повністю залежить від того, наскільки суворо конкретний браузер реалізує специфікацію HTML, і що він робить, коли стикається з порушенням цієї специфікації.

РЕДАКТИ: Я ДІЙСЬКИЙ ДІЙСЬКИЙ ДІЙСЬКИЙ СТАТИЙ Цього сьогодні. Я перетягую різні компоненти від форм пошуку для різних типів об'єктів, щоб створити велику велику утиліту звітності "все в одному" для цього сайту, я завантажую форми пошуку віддалених сторінок у приховані диви і розміщую їх у моїх генератор звітів, коли в якості джерела звіту вибрано відповідний тип сутності. Отже, є прихована версія форми та версія, що відображається в генераторі звітів. JavaScript, який постачався разом із усіма випадками, посилається на елементи за ідентифікатором, яких зараз на ДВІ на сторінці - прихований та відображений.

Що, здається, робить jQuery - це обирати мене ПЕРШИМ, який у всіх випадках - саме той, якого я НЕ хочу.

Я працюю над цим, записуючи селектори, щоб вказати регіон сторінки, в якій я хочу отримати своє поле (тобто: $ ('# containerDiv #specificElement')). Але є одне відповідь на ваше запитання - jQuery в Chrome, безумовно, поводиться особливим чином, стикаючись із цим специфікаційним порушенням.


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

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

це 8-річна відповідь, але я думаю, що це дуже неврівноважено, як ви гіперболуєте на питання ОП, але не скаржитеся на вседозволеність та небезпечну поведінку браузерів щодо повторних ідентифікаторів, що набагато гірше, ніж те, що намагаються зробити ОП.
erandros

20

Наскільки насправді це погано?

  1. Це змушує мене плакати
  2. Це недійсне
  3. Багато бібліотек javascript не працюватимуть, як очікувалося
  4. Це робить ваш код заплутаним

Досвід говорить, що getElementById у основних браузерах поверне перший збіглий елемент у документі. Але це може бути не завжди в майбутньому.

Коли jQuery отримують ідентифікатор, наприклад, #foo, він використовує getElementById і імітує цю поведінку. Якщо вам доведеться обійти це (це сумно), ви можете скористатися $ (" * #foo"), що переконає jQuery використовувати getElementsByTagName і повернути список усіх відповідних елементів.

Мені часто доводиться писати код для інших сайтів, і мені доводиться це робити. У справедливому світі мені не доведеться переробляти функції для запуску, перевіряючи, чи унікальний ідентифікатор. Ідентифікатори завжди повинні бути унікальними. Світ жорстокий, і тому я плачу.


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

8

Ви можете зробити багато чого, але це не означає, що вам слід.

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

Порушити правило - це те, що ми можемо зробити, тому що браузер занадто пристосований - але насправді нам би все було краще, якби браузери суворо ставились до необхідності добре сформованого та дійсного HTML-коду, то невелика кількість болю, що це спричинило б, давно б було погашено!

Отже, чи справді це погано? Як програміст, як ви навіть можете запитати? Це злочин проти цивілізації (-:


Додаток:

Ви пишете, що браузери занадто пристосовані, ніби це погано

Я це роблю, тому що це - ми не говоримо про складні правила, ми говоримо по суті про те, щоб зробити речі добре сформованими та іншим чином застосувати правила, які можна перевірити механічно і які, у свою чергу, полегшують механічну обробку результату. Якби браузери були суворими, інструменти дуже швидко адаптували б це для того, щоб це підтримати - це було не так, як не вони, в тій мірі, в якій вони скористаються цим недоліком. Подумайте лише про це - електронна пошта була б набагато приємнішим середовищем, якби MS та Netscape не прикрутили її, дозволяючи необмежений HTML, коли набагато менш складний "мова розмітки електронної пошти" з явною підтримкою цитованого тексту дав би нам набагато кращий інструмент ... але цей корабель приплив, і ми можемо так само 'повинно бути ), але ми не можемо


Ви пишете, що браузери занадто пристосовані, як це погано, але напевно ви не вірите в це?
KaptajnKold

4
Я не можу говорити за Мерфа, але я точно думаю, що це дійсно погано. Знову ж таки, без такого рівня прощення, павутина, можливо, не мала поштовху рости так, як ми це знаємо.
Андреа

1
@Andrea: Інтернет не виріс би так, як ми це знаємо. Воно б росло повільніше. Але це також мало б більш міцну основу того, що є, а не є правильним кодом. Швидке, але неохайне може працювати, але я більше віддаю перевагу повільнішому, але правильному. Тим більше, що це не так, як ми б говорили лише про пару років зростання чи близько того.
Нікол Болас

3
@Andrea Б'юсь об заклад, що він виріс би так само швидко - інструменти просто розвинулися б для вирішення проблеми. Тоді як у багатьох випадках інструменти були першопричиною поганої розмітки. Справа в тому, що люди, як правило, роблять найменш необхідне - крок до "добре сформованого" - порівняно невеликий і досить простий для перевірки та виконання, і люди могли б помістити це без істотного стресу
Мерф

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. Ви абсолютно праві :) Стандарт говорить: "Повертає перший елемент у нащадках вузла, ідентифікатор якого є elementId."
yoniLavi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.