如果它们是不同的元素,多个不同的HTML元素可以具有相同的ID吗?

177

不同的HTML元素能否使用相同的ID?如果它们是不同类型的元素,这种情况是否有效?例如:

div#foo
span#foo
a#foo

33
有时可能是可行的,但从未是有效的。 - Paul Creasey
4
以上所述值得注意的是,在由用户代理创建的内容文档中(比如框架,MV*,React,Polymer等),很可能会遇到多个相同的ID。这就是为什么看起来非常专业的XYZ网站却充满了这种“不良实践”编码的原因,如果有人感到疑惑的话。 - Lukasz Matysiak
@PaulCreasey的评论是回答这个问题的好方法。问题的标题和正文不匹配;它们各自都是合理的是或否问题,但具有不同的正确答案 - 这可能会让那些不注意的人犯错。关于如何解决这种问题不匹配的元问题,目前还没有答案:https://meta.stackoverflow.com/questions/256732 - Richard Abey-Nesbit
嗨@Tidorith!感谢您的评论。如果您有任何想法,我很乐意听取关于更改标题或正文的建议。最初的问题是出于好奇而提出的。某些代码生成工具(我认为可能是一些微软UI库)正在生成具有相同ID的元素。我尝试阅读规范并在浏览器中进行测试,但由于浏览器似乎允许它,而规范则表示不允许,因此感到困惑。 - omninonsense
@Tidorith稍微修改了问题的主体,希望现在更好了! - omninonsense
17个回答

212

不可以。

元素ID应在整个文档中是唯一的。


119
不这样做会有什么后果? - corsiKa
20
@corsiKa,这个后果是未定义行为,例如,当存在多个#foos时,document.getElementById("#foo")或$("#foo")会返回什么?您将遇到问题,在JS中无法使用这些元素,将它们作为选择器传递给库/API/Flash等等。 - mrooney
24
为什么在有class的情况下还要使用多个类似的ID呢? - Max Yari
10
实际上,使用类可以替代多个ID。然而,类是用于应用样式,而不是标识元素,因此名称范围更广,很可能会重叠,尤其是在使用第三方库时。 ID作为“标识符”并不打算进行复制,因此需要介于两者之间的东西。 实际应用是将页面/ DOM 的部分组件化为单独的逻辑单元。因此,至少需要使用2层标识。 - Alen Siljak
3
不一定要回答“这是否有效”这个问题的答案与“我需要吗?”、“我希望这是有效的吗?”甚至“这种糟糕的解决方案在规范的当前实现中是否可行?”这些问题的答案相匹配。 - Spyryto
显示剩余21条评论

112

多个元素可以有相同的ID吗?

可以 - 无论它们是否是相同的标记,浏览器都会呈现页面,即使多个元素具有相同的ID。

这是有效的HTML吗?

不是。这在2023年5月更新HTML活动标准中仍然是真实的。但是,getElementById的规范(截至2023年)也说明了它必须返回给定ID的第一个元素,使得在无效文档的情况下行为得到定义。

这种无效的HTML有什么后果?

大多数浏览器不会显示任何指示,而且大多数用户不会在意你的HTML以这种方式“无效”。当调用getElementById时,大多数(如果不是全部)浏览器会选择具有给定ID的第一个元素。一些查找元素的库继承了这种行为,而其他库(正如gman在他的答案中指出的那样)将使用更明确的querySelectorquerySelectorAll方法,分别明确地选择匹配的第一个或所有元素。大多数(如果不是全部)浏览器还会将由id选择器(例如#myid)分配的样式应用于所有具有指定ID的元素。如果这是您期望并打算的,那么就没有意外后果。如果您期望/打算其他事情(例如通过getElementById返回具有该ID的所有元素,或者使样式仅适用于一个元素),则您的期望将无法实现,并且依赖于这些期望的任何功能都将失败。

一些 JavaScript 库 确实 期望元素的 ID 不重复(参见 wootscootinboogie 的评论 关于 d3.js)

结论

最好遵循标准,但如果您知道您的代码在当前环境中按预期工作,并且这些 ID 以可预测/可维护的方式使用,则我只能想到两个实际的原因不这样做:

  1. 为了避免您错了,而您使用的库之一实际上在多个元素具有相同 ID 时出现故障。
  2. 为了保持您的网站/应用程序与将来可能遇到的库或服务(或开发人员!)的向前兼容性,当多个元素具有相同 ID 时会出现故障 - 这是一个合理的可能性,因为这不是有效的 HTML。

力量掌握在你手中!


你链接的规范似乎并没有说文档中的ID需要是唯一的,只需要在该元素树中唯一即可。 - gman
@gman 这是真的 - 但据我所知,一个文档在给定时间只能有一个节点树。当然,如果你处理多个文档或多个未连接到文档的节点树,则它们可以各自拥有相同ID的副本而不会无效。这似乎是一种玄学技术细节。但总体上,这种情况的有效条件比一般情况下要略微玄学,因为大多数现代库都没有问题处理重复的ID ;) - mltsy
作为一个考虑,在欢乐的2023年,如果你查看Google/YouTube的HTML代码,你会发现它们对每个视频都使用相同的id标识符。如果这是为了通过从class中减少3个字符来节省带宽,那么这与其他一英里长的自定义标签完全相悖,所以我怀疑这不是他们的理由。我无法猜测他们为什么这样做,但他们确实这样做了。 - Exit

