为什么在CSS中不建议使用ID选择器?

28

CSS Lint 中,他们不建议使用 id 来选择元素。我相信 CSS Lint,因为它是由非常了解 CSS 的聪明人编写的。但我想知道这背后的原因是什么?为什么使用 id 选择器不是一个好的选择?

6个回答

30

我不同意从不使用ID选择元素的想法,但我理解其中的推理。

通常情况下,开发人员会在一般形式足够的情况下使用具有非常高特异性的选择器:

#foo #bar #baz .something a {
    text-decoration: underline;
}

可能更好地写成

.something a {
     text-decoration: underline;
}

此外,像下面这样的写作风格:

#foo-1,
#foo-2,
#foo-3,
#foo-4 {
    color: #F00;
}

最好这样写:

.foo {
    color: #F00;
}

我在与CSSLint的不同之处在于,我重复使用结构性ID。

我常常使用以下的结构标记网页:

<div id="page">
    <div id="page-inner">
        <header id="header">
            <div id="header-inner"></div>
        </header>
        <nav id="nav">
            <div id="nav-inner"></div>
        </nav>
        <div id="wrapper">
            <div id="wrapper-inner">
                <div id="content">
                    <div id="content-inner">
                        <article></article>
                        ...
                    </div>
                </div>
                <div id="sidebar">
                    <div id="sidebar-inner">
                        <div class="module"></div>
                        ...
                    </div>
                </div>
            </div>
        </div>
        <footer id="footer">
            <div id="footer-inner"></div>
        </footer>
    </div>
</div>
而且因为我知道结构是一致的,所以在我的 CSS 中使用#page#header#nav#wrapper#content#sidebar#footer 来扫描特定区域的样式是无妨的。这些样式与此特定结构紧密地耦合,这使它们不太可重用;因为我重复使用结构,它们就是可重用的。需要记住的重点是,在选择器中使用 ID 是非常具体的,应该谨慎使用。
关于 优先级 的几句话:
通常来说,应该使用最低优先级的选择器来正确地选择:
如果你针对所有的<a>元素,请使用a
如果你针对<div class="foo">内的所有<a>元素,请使用.foo a
如果你针对<div id="bar">内的所有<a>元素,则使用#bar a是有意义的。然而,你也可以使用更低优先级的选择器。 [id="bar"] a.foo a 具有相同的优先级,这意味着你仍然可以通过 ID 针对特定元素进行选择,而不会创建具有不必要高优先级的选择器。
通常不建议使用[id="XXXX"]选择器来基于[id]属性选择,因为它很啰嗦并且可能会导致混淆。我建议使用[data-id="XXXX"]选择器来基于自定义的[data-*]属性选择样式,以更紧密地关联样式与 DOM 节点的当前状态。

29

CSSLint提供了为什么推荐使用类而不是id选择器的指南:

不应在选择器中使用ID,因为这些规则与HTML紧密耦合且无法重用。更好的做法是在选择器中使用类,并将类应用于页面上的元素。此外,ID会影响您的特异性并可能导致特异性冲突。

(来自禁止在选择器中使用ID的文档。)

基本上,如果你将代码结构化为使用类而不是ID,则你的代码可以变得更加通用和可重用,这通常是一件好事。此外,特异性是一个难以理解的问题,可能会导致难以找到的错误,如果省略ID选择器,则较少出现意外解析冲突的情况。


4
似乎这是用户偏好。我认为这取决于你要设计的内容,也许有人会在页面格式化div上使用相同的通用ID。 - Nick Rolando
12
CSS Lint 是胡说八道。 - Erik Reppen
有没有可能将可重用和特定的样式分别放在不同的样式表中?例如,特定的样式将驻留在site.css中,而通用的样式将在styles.css中。 - randacun
如果适合你的网站,就去试试吧。CSS Lint和类似的网站提供了有趣的最佳实践,但它们的实现通常需要一点点调整! - lonesomeday
我不喜欢完全不同意,特别是在开发自包含组件时。 - aemonge
显示剩余2条评论

23

首先:

CSS Lint和JS Lint一样,是一种伪装成验证的观点,而不是权威。

我在这个领域已经工作了五年。我曾在大型零售网站、互动代理机构以及作为独立承包商工作,并目前在一家SaaS公司工作。

我认为,ID无可非议地是坏的想法,只有当你处理团队时的CSS-fu并不好时,你才会得出这个想法。

