Могут ли несколько разных HTML-элементов иметь одинаковый идентификатор, если они разные?

144

Могут ли несколько элементов HTML иметь одинаковый идентификатор, если они относятся к разным типам элементов? Верен ли такой сценарий? Например:

div#foo
span#foo
a#foo
всезнайка
источник
26
Иногда это возможно, но никогда не действует.
Пол Кризи
3
При всем вышесказанном стоит отметить, что в документе с контентом, созданным пользовательским агентом (например, frameworks, mv *, react, полимер ...), вероятно, встретятся несколько одинаковых идентификаторов. Вот если кому-то было интересно, почему очень профессионально выглядящий сайт XYZ полон такой плохой практики кодирования.
Лукаш Матысяк
Комментарий от @PaulCreasey - хороший способ ответить на этот проблемный вопрос. Заголовок и текст вопроса не совпадают; каждый из них является разумным вопросом «да» или «нет», но с разными правильными ответами - это может уловить людей, которые не обращают внимания. Есть мета-вопрос о том, как разрешить подобные несоответствия вопросов, но пока ответов нет: meta.stackoverflow.com/questions/256732
Tidorith
Привет, @Tidorith! Спасибо за комментарий. Я открыт для предложения об изменении заголовка или текста, если у вас есть идея. Первоначальный вопрос был задан из любопытства. Какой-то инструмент кодогенерации (я думаю, это могла быть какая-то библиотека пользовательского интерфейса Microsoft) генерировал элементы с идентичными идентификаторами. Я попытался прочитать спецификацию и протестировать ее в браузерах, но остался в замешательстве, поскольку браузеры, казалось, позволяли это, а в спецификации говорилось «нет».
omninonsense
@Tidorith Немного отредактировал текст вопроса. Надеюсь, теперь стало лучше!
omninonsense

Ответы:

181

Нет.

Идентификаторы элементов должны быть уникальными в пределах всего документа.