100

我认为,某些内容“应该独一无二”和“必须独一无二”是有区别的(即由Web浏览器强制执行)。

ID是否应该是唯一的? 是的。

ID是否必须是唯一的? 不需要,至少IE和FireFox允许多个元素具有相同的ID。


7
在这条评论发布时(指2012年左右),Chrome浏览器(版本为v22)也具备了这个功能。 :D - omninonsense
38
根据规范,这是一个必须遵守的要求,而不是建议。虽然大多数浏览器仍能正常工作,但它不符合有效的HTML标准。对于getElementById,在这种情况下的结果为undefined,意味着无法确定浏览器如何处理它。 - leo
3
@leo 不过,这是现实世界,在这个世界里,浏览器并不完全符合标准。在这种情况下,这可能是一件好事,因为没有理由要求使用唯一的ID。 - BJury
6
在HTML5中,getElementById的规范实际上确实定义了必须返回具有给定ID的第一个元素(这也是所有浏览器目前处理此情况的方式)-有关更多信息,请参见我下面的答案。 - mltsy
1
如果您不按照规范编写HTML,则一切都可能出错。浏览器和/或任何JS库都可以合法地崩溃,这是您的责任,而不是他们的责任。 - Liam

27

即使这些元素类型不同,也可能会给你带来严重的问题...

假设您有3个具有相同ID的按钮:

<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设置的单击事件处理程序。不幸的是,这不会发生。只有第一个按钮调用单击处理程序。当点击其他两个按钮时,它们不会产生任何作用。好像它们根本就不是按钮一样!因此,始终为HTML元素分配不同的ID。这将防止出现奇怪的事情。 :)
<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...
        interestingFunction();

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

如果我有一个已经在变量中引用的“#content”,以及一个只在几个瞬间内拥有的“#my-div #content”,之后我删除了被引用的节点并忘记了它的变量,此后“#div #content”执行myDiv.outerHTML = myDiv.innerHTML来替换原始内容。这样可以避免将“#content”的所有样式和内容硬复制到“#decoy”中并执行相同操作的需要。在进行转换时,这是有意义的。 - Dmytro
这意味着,即使我使用'append'添加多个相同id的元素,DOM仅认为第一个元素是真实的,理想情况下1个ID = 1个元素。 - Karan Kaw

24

不可以有两个具有相同id的元素。id是唯一的,如果您希望做这样的事情,请使用class。不要忘记使用空格作为分隔符,元素可以具有多个类:

<div class="myclass sexy"></div>

20

希望能给您提供实用的答案。

我们去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))

并查看所有重复的id。

在这里输入图片描述

将上述代码更改为显示重复超过10次的id,以下是它生成的列表

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

其他使用相同id的网站包括Amazon.com、ebay.com、expedia.com和cnn.com。

显然,ids只是元素上的另一个元数据。

getElementById已经过时了。您可以使用querySelectorAll选择所有元素或querySelector选择第一个元素,而不管选择器如何。因此,如果您想要具有id 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.

我们可以使用选择器来查找具有相同id的不同元素。