在我看来,良好、灵活的CSS应该遵循以下 一般 的最佳实践:

  • 始终从一般到特定。例如,对于通用正文文本的字体系列和最常见的字体大小,应该只在一个地方声明。随着您上升到更典型地涉及类使用的选择器,您将开始覆盖字体大小。当需要将一个基本不使用的字体系列应用于非常特定的HTML子集时,使用ID命中获取正文文本变化的元素就有意义了。

  • 属性越普遍应用,越容易被覆盖,您永远不应该担心意外覆盖最常用的属性。例如,body#some_id div,由于这个原因是一个非常糟糕的选择器。在第二层(大概有三层),您通常处理与类容器相关联的通常重复使用元素的捆绑包时,意外发生更频繁,这时覆盖这些属性应该会更难一些。在最后一层,您不应该使用可重用元素,而是针对文档高度特定部分的覆盖。在这种情况下,使用ID是一种理想的做法,而不是坏做法,但是应该节制地使用ID,并且只为项目容器中的元素的具体属性需要更改的ID使用。

  • 选择器越具体,就越难被意外破坏。 具体而言,并不仅指元素上的ID。我指的是一个带有ID的容器元素,它靠近你实际目标的元素。然而,有意覆盖属性应始终涉及最小努力,这就是ID实际上有所帮助而不是阻碍的地方(见下面的例子)。如果你发现自己处于“用完所有ID、类和标签”的位置,我建议你采取暴力行为(至少是想象中的暴力行为)。但是认真地说,有人应该受到打击。

  • 避免过长的选择器列表: 在声明中定期使用4个或更多选择器值时,您应该开始感觉像是“做错了”。当计算时,我不会将 > 视为标记/值,因为明智地使用它对于可维护性和性能都是一种卓越的实践。

  • 避免具体性军备竞赛: 你知道那个人。这位“不要动我的东西”新手认为,用身体开始使用每个标记、选择器和ID是遮住他的屁股的最好方式。不要雇用那个人或者打他直到他停下来。但是,即使在更具前瞻性的团队中,如果你不在需要时在合适的位置上(谨慎地)增加选择器权重,军备竞赛仍然可以开始。

  • 特别是极简主义的方法非常重要。您越依靠HTML布局来避免需要CSS,就越好。您在全局分发最通用的样式方面做得越好,就越不必担心在更具体的情境中会出现什么问题。高度具体的属性覆盖越精准,长期管理起来就越容易。这就是我认为全局禁止使用ID的政策愚蠢的原因。

    哪种覆盖更实用和简单?

    这个:

    body .main-content .side-bar .sub-nav > ul > li > button

    还是这个?

    #sub-nav button

    如果你通常是一个独处的工作人员,或者只做一些小项目,以保持表面上在从事Web开发的同时赚取真正的利润,那么对于你来说,上述建议可能看起来有些傻和不可行。但是,当你与团队合作,并遵循仅使用类之类的策略时,最近由于未使用足够高的特异性而导致的问题,很容易开始为你的内容添加越来越多的类和标签(仅为了避免在短时间内出现问题,当然后来你会改回来),这将导致CSS文件中出现巨大的、不可预测的混乱。

    因此:尽量不要使用多个ID,仅用于容器本身局部的属性,而且不包含其他容器。尽量不要使用超过一个或两个类。避免针对高层元素(它们所代表的容器往往是许多祖先节点之上)的类和ID。除非进行维护或培训/惩罚新手,否则大多数情况下超过3-4个标记可能太多了。遵循童子军规则。在安全时随时清除那些重要的和明显过于具体的选择器。

    但是,请坚持经验法则而不是CSS“规律”,并确保在实践中评估这些想法。不要相信任何人或任何工具发表像“永远不要使用ID”这样的笼统陈述,因为CSS布局方案有很多变量。就我而言,这只是新手才会干的事情,作者如果想要声称自己是专家,那么应该懂得更好的做法。


    2
    是的,是的,是的,是的和是的。我错过了一个“是”吗? - BoltClock
    3
    无论如何,你都不应该有像body .main-content .side-bar .sub-nav > ul > li > button这样的规则。通过将适用深度保持在2级,不使用ID或元素进行样式设置,可以避免具有极高特定性的选择器争夺问题。有例外吗?是的。但如果你真正组织好你的选择器,就不会出现这种垃圾选择器。 - Scott Silvi
    我想点赞这个答案,并且我同意其中很多观点。它可以归结为“了解CSS特异性并正确使用它”。不过,我大多数时候还是和@ScottSilvi保持一致 - 通过像他提到的标准,几乎没有地方需要使用ID或超级具体的类/元素结构来编写良好的CSS。ID就像特异性的棒球棒,它们只会猛击事物,并且通常会导致比必要更高的特异性。 - LocalPCGuy
    1
    IDs是每个钉子的棒球棒还是类是锤子?当具体性带来困扰时,通常是因为有人用锤子打棒球或用棒球棒钉钉子。ID可以帮助您编写更少的CSS和CSS钩子,让试图理解您的布局的人减少查看和查找的地方。在我看来,99%的时间没有Twitter对我们施加的混合组件方案或CSS仇恨罪的价值高。 - Erik Reppen
    1
    人们总是谈论ID,比如标签可能是#second_div#a_tag_named_kevin。那么#overlay_container呢?当您将其作为类看待时,您是否确定它可能是每个页面上唯一的弹出式容器,可以在Web应用程序的每个页面上交换内容?哪种方法更具语义,并为我提供有关该元素在布局中可能扮演的角色的更多信息?如果我想要更改大型应用程序中的#overlay_container > .standard_headline与类版本之间的区别,我可以获得多少关于意图和布局影响范围的确定性? - Erik Reppen
    显示剩余2条评论

    4
    他们的观点在lonesomeday的回答中提到,即它将CSS紧密耦合到HTML中,不允许重用。
    我可以提出一个论点,即有些情况下,您不希望样式被除单个元素外的任何其他内容使用,因此在id选择器上指定它是有意义的。
    这都将取决于个人喜好。这不是您必须遵循的硬性规定,它似乎是CSS Lint团队的思考方式,而不是导致错误或其他任何问题的规则。

    3
    当你管理大量CSS或大型网站时,一个大问题出现了。ID根据定义是不可重用的。但是,当你涉及到特定性时,你也会遇到问题。当你开始更改特异性时,你会遇到恶性竞赛条件,样式变得难以处理。IDs具有比类更高的特异性,而内联样式具有比IDs更高的特异性。内联样式比外部样式表具有更高的特异性。通过使用类,你可以标准化如何应用样式到元素上,使事情更可预测。这倾向于简化开发,尤其是在与多个人合作时。

    6
    专一性是一种工具,而不是敌人。选择器膨胀才是敌人。 - Erik Reppen
    @ErikReppen 这个问题是为什么不推荐在CSS选择器中使用ID,我的论点是它们不能被重复使用,并且往往会创建难以管理的竞争条件。特异性不是一种工具,而是CSS的工作原理。选择器膨胀是一件坏事。它使CSS难以管理并减缓浏览器渲染速度。特异性是我认为ID通常不是好的CSS选择器的原因,而选择器膨胀则超出了此问题的范围。 - hradac
    1
    在任何具有多个布局的网站上,ID都是可重复使用的。布局通常具有仅在每页中使用一次的共同元素,例如模态对话框或全局导航。在需要覆盖由类设置的属性时,毫无理由地不使用这些容器的唯一属性来识别它们。良好且适度地使用ID将减少臃肿。在我看来,关键是不要不必要地增加元素的特异性权重,并管理拥有独特标记、类、ID之一的数量级,以此来帮助保持选择器的数量。 - Erik Reppen
    @ErikReppen 首先你说ID是可重复使用的,然后又说有些元素每个页面只使用一次。如果元素只使用一次,它们就是唯一的,根据定义不可重复使用。我并没有建议不使用ID,我只是提出了CSSLint可能不喜欢它们的可能原因。我也没有建议使用更高的特异性,那会导致灾难。至于ID减少膨胀的问题,我看过的演示文稿表明,设计良好的类可以减少膨胀。我参考的是Nichole Sullivan关于OOCSS的演示文稿。 - hradac
    特定性确实很有用,但过度的特定性会导致重复。当您开始将CSS绑定到ID时,HTML和CSS之间变得紧密耦合。它使CSS标记远离意图驱动的标记,并且从可维护性和关注点分离的角度来看,在大多数情况下并没有明显的优势,甚至不如在样式属性中嵌入CSS。像所有事物一样,也有例外,但由于基于ID的CSS只能针对单个元素,所以这种情况很少见。 - MightyE
    1
    @hradac 我的意思是在应用程序中可重复使用的组件,这些组件将在各种布局中被唯一使用。您可以将CSS应用于组件或图层。我建议根据需要同时使用两者。如果您完全使用图层,那么很难阅读/维护。如果您完全使用组件,则会在各个地方重复使用,使重新设计网站变得更加困难/混乱。ID是图层的一部分。仅在特定上下文中覆盖,而不是挂载整个属性集。 - Erik Reppen

    0

    组件:如果您编写可重复使用的组件,例如带有 ID 的表格(例如 <div id="data">),那么如果您将两个表格放入同一文档中,则会得到 INVALID HTML。


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