级联是 CSS 的一个如此重要的组成部分,以至于他们直接将其包含在名称中。如果您曾经需要使用 !important
来影响级联中的特性,您就会知道这可能是 一件棘手的事情。在 CSS 的早期,看到像这样的高度特性的选择器是很常见的
#sidebar ul li {}
如今,我们都擅长管理特性。将特性保持在较低和扁平化的水平是公认的最佳实践——避开 ID 选择器,大量使用类,并避免不必要的嵌套。但是,仍然有许多情况需要使用更特性的选择器。随着新提议的伪类的引入、对影子 DOM 的更多支持以及 all
属性的使用,我们将很快能够以新的和令人兴奋的方式处理继承和特性。
:is()
伪类
Lea Verou 最近提出了这个专门设计用于控制特性的新伪类。它已经进入了 CSS 第 4 级选择器规范。Lea 有 一篇关于它为什么有用的文章,并且在 CSS-Tricks 年鉴中 有一些关于它的报道。
让我们以 :not
为例。:not
的特性等于其参数的特性。这使得使用 :not
非常痛苦。以下就是一个例子
我们可能会预期 .red
类具有更高的特性,因为它在级联中处于较低位置。但是,对于任何样式要覆盖 div:not(.foobar)
,它们至少需要匹配组合元素选择器(div
)和类选择器(.foobar
)的特性。另一种方法是 div.red
,但有一种更好的方法。这就是 :is
可以提供帮助的地方。
div:is(:not(.foobar)) {
background-color: black;
}
:not
选择器不再添加任何特性,因此上述选择器的总特性只是单个元素选择器(div
)的特性。.red
类现在能够在级联中覆盖它。一旦实现,特性技巧 将成为过去。
影子 DOM
如今,许多人正在 HTML 中使用这样的类
<form class="site-search site-search--full">
<input type="text" class="site-search__field">
<button type="Submit" class="site-search__button">search</button>
</form>
使用 影子 DOM 时,而不是遵循冗长的命名约定,我们将能够完全省略类。在影子 DOM 中定义的样式被限定为仅在组件内应用。可以使用简单的元素选择器来实现样式,而无需担心选择器是否会干扰页面上的其他元素。
编写如此简单的 CSS 是令人解放的。无需再花费精力命名事物。影子 DOM 看起来终于要全面支持浏览器了。它很可能会进入 Firefox 的 下一个版本,而 Edge 则将其实现为 高优先级。
这些浏览器支持数据来自 Caniuse,其中有更多详细信息。数字表示浏览器在该版本及其更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
53 | 63 | 否 | 79 | 10 |
移动设备/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 11.0-11.2 |
all
属性
all
属性是一种一次设置所有 CSS 属性的方法——从 align-content
到 z-index
的所有属性。它接受什么值?我想不出任何情况下我希望所有属性都 inherit
,但这是一个选项。然后是 initial
,它更像是应用 CSS 重置,其中所有样式都消失了。没有填充。没有边距。初始值根据属性设置,与应用它的元素无关。display
的初始值是 inline
,即使将其应用于 div。em
标签的 font-style
是 normal
,strong
标签的 font-weight
也是 normal
。链接文本将为黑色。您明白了。 (您可以在 MDN 上找到任何 CSS 属性的初始值。)这也许限制了它的用途,它会超越我们的预期,通过删除所有样式,无论上下文如何。
不幸的是,all
最有用的值也是实现最少的:revert
。它可以删除您作为开发人员应用的样式,同时保留默认的用户代理样式。我们都见过没有样式表的 HTML 页面——白色(透明)背景上的黑色 Times New Roman,带有蓝色的带下划线的链接。如果您真的想避免继承,那么 all: revert
可以帮您解决。所有 div 都将为 display: block
,span 将为 inline
。所有 em
标签都将为斜体,strong
标签都将为粗体。链接将为蓝色,并带下划线。
这些浏览器支持数据来自 Caniuse,其中有更多详细信息。数字表示浏览器在该版本及其更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
84 | 67 | 否 | 84 | 9.1 |
移动设备/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 9.3 |
未来?
CSS-in-JS 是一种求助的呼声。我们 @csswg 应该关注这个问题,并在情况恶化之前解决问题。https://#/lWQ4ct61ir
— Lea Verou (@LeaVerou) 2017年5月24日
各种各样的竞争性非标准化方法用于编写 CSS-in-JS 试图绕过这些问题。这种方法在过去几年中越来越流行。一些支持者认为,继承、级联和特性是该语言的基本设计缺陷。W3C 的 CSS 工作组正在通过提高 CSS 和原生 Web 平台的功能来应对。看到结果会很有趣……
我对影子 DOM 的理解是,创建影子根的唯一方法是通过客户端 JavaScript?因此,如果您的 JS 未加载,您将获得一个未设置样式的页面?如果是这样的话,这似乎是一个非常严重的缺陷。
绝对没错,这是一个非常重要的考虑因素。也许您有一些依赖于 JavaScript 的组件——它们存在的理由本身就依赖于 JavaScript。对于这些东西,影子 DOM 很棒。您肯定不会用影子 DOM 为页面上的每个元素设置样式——也许我应该更加清楚地说明这一点!
实际上,这个缺陷(JS 依赖性)可以在未来得到解决,因为正在讨论创建新的标签
shadowroot
→ https://github.com/whatwg/dom/issues/510作为仍然使用诸如
#sidebar ul li {}
之类方法的人,有没有推荐的资源(或一系列资源)专门介绍现代 CSS 继承和最佳实践?我倾向于处理小型项目,其中我是唯一的开发人员,所以我使用对我有效的方法,但我一直希望通过编写“好的”CSS 来提高水平。谢谢。嗨 Brad。我的主要建议:不要费心去关注像 BEM 这样的命名约定,或者像 OOCSS 这样的听起来很花哨的东西,无论它们看起来多么流行。也不要担心 Sass。只要确保您了解特性的工作原理。关于“CSS 架构”的讨论大多是无事生非(而且没有明确的最佳方法),但如果您真的想阅读一些内容
https://adamwathan.me/css-utility-classes-and-separation-of-concerns
https://www.smashingmagazine.com/2016/11/css-inheritance-cascade-global-scope-new-old-worst-best-friends/
http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
https://csswizardry.com/2012/05/keep-your-css-selectors-short/
主要建议:尽可能降低特性,大量使用类,不要为 CSS 使用 ID。
因此,该示例可以为
.sidebar li {} (如果需要,这更容易在以后被覆盖,而无需使用 !important)
在团队合作或接手其他团队完成的工作时,特异性非常重要。理解特异性至关重要,我并不主张盲目使用任何新奇的命名约定。然而,如果你深入学习 ITCSS BEM(也称为 BEMIT)和 CSS 命名空间,它将彻底改变你编写 CSS 的方式,使其变得更好。我最初非常反对 BEM,但现在我已经完全转变为它的支持者,因为我亲眼看到了特异性问题是如何在我们大型项目中造成困扰,而这些项目涉及各种技能水平的团队成员,他们需要共同完成长期工作。没有一个系统是完美的,ITCSS 和 BEM 当然也不例外,但它们比传统的 CSS 工作方式要好得多。
在大型项目中使用 CSS 将是一件愉快的事。关注像 Harry Roberts(CSSWIZARDRY)这样的专家。另外,你会遇到 OOCSS,这是一种在现实世界中行不通的无稽之谈,忘记它吧。OOCSS 教导我们要骨干 DRY,这会导致各种问题。适度 DRY 就足够了……运用常识。
:revert 目前似乎只被 Safari 支持。
对我来说,大多数内容都很有用,除了 Shadow DOM,因为它只会让我的代码变得更冗长。除此之外,我将继续在为 SVG 编写 CSS 时大量使用 id。我倾向于将 id 作为一种注释(例如,id 为“leaf”将引用 SVG 中唯一的叶子),它同时起着类名的作用。在这些情况下使用 id 的真正好处是,与实际的注释不同,id 在压缩过程中不会被移除,并且使用更少的字节,因为 id 是两个字母,而类名是五个字母。
另一方面,我的 HTML 倾向于更复杂,因此我避免使用 id,除非在绝对必要的情况下。
我不介意将旧的和新的混合使用,只要我知道我理解所有新的内容,以便在需要突然切换时能够做到。