2023 年开始写 CSS 会与众不同(Part1)

CSS 的发展速度比以往任何时候都要快。在 Flexbox 和 Grid (https://s.juejin.cn/ds/i8TmVYNt/)之后,CSS 的发展似乎经历了一段漫长的停滞期,但在近几年,CSS 已经新增了许多新功能可用(https://s.juejin.cn/ds/i8Tmg379/),而且还会有更多新功能即将推出。这个发展速度是令人兴奋的,同时也有些压倒性。

虽然 CSS 新增了很多新功能(https://s.juejin.cn/ds/i8Tmg379/),但很多 Web 开发者都认为这些花里胡哨的东西并没有给自己带来实质上的变化。换句话说,所有这些花里胡哨的东西(CSS 新特性)实际上改变了你编写 CSS 的方式吗?对于大多数 Web 开发者而言,CSS 的新特性确实影响了今天编写 CSS 的方式,但也许并没有像我预期的那样彻底。

虽然我看到很多博客文章以及我自己的小册《现代 CSS》(https://s.juejin.cn/ds/i8Tmg379/)中有关这些新潮事物的介绍和示例,但我还没有看到这些实际应用在生产或日常中使用。这并不是对任何人或任何事情的抱怨。就我个人而言,我对 CSS 的演进感到非常兴奋。许多最新的功能是我们多年来一直渴望的。确实,其中有一些功能正在逐渐融入我的 CSS 中。虽然不是彻底改变,但足以让我比以往更喜欢编写 CSS。

2023 年对 CSS 来说是重要的一年!

f5ceb774826204c25bdc0e027f71fd83.jpeg


从年初的 2023 Google I/O 大会(https://developer.chrome.com/blog/whats-new-css-ui-2023)到年底的 WWDC23 大会(https://developer.apple.com/videos/play/wwdc2023/10121/),还有 @Bramus 在乌得勒支@Frontmania 大会上的分享(https://www.bram.us/2023/10/13/whats-new-in-css-2022-10-12-frontmania/)以及最近 Chrome 团队分享的《CSS Wrapped: 2023!》(https://developer.chrome.com/blog/css-wrapped-2023)都在聊 CSS 的最新特性。我也不例外,我花了半年的时间专门以小册的形式在阐述 CSS 现代特性(https://s.juejin.cn/ds/i8Tmg379/)。很庆幸的是,我的小册所介绍的 CSS 最新特性(https://s.juejin.cn/ds/i8Tmg379/)基本上(达 95% 以上的特性)都在前面这些大会的主题上出现过。

6c5c67d0f202ae47f1a5e93d08852d57.png


小册地址:https://juejin.cn/book/7223230325122400288

可以说,零零总总有几十个 CSS 新特性得到了主流 Web 平台的支持,可以说 2023 年是 CSS 很重要的一年。这些进展使开发者们曾经认为在 Web 平台上不可能实现的功能成为现实。现在,主流的现代 Web 浏览器都支持 CSS 容器查询(尺寸查询(https://juejin.cn/book/7223230325122400288/section/7259668032165773368)、样式查询和状态查询(https://juejin.cn/book/7223230325122400288/section/7259316003635462201)等)、子网格(https://juejin.cn/book/7161370789680250917/section/7160657953932967967)(subgrid)、关系型选择器 :has() (https://juejin.cn/book/7223230325122400288/section/7224404685615005728)(也常被称为父选择器)、复杂的第 n-* 选择器,以及一系列新的颜色空间(https://juejin.cn/book/7223230325122400288/section/7233227753909125178)和函数(https://juejin.cn/book/7223230325122400288/section/7237288025221234744),例如 color()color-mix() 。Chrome 浏览器还支持仅用 CSS 实现的滚动驱动动画(https://juejin.cn/book/7223230325122400288/section/7259272255786450981),以及在 Web 视图之间平滑过渡的视图过渡效果(https://juejin.cn/book/7223230325122400288/section/7259669097242329145)(如果你对 Web 动画感兴趣,可以移步阅读《Web 动画之旅》(https://s.juejin.cn/ds/i8T4KsX7/))。最重要的是,有许多新的基础特性出现,例如 CSS图层(@layer)(https://juejin.cn/book/7223230325122400288/section/7259563116462080037)、 嵌套和作用域(https://juejin.cn/book/7223230325122400288/section/7259668111974989882)等,可以更好的提高Web 开发者编写 CSS 的体验,甚至是改变 Web 开发者编写、维护和管理 CSS 的方式。

d3d83849ce780ba09328f5e123f1b2b5.jpeg

很精彩的一年吧!看到这么多新特性,你是否有点迟疑了,CSS 有这么多新东西?甚至还有可能会令你感到困惑,这还是你认识的 CSS 吗?

91ee6c003c8272880206a037cbd2de98.png


试问一下,自己认识多少,又用过多少。更重要的是这些新特性有没有真正的给你自己带来变化!

放弃你的迟疑

通常情况之下,人面对新鲜事物的表现因个体差异有所不同,有的人可能表现为好奇、兴奋和积极,而有的人可能表现为恐惧和抵触。同样的,Web 开发者面对 CSS 的新特性时,也可能会表现出多种反应和行为,这些反应和行为取决于他们的技术水平、项目需求、个人偏好以及对新技术的接受程度。比如,有的同学会对 CSS 新特性感到好奇、兴奋(比如我),对于这部分同学而言,他们会立即行动起来,去学习和实践这些新特性,甚至还有同学会积极参与社区建设,使这些新特性更完善。当然,也有一部分同学会表现出抗拒、保守,甚至是排斥。而且在中国社区,这部分人占多数,因为我经会听到身边小伙伴对新特性感迟疑。这些花里胡哨的东西,能用吗?兼容性好吗?等等!

在这里,我想说的是,随着时间的推移,新特性会不断进化和改进。正如当年在推广 CSS3 特性的时候,被问得最多的是“新特性能兼容 IE 吗”?

现如今,我同样会被问类似的问题:“这些新特性兼容性如何?” 同时,会有很多同学问我,如何以及在哪里可以获得这些新特性?其实,这是一件好事,意味着有更多的同学在放弃对新特性的迟疑、恐惧和排斥等。

这已经是一种改变。

事实上,当下的环境对于 Web 开发者而言是友好的,我们可以通过不同的方式获得新特性的版本发布信息、兼容性数据、互操作性以及 Web 平台的提供的信息。

版本发布

b5db8fae5c06ff96a9a8866cbc0576c7.png

我们可以在 Chrome(https://chromestatus.com/roadmap)、Safari (https://developer.apple.com/documentation/safari-release-notes)和 Firefox(https://whattrainisitnow.com/calendar/) 等主流浏览器发版中获得各 Web 平台引入的新功能、错误修复等相关信息。

发布说明

5ee08c21a9646ab41f4bdad71e9dfccc.png

Web 平台(Chrome(https://developer.chrome.com/blog)、Safari (https://webkit.org/blog/)和 Firefox(https://www.mozilla.org/en-US/firefox/releases/))每一次发布新版本都会提供相应的文档,其中包含有关新功能、改进和问题修复的详细信息。Web 开发者可以通过阅读发布说明来了解相关的信息。同样的,我们在相应的文档中也能获得 CSS 相关的信息,包括最新功能、功能改进和问题修复等信息。

兼容性数据

26aeed7587ed86d2f4f55eee34d330e0.png

Web 开发对 CSS 新特性止步的关键因素还是跨平台的兼容性。如果你想了解某个新特性的兼容性相关数据,可以通过 Can I Use(https://caniuse.com/)、Browser Compat Data(https://github.com/mdn/browser-compat-data/) 和 Time to Stable (https://time-to-stable.deno.dev/)等平台上获取。

互操作性

Interop 是一项跨浏览器的努力,旨在提高 Web 的互操作性。互操作性指的是为改善 Web 技术在不同浏览器中的互操作性而进行的努力。互操作性是指确保在不同环境下(尤其是不同浏览器)使用相同的 Web 技术时,能够获得一致的行为和效果。简单地说,每种技术在所有浏览器中达到完全相同的状态。

Interop 是从 2021 年开始,现代浏览器都参与进来了,到目前已有 Interop2021(https://wpt.fyi/interop-2021)、Interop2022(https://wpt.fyi/interop-2022) 和 Interop2023(https://wpt.fyi/interop-2023):

98d85eeaf1782054fbc96f36db8dc760.png

从上图中,你就能发现 2023 年各 Web 平台对 CSS 付出的努力,这也是为什么 2023 年会有这么多 CSS 新特性得到主流 Web 浏览器的支持。

平台新闻

dff1cf2a32f0e9c00e10014ed48a07e3.png

在 web.dev 的博客中(https://web.dev/blog),你将获得每个月关于 Web 平台的最新消息。这可能包括有关Web 技术的更新、改进或变化的信息:

268c83c736808037fb5cd6dc1ffcc8b8.png

正如上图所示,它陈述了 2023 年 12 月份 Web 平台上的新功能。

Baseline

547f78532a8bb89e5d41067a225c05ab.png


在 2023年 Google I/O 大会上推出了基准(https://web.dev/baseline?hl=zh-cn),旨在明确说明网络平台功能是否可供使用。Baseline 的原始定义(https://web.dev/blog/baseline-definition-update)是,当所有主流浏览器(Chrome、Edge、Firefox 和 Safari)的现行版本和以往版本均支持这些功能时,这些功能已纳入 Baseline。

Baseline 即将登陆 caniuse.com(https://caniuse.com/)!这篇博文将介绍这项集成,并探索 2023 年 Baseline 中包含的一些功能。根据基准的新定义(https://web.dev/blog/baseline-definition-update?hl=zh-cn),功能生命周期分为两个阶段。第一个选项是新推出,然后在 30 个月后全面推出。如果某个功能在以下浏览器中可互操作,便会成为 Baseline 新提供的功能的一部分:

  • Safari(macOS 和 iOS)

  • Firefox(桌面版和 Android 版)

  • Chrome(桌面版和 Android 版)

  • Edge(桌面设备)

以后大家在 caniuse.com (https://caniuse.com/)查看兼容数据时,你会看到一个标志,告知你相应功能是否已在 Baseline 中广泛提供。换句话说,如果你看到这个标志,你就可以大胆的使用,不用再担心跨浏览器的兼容性问题。这也就解决你对 CSS 新特性最大的疑惑——兼不兼容:

6a71de3716df049bf4cfcce43d9d816a.jpeg

通过上面所述这些资源,你将获得 Web 平台的第一手信息,也你将获得 CSS 相关的最新信息。如果你对 CSS 感兴趣,或者说对 Web 平台相关技术感兴趣,那么请订阅它们,这样能确保你时刻获得跨平台的最新信息。有助于掌握更多的技能。

请留意接下来所介绍的 CSS 特性标题前的表情符,该表情符表示的是新 Baseline 徽章!具体详细性请猛击此处(https://web.dev/blog/baseline-definition-update?hl=zh-cn):

  • 💯:新增主要浏览器的所有稳定版 (放心使用)

  • 👁️:主要浏览器只支持部分功能(还得等一等)

架构基础

a7ace025b8148e194dad80e200e3af93.jpeg

让我们从 CSS 的核心功能开始。这些是对你如何编写和组织 CSS 具有基础性作用的特性,这些基础性特性解决了 CSS 中一直令 Web 开发者感到头痛的问题。可以说,这些特性将直接改变你编写、管理和维护 CSS 代码的姿势。

💯 级联层

b2644ca0da4f17625fb769e915132f46.png

级联层是 CSS 中最为重要的一个概念,很多 Web 开发者惧怕级联层,其中原因之一就是编写的 CSS 很容易造成冲突或者被覆盖。例如:

ul[class] { /* (0,1,1) */
    margin: 0; 
    padding: 0; 
    list-style-type: none;
} 

.nav { /* (0,1,0) */
    margin: 0 40px; /* 被 ul[class] 中的 margin 覆盖 */
}

为了决定哪个声明(CSS 样式规则)会“获胜”(从而被应用到元素上),级联提供了相应的算法。了解级联算法有助于帮助我们理解浏览器是如何解决样式规则冲突,也就是浏览器决定哪个样式规则运用到元素上。但需要知道的是,级联算法在不同的规范中有不同的描述,在 Level 5 中提供了六个不同的级别。在不考虑级联层的情况下,其标准如下:

f52f94ad9388de84354136b72c0a69fa.png

如上面示例,我们根据该标准需要提高 .nav 权重:

ul[class] { /* (0,1,1) */
    margin: 0; 
    padding: 0; 
    list-style-type: none;
} 

ul.nav { /* (0,1,1) */
    margin: 0 40px;
}

熟悉 CSS 的同学,应该知道这些标准的优先级从高到低排列,并且一个接一个地检查,直到确定一个获取的声明。如果在较高的标准上不能确定哪一个属性声明会获胜,级联将转到下一个标准。比如下图所示:

e048bed5e21de6ed0cd0d105b4d0ec9b.png

为了解决诸如此类的问题(级联与权重),CSS 新增了一个级联层的规则,即 @layer

简单地说:级联层提供了一种结构化的方式来组织和平衡单一来源中的 CSS 规则,最终决定谁获胜!。

由于 CSS 的级联层在 CSS 级联中有着独特的地位,使用它有一些好处,使开发者对级联有更多的控制。CSS 的级联层一般位于 “Style 属性”(Style Attribute)和 CSS 选择器权重(Specificity)之间,即:

87d23ebab47a5153f3504e23e746904a.png

有了 @layer 之后,我们可以像下面这样改造前面所展示的代码:

@layer reset, components;

@layer reset {
    ul[class] {
        margin: 0; 
        padding: 0; 
        list-style-type: none;
    } 
}

@layer components {
    .nav {
        margin: 0 40px;
    }
}

我使用下图来阐述有级联层 @layer 前后,CSS 级联的差异:

6cfea51765ddd1d8de99cd9e7af912ef.png

带来的直接变化是权重计算规则变了:

88c6603a57f14e39809339cbe02187fe.png


有了 CSS 级联层 @layer 特性之后,你可以抛弃以前的一些 CSS 方法论(例如 ITCSS),因为 @layer 能更好的帮助你管理 CSS 的级联。

简单地说,级联层 @layer 是 CSS 的一个新特性,它影响着样式规则的应用和优先级。以下是级联层的一些关键细节:

  • 添加到级联层:可以通过 @layer 规则将样式添加到指定的级联层中。这使得开发者能够更有序地组织样式。

  • 匿名级联层:如果未使用 @layer 规则,样式将被放入默认的匿名级联层。这样可以确保未指定级联层的样式不会影响到指定级联层的样式。

  • 预定义级联层顺序:级联层可以预定义一个顺序,确保在样式规则中未明确指定级联层的情况下,样式按照默认的预定义级联层顺序应用。

  • 加载外部 CSS 文件到级联层:可以通过 @layer 规则加载外部 CSS 文件到指定的级联层中,这样可以更灵活地组织和加载样式。

  • 无级联层样式:可以使用 @layer unlayered 规则将样式添加到无级联层的样式层,这样的样式在默认情况下不会被任何级联层继承。

  • 级联层嵌套:可以将一个级联层嵌套在另一个级联层中,以创建更复杂的样式层次结构。

  • 回滚级联层:可以通过 @layer 规则回滚到之前的级联层状态,以便撤销某些样式的更改。

级联层为开发者提供了更精细的样式管理和组织的能力,使得在大型项目中更容易维护和扩展样式。

有关于 CSS 级联层 @layer 特性更详细的介绍,请移步阅读《现代 CSS》(https://s.juejin.cn/ds/i8wsdWCn/)中的《CSS 分层:@layer 》(https://juejin.cn/book/7223230325122400288/section/7259563116462080037)课程!

💯 嵌套

c3c3e8a1fe284c490a0788189a781089.png

通常情况之下,Web 开发者如果不使用 CSS 处理器,例如 Sass(或 SCSS)、LESS 和 Stylus 等,每个 CSS 选择器都需要显式声明,彼此之间分开。例如:

table.colortable td {
    text-align: center;
} 

table.colortable td .c {
    text-transform: uppercase;
}
 
table.colortable td:first-child,
table.colortable td:first-child + td {
    border: 1px solid black;
}

table.colortable th {
    text-align: center;
    background: black;
    color: white;
}

这将使得样式代码重复、冗余和分散。正因此,很多 Web 开发者会基于 CSS 处理器特性上,使用嵌套的方式来编写 CSS 的选择器。例如,上面的代码用 SCSS 的嵌套语法编写的话,会像下面这样:

table.colortable {
    td {
        text-align: center;
        .c {
            text-transform: uppercase;
        }
        &:first-child {
            border: 1px solid black;
            + td {
                border: 1px solid black;
            }
        }
    }
    th {
        text-align: center;
        background: black;
        color: white;
    }
}

现在,CSS 也具备像 SCSS 相似的嵌套特性,可以将相关样式规则分组到选择器中,从而继续创建选择器。

table.colortable {
    & td {
        text-align: center;
        .c {
            text-transform: uppercase;
        }
        &:first-child,
        &:first-child + td {
            border: 1px solid black;
        }
    }
    & th { 
        text-align: center;
        background: black;
        color: white;
    } 
}

嵌套可以减少样式表的大小、减少重复选择器的开销,并集中组件样式。该语法最初发布时存在一个限制:“CSS 的任何选择器都可以嵌套到另一个选择器中,但它必须以 & . (类名)、# (ID)、@ @ 规则)、: :: \ + ~ >  [ 符号开头。” 这些符号是一些识别符号,它会向解析器发出信号,表示它正在使用嵌套样式。后来,通过嵌套宽松的语法更新,该限制已被解决,例如不需要在元素选择器之前添加 & 识别符:

table.colortable {
    td {
        text-align: center;
        .c {
            text-transform: uppercase;
        }
        &:first-child,
        &:first-child + td {
            border: 1px solid black;
        }
    }
    th { 
        text-align: center;
        background: black;
        color: white;
    } 
}

同样的,它也可以和 @ 规则相互嵌套,例如:

h1 {
    font-size: 2em;
    
    @media (width >= 40em) {
        & {
            font-size: 4em;
        }
    }
}

/* 宽松语法 */

h1 {
    font-size: 2em;
    
    @media (width >= 40em) {  
        font-size: 4em;
    }
}

有关于 CSS 嵌套特性更详细的介绍,请移步阅读《现代 CSS》(https://s.juejin.cn/ds/i8wsdWCn/)中的《CSS 的嵌套和作用域:& 和 @scope 》(https://juejin.cn/book/7223230325122400288/section/7259668111974989882)课程!

👁️ 作用域

9ef66e534c9da3237ee2979042ba5b01.png

众所周知,CSS 语言和其他程序语言不同,它是没有作用域的概念。通常情况之下,开发者需要通过 DOM 结构和选择器来达到类似作用域的功能。这使得 Web 开发者在编写选择器时,可能会发现自己在两个世界之间交替。一方面,Web 开发者需要明确具体选择哪些元素;另一方面,Web 开发者希望选择器保持晚于替换,而不是与 DOM 结构紧密耦合。这也是 tailwindcss (https://tailwindcss.com/)备受欢迎的原因之一。

为此,W3C 的 CSS 工作小组为 CSS 新增了作用域 @scope 特性,该特性首先得到了 Chrome (118版本)的支持。@scope 是一个 @ 规则,它主要有两个卖点:基于接近度的样式为选择器设置下限。换句话说,作用域给 CSS 带来了两个关键的东西:

  • 一组样式可以根据在 DOM 中的接近程度覆盖另一组样式

  • 更多地控制选择器针对哪些元素(即更好地操作 CSS 的级联)

这意味着,@scope 规则可以让你将选择器的范围限定为文档的特定子树。借助作用域样式,你可以非常具体地选择元素,而无需编写过于具体的选择器或将它们与 DOM 结构紧密耦合。

/* 根作用域 */ 

@scope (.card) {
    img {
        border-color: green;
    }
}

限定了作用域的样式规则 img { … } 实际上只能选择在所匹配 .card 元素范围内(https://drafts.csswg.org/css-cascade-6/#in-scope)的 <img> 元素。如需阻止卡片内容区域 (.card__content) 内的 <img> 元素处于选中状态,你可以使用更具体的 img 选择器。另一种方法是利用 @scope at 规则这一事实,也接受用于确定下限的范围限制

@scope (.card) to (.card__content) {
    img {
        border-color: green;
    }
}

此限定了范围的样式规则仅定位到祖先树中位于 .card.card__content 元素之间的 <img> 元素。这种包含上下边界的范围通常称为“圆环图范围”。

下面这个案例中,由于应用了范围限制,轮播图组件中的 <img> 元素不匹配:

31f84e134794325aa615c6b343213249.png

Demo 地址:https://codepen.io/web-dot-dev/pen/YzBLdjG

在 CSS 级联(https://juejin.cn/book/7223230325122400288/section/7259563116462080037)内,@scope 还添加了一个新条件:确定邻近区域。该步骤在特异性之后,但出现在呈现顺序之前。

805242bba58c4ff9c50b819d09fe43d7.jpeg

按照规范(https://drafts.csswg.org/css-cascade-6/#cascade-proximity):“比较出现在具有不同范围根的样式规则中的声明时,范围根和限定范围的样式规则主题之间具有最少的代数或同级元素跃点的声明胜出”。

有关于 CSS 嵌套特性更详细的介绍,请移步阅读《现代 CSS》(https://s.juejin.cn/ds/i8wsdWCn/)中的《CSS 的嵌套和作用域:& 和 @scope 》(https://juejin.cn/book/7223230325122400288/section/7259668111974989882)课程,或者请参阅《如何使用 @scope 限制选择器的覆盖面》(https://developer.chrome.com/articles/at-scope/?hl=zh-cn)和 @Miriam Suzanne 的《CSS @scope》(https://12daysofweb.dev/2023/css-scope/)。

💯 选择器 :is() 和 :where()

cbe80d613b253b81fcaa157a847c75a9.png

:is():where() 是两个伪类选择器,可以用于选择多个简单选择器的集合,并将它们作为一个整体来进行选择,以简化和优化选择器的编写。

  • :is() 函数接受一个包含多个简单选择器的列表,它返回一个与其中任何一个简单选择器匹配的元素,类似于数组中的 ||(逻辑或)。

  • :where() 函数也接受一个包含多个简单选择器的列表,将选择器中的元素组合在一起,使其更易读、易用。

:is():where() 选择器属于宽容型选择器,使用 :is():where() 时,如果一个选择器无法解析,整个选择器列表不会被视为无效,而是会忽略不正确或不支持的选择器,并使用其他的选择器。另外,它们的使用方式基本相似,唯一的差别就是 :where() 选择器权重总是为 **0**,而 :is() 选择器的权重计数等同于选择器列表中最高权重的值

正因为 :where():is() 选择器可以用来改变选择器权重,因此,可以使用它们来做为级联层的一种简单替代方案。比如,你正在创建一个框架或者一个库,那么可以使用 :where() 伪类函数,将框架或库中的选择器权重降低至 0 。这样做的好处是,使用你的框架或库的 Web 开发者,无需处理选择器权重的问题,它可以很轻易的覆盖你框架或库中的样式规则。

简单地说,:is():where() 可以帮助我们更好地管理 CSS 选择器权重。最为有效的使用方式是:

  • 在构建 CSS 框架或库的时候,使用 :where() 来管理所有选择器的权重,将选择器权重降至为 0

  • 在使用框或库的时候,可以使用 :is() 来提高选择器权重,在不改变 HTML 代码的情况之下,可以将选择器权重提高到最高级别

考虑到 :is():where() 之间的差异,使用哪个选择器,最终还是取决于你的具体需求。

有关于 CSS 嵌套特性更详细的介绍,请移步阅读《现代 CSS》(https://s.juejin.cn/ds/i8wsdWCn/)中的《CSS 选择器::where() vs. :is() 》(https://juejin.cn/book/7223230325122400288/section/7226251495069450278)课程!

💯 选择器 :has()

7a669b192b5c61c5980b1286c5bf77be.png

CSS 的 :has() 选择器被称为 CSS 的父选择器!它和 CSS 的容器查询特性一样,一直以来是 Web 开发者最想要的 CSS 功能。

就我个人而言,CSS 的 :has() 是最接近 if ... else ... 功能的。它与 HTML 的 DOM 关系紧密相连,这也是它被称之为是关系型选择器的主要原因。比如下面这个示例,你正在寻找后代元素的存在,但应用的样式将是父元素。

<!-- Case ① -->
<figure> 
    <figcaption>CSS Pseudo-Class Specification</figcaption> 
    <img src="https://picsum.photos/1240/?random=11" alt=""> 
</figure> 

<!-- Case ② -->
<figure> 
    <div class="media"> 
        <img src="https://picsum.photos/1240/?random=12" alt=""> 
    </div> 
    <figcaption>CSS Pseudo-Class Specification</figcaption> 
</figure> 

<!-- Case ③ -->
<figure> 
    <img src="https://picsum.photos/1240/?random=13" alt=""> 
    <figcaption>CSS Pseudo-Class Specification</figcaption> 
</figure>

这三个 Case 对应的 DOM 树如下图所示:

0f5c961c846a7bd6bae1f370fbee5bea.jpeg

添加下面这样一段 CSS 代码:

/* 匹配包含<figcaption>后代元素的<figure>元素 */ 
figure:has(figcaption) { 
    background-color: #3f51b5; 
}

figure:has(figcaption) 将能匹配所有 figure ,因为 figure 都包含了 figcaption 元素:

888b1ec4804c608e1d6cad0ab5586a2a.jpeg

Demo 地址:https://codepen.io/airen/full/jOeMapz

上面你所看到的只是 :has() 最简单地使用,它可以帮助你做更为复杂的事情,甚至是一些带交互行为的操作。比如下面这个示例,使用 :has() 选择器和状态选择器,可以实现一个纯 CSS 制作的评分组件(StarRating):

984c96aeb7a9a5c77d1113a208c6951b.gif

Demo 地址:https://codepen.io/airen/full/poxeoeE

也正因如此,我在《防御式 CSS 精讲》(https://juejin.cn/book/7199571709102391328?utm_source=profile_book)中,将 :has() 纳入到条件 CSS 的范畴(https://juejin.cn/book/7199571709102391328/section/7199845944760729632),因为它在很多时候,能根据相关的动态条件,允许你使用不同的 CSS。

:has() 选择器是强大的,它除了能让我们不使用 JavaScript 脚本实现一些具有挑战性的 GUI 之外(比如上面这个示例),它还有很多其他的功能,比如 @wesbos 前段时间在 Twitter 分享一张图(https://twitter.com/wesbos/status/1737148340322652632),介绍了 :has() 选择器十个小技巧:

02ad017c039b43b93ada7403141c9f5c.png

图片来源:https://twitter.com/wesbos/status/1737148340322652632

有关于 :has() 选择器更详细的介绍,你还可以参阅:

  • CSS 父选择器::has() (https://juejin.cn/book/7223230325122400288/section/7224404685615005728)

  • CSS 选择器::has() 能解决哪些问题 (https://juejin.cn/book/7223230325122400288/section/7224404685799555111)

  • CSS 选择器::has() 和 :not() 的组合 (https://juejin.cn/book/7223230325122400288/section/7226251495276609569)

💯 复杂的第 n-* 选择

b58c356fd6df3a48ad371892a28e0d5a.png

CSS 选择器级别 4 (https://www.w3.org/TR/selectors-4/)中的新功能是可以选择将选择器列表传递到 :nth-child():nth-last-child()

:nth-child(An+B [of S]?)
:nth-last-child(An+B [of S]?)

指定 of S 后,An+B 逻辑仅应用于与给定选择器列表 S 匹配的元素。这实际上意味着,你可以在 An+B 执行操作之前预先过滤子项。

我们借助 :nth-child() 伪类选择器,可以按索引选择 DOM 中的元素。你可以使用 An+B 微语法精确控制要选择哪些元素。

默认情况下,:nth-*() 伪代码会考虑所有子元素。从 Chrome 111 开始,你可以选择将选择器列表传递到 :nth-child():nth-last-child()。这样一来,就可以在 An+B 执行操作之前预先过滤子项列表。

在下面的演示中,通过使用 of .small 对小玩偶进行预过滤,3n+1 逻辑仅应用于它们。使用下拉菜单可动态更改所使用的选择器。

9b28b3c7015d3b80bf24650a17387a24.png


Demo  地址:https://codepen.io/web-dot-dev/full/YzBLdLW

更有意思的是,我们可以使用 :has():not()~+ 组合在一起模拟 :nth-child(An+B [of S]?):nth-last-child(An+B [of S]?) 选择器,甚至是 CSS 中不存在的选择器:

  • :first-in-ElementGroups-of-class(.😍) ,即选中元素组(ElementGroups)中第一个元素(类名为 .**😍**),对应的选择器为 .😍:not(:has(+ .😍))

  • :last-in-ElementGroups-of-class(.😍) ,即选中元素组(ElementGroups)中最后一个元素(类名为 .**😍**),对应的选择器为 .😍:not(:has(+ .😍))

  • :single-in-ElementGroups-of-class(.😍) ,即选中元素组(ElementGroups)中仅有的一个元素(类名为 .**😍**),对应的选择器为 .😍:not(.😍 + .😍):not(:has(+ .😍))

  • :nth-in-ElementGroups-of-class(.😍) ,即选中元素组(ElementGroups)中的第 n 个元素(类名为 .**😍)。比如 .😍:not(.😍 + .😍) + .😍 选择元素组中第 2 个元素(类名为 .😍);.😍:not(.😍 + .😍) + .😍 + .😍 选择元素组中第 3 个元素(类名为 .😍**)。

  • **:nth-last-in-island-of-class(.special),即选中元素组(ElementGroups)中的倒数第 n 个元素(类名为 .😍)。比如 .😍:not(:has(+ .😍 + .😍)):has(+ .😍) 选中元素组中倒数第 2 个元素(类名为 .😍),.😍:not(:has(+ .😍 + .😍 + .😍)):has(+ .😍 + .😍) 选中元素组中倒数第 3 个元素(类名为 .😍**)。

278dac770e7a21bc4a33f64e85c55a7c.png

Demo 地址:https://codepen.io/airen/full/rNqmGrN

💯 CSS 三角函数

9cede9bf366772cc69fc3e80b2613255.png

在 W3C 规范的 CSS 值和单位模块 Level 4 (https://www.w3.org/TR/css-values-4/)(CSS Values and Units Module Level 4)为 Web 开发者提供了数学表达式(https://www.w3.org/TR/css-values-4/#math)相关的能力。除了我们所熟悉的 calc() 函数和 CSS 比较函数(https://juejin.cn/book/7223230325122400288/section/7241401565653762108)(比如 min()max()clamp())之外,还有 CSS 的三角函数(https://www.w3.org/TR/css-values-4/#trig-funcs),比如 sin()cos()tan()asin()acos()atan()atan2() 等。

现在,使用 CSS 的三角函数,你可以更轻松地在以一点为中心的圆圈上布置元素:

c22bb58c32be30d8ef5c5e6ffb8b6893.png

img

Demo  地址:https://codepen.io/web-dot-dev/full/poGVqLO

如果你是一名动画爱好者或者说平时经常有开发动画的需求(https://s.juejin.cn/ds/i8K8poEy/),那么 CSS 三角函数将是你最好的助手。动画开发过程中,你可以这样来使用 CSS 的三角函数:

  • sin() 函数可用于改变元素尺寸或控制动画时长;

  • cos() 函数可用于保持旋转元素的尺寸不变;

  • tan() 函数可用于绘制平行四边形;

  • asin()acos()atan()atan2() 函数可用于旋转元素。

除此之外,三角函数在动画中有多种应用和作用,以下是一些常见的例子:

  • 平滑运动和缓动效果:通过使用三角函数,特别是正弦(sin())和余弦(cos())函数,可以实现元素的平滑运动和缓动效果。这有助于使动画看起来更自然,避免了突然的加速和减速。

  • 周期性动画:正弦(sin())和余弦(cos())函数是周期性的,因此它们经常用于创建具有循环或重复动作的动画效果。例如,通过调整正弦(sin())函数的参数,可以创建水波纹或震荡效果。

  • 旋转动画:三角函数的旋转性质使其成为创建对象旋转动画的理想选择。通过在正弦(sin())和余弦(cos())函数中使用时间变量,可以实现平滑的旋转效果。

  • 路径动画:三角函数的周期性和平滑性使其适用于定义对象沿着复杂路径运动的动画。通过适当调整三角函数的参数,可以创建各种路径动画。

  • 振荡效果:通过使用正弦(sin())函数,可以模拟振荡效果,例如摆动或弹簧的弹性动画。

  • 相位和频率调整:调整三角函数的相位和频率可以改变动画的速度和周期,从而提供更多的创造性控制。

这些只是三角函数在动画中的一些常见应用,创意的设计师和开发者可以发挥出更多的潜力,创造出丰富多彩且引人入胜的动画效果。例如下面这个摩天轮旋转动效,就应用了 CSS 的三角函数:

746297a058d2280b170d8405dcebd265.png


Demo 地址:https://codepen.io/airen/full/JjxzWgW

你可以从《CSS 的三角函数》(https://juejin.cn/book/7223230325122400288/section/7242216512176521277)和 《数学的魔法:探索数学在动画中的应用》(https://juejin.cn/book/7288940354408022074/section/7307213432616648745)两节课中获得 CSS 三角函数更多的信息!

💯 子网格 subgrid

7db98599dd7f3a545e02b4daef915a5d.png

借助 CSS 子网格 subgrid ,你可以创建更复杂的网格布局,并在子布局之间实现更好的对齐。

5e0b3843690d9a20559c3162a457d875.png

它允许另一个网格内的网格将外部网格的行和列作为自己的行和列,方法是使用 subgrid 作为网格行或列的值。

简单地说,在一个网格项目上显式设置 display 的值为 gridinline-grid ,或者继承其父网格容器的 display 值,就意味着该网格项目是一个独立的网格格式化上下文。同时,子网格的 grid-template-columns 和(或)grid-template-rows 显式设置值为 subgrid 时,就意味着子网格的内容参与其父网格的格式化上下文,而不会建立一个新的网格格式化上下文。

网格布局中的子网格是非常有用的,它将为我们提供更多的方法来实现 CSS 网格之前不可能实现的功能。subgrid 非常适合用来根据彼此的动态内容对齐同级,借助 subgrid,可以调整布局以适应内容。

8e0e8778602aa34343f2064271217ce5.png

如果你对子网格布局特性感兴趣,可以移步阅读《现代 Web 布局》(https://s.juejin.cn/ds/i8KNNR7j/)中的《网格布局中的子网格和嵌套网格》(https://juejin.cn/book/7161370789680250917/section/7160657953932967967)!

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值