SLaks
источник
89
Каковы последствия невыполнения этого требования?
corsiKa
17
@corsiKa последствием является неопределенное поведение, например, что возвращает document.getElementById ("# foo") или $ ("# foo") при наличии нескольких #foos? Вы столкнетесь с проблемами, когда сможете работать с этими элементами из JS, передавать их в качестве селекторов в библиотеки / API / Flash и т. Д.
mrooney
81
Это неверно. Вполне возможно иметь несколько элементов с одним и тем же идентификатором. Обычно это не лучшая практика , но время от времени она используется. Кажется, все цитируют, как будут работать селекторы, ну, если вы знаете, что у вас будут конфликтующие идентификаторы, вы используете свои селекторы с родителем, где идентификаторы под родительским элементом будут уникальными. например, $('div#car span#size)и $('div#truck span#size').
BJury 02
19
зачем даже использовать несколько одинаковых идентификаторов, когда у вас есть класс для этой цели?
Макс Яри
8
Да, на практике несколько идентификаторов можно заменить с помощью классов. Однако классы предназначены для применения стилей, а не для идентификации элементов, что значительно увеличивает объем имен и, следовательно, может перекрываться. Особенно при использовании сторонних библиотек. Id как «идентификатор» не предназначен для умножения, поэтому явно необходимо что-то среднее. Практическое использование - это разбиение разделов страницы / домена на отдельные логические блоки. Следовательно, требуется использование (как минимум) двухуровневой идентификации.
Ален Сильджак
88

Я думаю, есть разница между тем, ДОЛЖНО ли что-то быть уникальным или ДОЛЖНО быть уникальным (т. Е. Обеспечивается веб-браузерами).

Должны ли идентификаторы быть уникальными? ДА.

Идентификаторы должны быть уникальными? НЕТ, по крайней мере IE и FireFox позволяют нескольким элементам иметь один и тот же идентификатор.

Джин Ким
источник
6
Как и Chrome (версия 22 на момент написания этого комментария). : D
omninonsense
27
Согласно спецификации , это ОБЯЗАТЕЛЬНО, а не ОБЯЗАТЕЛЬНО. (Он по-прежнему работает в большинстве браузеров? Да. Это правильный HTML? Нет. Кроме того, getElementByIdв таких случаях результатом является то undefined, что невозможно определить, как браузер может решить его обрабатывать.)
Лео
2
@leo, однако, это реальный мир, где браузеры не полностью соответствуют стандартам. В этом случае это может быть хорошо, поскольку нет причин вводить уникальные идентификаторы.
BJury 02
3
В HTML5 спецификация на getElementByIdсамом деле определяет, что должен быть возвращен первый элемент с данным идентификатором (именно так все браузеры в настоящее время обрабатывают ситуацию) - подробнее см. Мой ответ ниже.
млцы
1
Не плачь, пользуйся jQuery. @leo
Максима Алекз 06
72

Могут ли несколько элементов иметь одинаковый идентификатор?

Да - независимо от того, являются ли они одним и тем же тегом, браузеры будут отображать страницу, даже если несколько элементов имеют одинаковый идентификатор.

Это действительный HTML?

Нет. Это все еще верно для спецификации HTML 5.1 . Однако в спецификации также говорится, что getElementById должен возвращать первый элемент с данным идентификатором , что делает поведение не неопределенным в случае недопустимого документа.

Каковы последствия этого типа недействительного HTML?

Большинство (если не все) браузеры выбрали и все еще выбирают первый элемент с заданным идентификатором при вызове getElementById. Большинство библиотек, которые находят элементы по идентификатору, наследуют это поведение. Большинство (если не все) браузеры также применяют стили, назначенные селекторами идентификаторов (например #myid), ко всем элементам с указанным идентификатором. Если это то, чего вы ожидаете и намерены, то непредвиденных последствий не будет. Если вы ожидаете / намереваетесь что-то еще (например, чтобы все элементы с этим идентификатором были возвращены, или чтобы стиль применялся только к одному элементу), ваши ожидания не будут выполнены, и любая функция, основанная на этих ожиданиях, потерпит неудачу.

Некоторые библиотеки javascript действительно имеют ожидания, которые не оправдываются, когда несколько элементов имеют одинаковый идентификатор (см . Комментарий wootscootinboogie о d3.js)

Вывод

Лучше придерживаться стандартов, но если вы знаете, что ваш код работает должным образом в ваших текущих средах, и эти идентификаторы используются предсказуемым / поддерживаемым способом, то есть только две практические причины не делать этого:

  1. Чтобы избежать вероятности того, что вы ошибаетесь, и одна из используемых вами библиотек действительно не работает, когда несколько элементов имеют одинаковый идентификатор.
  2. Чтобы поддерживать прямую совместимость вашего веб-сайта / приложения с библиотеками или службами (или разработчиками!), Вы можете столкнуться в будущем со сбоями, когда несколько элементов имеют одинаковый идентификатор - что является разумной возможностью, поскольку это технически недействительно. HTML.

Сила твоя!

млцы
источник
Отличный ответ. всегда лучше, если вы будете придерживаться стандартов.
EKanadily
25

Даже если элементы бывают разных типов, это может вызвать у вас серьезные проблемы ...

Предположим, у вас есть 3 кнопки с одинаковым идентификатором:

<button id="myid" data-mydata="this is button 1">button 1</button>
<button id="myid" data-mydata="this is button 2">button 2</button>
<button id="myid" data-mydata="this is button 3">button 3</button>

Теперь вы настраиваете jQueryкод, чтобы что-то делать при myidнажатии кнопок:

$(document).ready(function ()
{
    $("#myid").click(function ()
    {
        var buttonData = $(this).data("mydata");

        // Call interesting function...
        interestingFunction();

        $('form').trigger('submit');
    });
});

Чего бы вы ожидали? Каждая нажатая кнопка будет запускать установку обработчика событий щелчка с помощью jQuery. К сожалению, этого не произойдет. ТОЛЬКО первая кнопка вызывает обработчик щелчка. Остальные 2 при нажатии ничего не делают. Как будто они вовсе не были кнопками!

Так всегда назначать разные IDsдля HTMLэлементов. Это защитит вас от странных вещей. :)

<button id="button1" class="mybtn" data-mydata="this is button 1">button 1</button>
<button id="button2" class="mybtn" data-mydata="this is button 2">button 2</button>
<button id="button3" class="mybtn" data-mydata="this is button 3">button 3</button>

Теперь, если вы хотите, чтобы обработчик события щелчка запускался при нажатии любой из кнопок, он будет отлично работать, если вы измените селектор в коде jQuery, чтобы использовать CSSкласс, примененный к ним следующим образом:

$(document).ready(function ()
{
    $(".mybtn").click(function ()
    {
        var buttonData = $(this).data("mydata");

        // Call interesting function...
        interstingFunction();

        $('form').trigger('submit');
    });
});
Лениэль Маккаферри
источник
что, если у меня есть "#content", на который я уже ссылался в переменной, и # my-div #content, которое у меня есть только на несколько мгновений, после чего я удаляю указанный узел и забываю его переменную, после чего # div #content выполняет myDiv.outerHTML = myDiv.innerHTML для замены оригинала. Это избавляет от необходимости копировать все стили и содержимое #content в #decoy и делать то же самое. Это имеет смысл при выполнении переходов.
Дмитрий
Это означает, что даже если я использую 'append' для добавления нескольких элементов с одинаковым идентификатором, DOM считает реальным только первый элемент, в идеале 1 ID = 1 элемент
Karan Kaw
22

Нет. Два элемента с одинаковым идентификатором недопустимы. Идентификаторы уникальны, если вы хотите сделать что-то подобное, используйте класс. Не забывайте, что элементы могут иметь несколько классов, используя пробел в качестве разделителя:

<div class="myclass sexy"></div>
Газлер
источник
12

Официальная спецификация для HTML гласит, что теги идентификаторов должны быть уникальными, И в официальной спецификации также говорится, что если рендеринг может быть завершен, он должен (т.е. в HTML нет такой вещи, как «ошибки», только «недействительный» HTML). Итак, ниже показано, как теги id работают на практике . Все они недействительны , но работают:

Этот:

<div id="unique">One</div>
<div id="unique">Two</div>

Хорошо отображается во всех браузерах. Однако document.getElementById возвращает только объект, а не массив; вы сможете выбрать только первый div с помощью тега id. Если вы измените идентификатор первого div с помощью JavaScript, второй идентификатор будет доступен с помощью document.getElementById (проверено в Chrome, FireFox и IE11). Вы по-прежнему можете выбрать div, используя другие методы выбора, и его свойство id будет возвращено правильно.

Обратите внимание, что указанная выше проблема открывает потенциальную уязвимость безопасности на сайтах, которые отображают изображения SVG, поскольку SVG могут содержать элементы DOM, а также теги id на них (разрешает перенаправление DOM сценария через загруженные изображения). Пока SVG расположен в DOM перед заменяемым элементом, изображение будет получать все события JavaScript, предназначенные для другого элемента.

Насколько я знаю, эта проблема в настоящее время никого не интересует, но она реальна.

Этот:

<div id="unique" id="unique-also">One</div>

Также отлично отображается во всех браузерах. Однако используется только первый идентификатор, который вы определяете таким образом, если вы пробовали document.getElementById ('unique-also'); в приведенном выше примере вам будет возвращено значение null (проверено в Chrome, FireFox и IE11).

Этот:

<div id="unique unique-two">Two</div>

Также отлично отображается во всех браузерах, однако, в отличие от тегов классов, которые могут быть разделены пробелом, тег id допускает пробелы, поэтому идентификатор вышеуказанного элемента фактически равен «unique unique-two» и запрашивает у dom значение «unique» или «unique-two» изолированно возвращает null, если иное не определено где-либо в DOM (проверено в Chrome, FireFox и IE11).

Ник Стил
источник
1
«тег id допускает пробелы» - хотя, согласно спецификации , «значение не должно содержать пробелов».
MrWhite
Согласен. Однако есть спецификация и то, как работают браузеры. Исторически браузеры рассматривали спецификацию как некую цель, но не были строги по многим параметрам. Я думаю, они делают это, потому что, если они соответствуют спецификации, это нарушит работу многих существующих сайтов или что-то в этом роде. Я упоминаю вверху, что, хотя эти вещи работают, они недействительны.
Ник Стил
5

Ответ SLaks правильный, но в качестве дополнения обратите внимание, что в спецификациях x / html указано, что все идентификаторы должны быть уникальными в (одном) html-документе . Хотя это не совсем то, о чем спрашивал оператор, могут быть допустимые случаи, когда один и тот же идентификатор привязан к разным объектам на нескольких страницах.

Пример:

(обслуживается в современных браузерах) article # main-content {в одностороннем стиле }
(используется в устаревших версиях) div # main-content { в другом стиле }

Хотя, наверное, антипаттерн. Просто уйду отсюда как защитник дьявола.

RobW
источник
1
Хорошая точка зрения. Хотя динамически генерируемый контент, который предполагается вставить на другую страницу, должен вообще избегать идентификаторов. Идентификаторы похожи на глобальные переменные в языках программирования, вы можете их использовать, и есть допустимые случаи, когда это хороший способ упрощения. Хорошая практика - подумать о том, чтобы сделать что-то правильно, прежде чем делать хаки.
psycho brm
4

И чего бы это ни стоило, по крайней мере, в Chrome 26.0.1410.65, Firefox 19.0.2 и Safari 6.0.3, если у вас есть несколько элементов с одним и тем же идентификатором, селекторы jquery (по крайней мере) вернут первый элемент с этим идентификатором.

например

<div id="one">first text for one</div>
<div id="one">second text for one</div>

а также

alert($('#one').size());

См. Http://jsfiddle.net/RuysX/ для теста.

денишаскин
источник
Если вы не используете более сложный селектор, такой как, div#oneконечно, это не меняет того факта, что он недействителен.
Kevin B
Возможно, это правильный ответ, я говорю это на собственном опыте.
Дибьяншу Джайсвал
4

Что ж, используя валидатор HTML на w3.org , специфичный для HTML5, идентификаторы должны быть уникальными.

Рассмотрим следующее ...

<!DOCTYPE html> 
<html>
    <head>
        <meta charset="UTF-8">
        <title>MyTitle</title> 
    </head>
    <body>
        <div id="x">Barry</div>
        <div id="x">was</div>
        <div id="x">here</div>
    </body>
</html>

валидатор отвечает ...

Line 9, Column 14: Duplicate ID x.      <div id="x">was</div>
Warning Line 8, Column 14: The first occurrence of ID x was here.       <div id="x">Barry</div>
Error Line 10, Column 14: Duplicate ID x.       <div id="x">here</div>
Warning Line 8, Column 14: The first occurrence of ID x was here.       <div id="x">Barry</div>

... но в OP конкретно указано - как насчет разных типов элементов. Итак, рассмотрим следующий HTML ...

<!DOCTYPE html> 
<html>
    <head>
        <meta charset="UTF-8">
        <title>MyTitle</title> 
    </head>
    <body>
        <div id="x">barry
            <span id="x">was here</span>
        </div>
    </body>
</html>

... результат валидатора ...

Line 9, Column 16: Duplicate ID x.          <span id="x">was here</span>
Warning Line 8, Column 14: The first occurrence of ID x was here.       <div id="x">barry

Вывод:

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

баррипикер
источник
2

Да, они могут.

Я не знаю, устарели ли все эти ответы, но просто откройте YouTube и проверьте HTML. Попробуйте просмотреть предложенные видео, вы увидите, что все они имеют одинаковый идентификатор и повторяющуюся структуру, как показано ниже:

<span id="video-title" class="style-scope ytd-compact-radio-renderer" title="Mix - LARA TACTICAL">
Каратель
источник
1

<div id="one">first text for one</div>
<div id="one">second text for one</div>

var ids = document.getElementById('one');

идентификаторы содержат только первый элемент div. Таким образом, даже если есть несколько элементов с одинаковым идентификатором, объект документа вернет только первое совпадение.

Ганеш Фирке
источник
1

Как насчет прагматичного ответа.

Заходим на YouTube и запускаем этот код

Object.fromEntries(Object.entries([...document.querySelectorAll('[id]')].reduce((s, e) => { s[e.id] = (s[e.id] || 0) + 1; return s; }, {})).filter(([k,v]) => v > 1))

и увидеть все повторяющиеся идентификаторы.

введите описание изображения здесь

Изменение приведенного выше кода для отображения идентификаторов, повторяющихся более 10 раз, вот список, который он создал

additional-metadata-line: 43
avatar: 46
avatar-link: 43
button: 120
buttons: 45
byline-container: 45
channel-name: 44
container: 51
content: 49
details: 43
dismissable: 46
dismissed: 46
dismissed-content: 43
hover-overlays: 45
img: 90
menu: 50
meta: 44
metadata: 44
metadata-line: 43
mouseover-overlay: 45
overlays: 45
repeat: 36
separator: 43
text: 49
text-container: 44
thumbnail: 46
tooltip: 80
top-level-buttons: 45
video-title: 43
video-title-link: 43

Другие сайты, которые используют один и тот же идентификатор более одного раза, включают Amazon.com, ebay.com, Expedia.com, cnn.com.

очевидно, что идентификаторы - это просто еще одна часть метаданных элемента.

getElementByIdв значительной степени устарело. Вы можете использовать querySelectorAllдля всех элементов или querySelectorдля первого, независимо от селектора, поэтому, если вам нужны все элементы с идентификатором, fooтогда

document.querySelectorAll('#foo')  // returns all elements with id="foo"

где, как если бы вы хотите использовать только первый элемент querySelector

document.querySelector('#foo')  // returns the first element with id="foo"
document.querySelector('.foo')  // returns the first element with class "foo"
document.querySelector('foo')   // returns the first <foo> element
document.querySelector('foo .foo #foo') // returns the first element with
                                        // id="foo" that has an ancestor
                                        // with class "foo" who has an
                                        // ancestor <foo> element.

И мы видим, что с помощью селекторов мы можем находить разные элементы с одним и тем же идентификатором.

function addClick(selector, add) {
  document.querySelector(selector).addEventListener('click', function() {
    const e = this.parentElement.querySelector('span');
    e.textContent = parseInt(e.textContent) + add;
  });
}
addClick('.e #foo', 1);
addClick('.f #foo', 10);
body { font-size: x-large; font-weight: bold; }
.a #foo { color: red; }
.b #foo { color: green; }
div:nth-child(3) #foo { color: blue; }
#foo { color: purple }
<div class="a"><span id="foo">a</span></div>
<div class="b"><span id="foo">b</span></div>
<div><span id="foo">c</span></div>
<span id="foo">d</span>
<div class="e"><button type="button" id="foo">+1</button>: <span>0</span></div>
<div class="f"><button type="button" id="foo">+10</button>: <span>0</span></div>

Где важно, что идентификатор уникален

  • <a>Теги могут ссылаться на идентификаторы, как в <a href="#foo">. Щелчок по нему переместит документ к первому элементу с id="foo". Точно так же хэш-тег в URL-адресе, который фактически является той же функцией.

  • <label>Теги имеют forатрибут, который указывает, какой элемент они маркируют по идентификатору. Щелчок по метке щелкает / активирует / дает фокус соответствующему элементу. Метка повлияет только на первый элемент с совпадающим идентификатором

В противном случае idэто просто еще один инструмент в вашем наборе инструментов.

gman
источник
Интересный ответ, спасибо! Я наблюдал сгенерированные дублированные идентификаторы в каком-то стороннем коде (я забыл, что это было сейчас), и хотя я знал, что это будет работать в большинстве браузеров, мне было любопытно, есть ли какие-либо серьезные последствия / недостатки, и было ли это на самом деле действителен, поскольку в то время я считал, что он недействителен (и он все еще недействителен, но оказывается, что большинство клиентов снисходительны).
omninonsense
Я бы сказал, что спецификация недействительна. Учитывая, что некоторые из крупнейших сайтов на планете используют эту функцию, спецификация должна измениться, чтобы отражать то, что на самом деле делают браузеры.
gman
0

Возможно ли, чтобы в классе было более одного ученика с одинаковым номером Roll / Id? В HTML idатрибут вроде так. Вы можете использовать для них один и тот же класс. например:

<div class="a b c"></div>
<div class="a b c d"></div>

И так далее.

кодпарадокс
источник
-1

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

<div class="a" /><div class="a b" /><span class="a" />

div.a {font: ...;}
/* or just: */
.a {prop: value;}
Phihag
источник
-1

Я думаю, вы не можете этого сделать, потому что Id уникален, вы должны использовать его для одного элемента. Вы можете использовать класс для этой цели

Джанарави
источник
-1

Мы можем использовать имя класса вместо идентификатора. html id должен быть уникальным, а классы - нет. при извлечении данных с использованием имени класса можно уменьшить количество строк кода в ваших файлах js.

$(document).ready(function ()
{
    $(".class_name").click(function ()
    {
        //code
    });
});

Малит Илеперума
источник