function addClick(selector, add) {
  document.querySelector(selector).addEventListener('click', function() {
    const e = this.parentElement.querySelector('#value');
    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 id="value">0</span></div>
<div class="f"><button type="button" id="foo">+10</button>: <span id="value">0</span></div>

id唯一性的重要性

  • <a>标签可以引用id,例如<a href="#foo">。点击它将跳转到文档中第一个具有id="foo"的元素。同样,URL中的哈希标记也具有相同的功能。

  • <label>标签具有一个for属性,指定它们通过id标识的元素。点击标签将点击/激活/聚焦于相应的元素。标签只会影响第一个具有匹配id的元素

label { user-select: none; }
<p>nested for checking</p>
<form>
  <div><input type="checkbox" id="foo"><label for="foo">foo</label></div>
</form>
<form>
  <div><input type="checkbox" id="foo"><label for="foo">foo (clicking here will check first checkbox)</label></div>
</form>

否则,id 只是你工具箱中的另一种工具。

1
有趣的回答,谢谢!我曾经在某些第三方代码中观察到生成了重复的ID,虽然我知道它在大多数浏览器中可以工作,但我很好奇是否存在任何严重的影响/缺陷,并且它是否实际上是有效的,因为当时我认为它无效(现在仍然无效),但事实证明大多数客户都很宽容。 - omninonsense
我认为规范是无效的。考虑到一些全球最大的网站正在使用该功能,规范应该改变以反映浏览器实际执行的操作。 - gman

14
HTML官方规范规定id标签必须是唯一的并且官方规范还规定,如果可以完成渲染,则必须这样做(即在HTML中不存在“错误”,只有“无效的”HTML)。因此,以下是id标签实际工作的方式。它们都是无效的,但仍然可以正常工作:

这个:

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

在所有浏览器中都可以正常渲染。然而,document.getElementById只返回一个对象,而不是一个数组;你只能通过id标签选择第一个div。如果你使用JavaScript更改了第一个div的id,则第二个ID将可用于document.getElementById(在Chrome、FireFox和IE11上测试通过)。你仍然可以使用其他选择方法选择该div,并且其id属性将被正确返回。

请注意,上述问题为呈现SVG图像的网站打开了潜在的安全漏洞,因为SVG允许包含DOM元素以及它们的id标签(允许通过上传的图像进行脚本DOM重定向)。只要SVG在要替换的元素之前在DOM中定位,图像将接收所有JavaScript事件。

据我所知,目前没有人关注这个问题,但它是真实存在的。

这个:

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

在所有浏览器中都能正确渲染。但是,只有以这种方式定义的第一个id才会被使用。例如,在上面的示例中尝试document.getElementById('unique-also');,你将得到null(在Chrome、FireFox和IE11上测试过)。

这样:

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

在所有浏览器中都能正常渲染,但与可以用空格分隔的类标签不同,id标签允许有空格,因此上述元素的id实际上是"unique unique-two",如果在DOM中单独查找"unique"或"unique-two",除非在DOM的其他位置已定义,否则返回null(在Chrome、FireFox和IE11上测试过)。


1
"id" 标签允许包含空格 - 尽管根据 规范 ,“值不能包含任何空格字符。” - MrWhite
我同意。然而,有规范,也有浏览器的操作方式。历史上,浏览器将规范视为目标,但在许多项目上并不严格。我认为他们这样做是因为如果他们符合规范,会破坏很多现有的网站或其他原因。我在顶部提到,尽管这些东西可以工作,但它们是无效的。 - Nick Steele

6

值得一提的是,在Chrome 26.0.1410.65、Firefox 19.0.2和Safari 6.0.3等浏览器中,如果您有多个具有相同ID的元素,则jquery选择器(至少)将返回具有该ID的第一个元素。

例如:

<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
可能这个答案是正确的,我是从经验中说出来的。 - Dibyanshu Jaiswal

6

SLaks的答案是正确的,但需要补充说明的是,x/html规范规定所有id必须在单个html文档中是唯一的。尽管这不完全符合提问者的问题,但有些情况下同一个id可能会附加到多个页面上的不同实体。

例如:

(针对现代浏览器) article#main-content {以一种方式设置样式}
(针对旧版) div#main-content {以另一种方式设置样式}

虽然这可能是一个反模式,但我将其放在这里作为一个争议点。


1
好观点。虽然应该插入到另一页中的动态生成内容应该完全避免使用id。在编程语言中,ids就像全局变量一样,你可以使用它们,并且有一些有效的情况下,这是一个不错的技巧,可以简化事情。在进行黑客之前,考虑正确地做事是一个不错的实践。 - psycho brm

5

好的,使用 w3.org 的 HTML 验证器(专门针对 HTML5),ID 必须是唯一的

请考虑以下内容...

<!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>

...但是原帖明确提到了不同的元素类型,所以考虑以下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

结论:

无论是相同的元素类型还是不同的元素类型,如果id被使用了多次,则不符合HTML5的规范。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接