什么是CSS嵌套?

0 股票
0
0
0
0

介绍

如果你是一名使用过 CSS 预处理器的前端开发人员,那么你很可能已经接触或使用过嵌套功能。它一直是一个很受欢迎的功能,对我来说,它也是促使我使用 CSS 预处理器的原因之一。.

今年,所有主流浏览器(Chrome、Firefox 和 Safari)都已支持原生 CSS 嵌套。这是 CSS 的一项核心特性,能够简化 CSS 的编写。在本文中,我将记录我目前对 CSS 嵌套的理解,并与大家分享我的发现、应用案例和示例。.

除了热情和专注之外,没有其他先决条件。.

CSS嵌套一直是许多开发者期待已久的功能。过去我们依赖于Sass或Less等CSS预处理器。下面我简单介绍一下:

请看以下示例。我们有一个位于 .nav__item 选择器中的图标。.

.nav__item {
.icon {
display: flex;
padding: 1rem;
}
}

以上代码是有效的 Sass 代码。编译后,在浏览器中将显示如下内容:

.nav__item .icon {
display: flex;
padding: 1rem;
}

使用原生 CSS 嵌套,同样的 CSS 代码可以直接生效。下图展示了原生 CSS 嵌套和浏览器开发者工具的对比。.

注意浏览器显示 CSS 的方式与 CSS 中的显示方式几乎相同。.

如果将这段 CSS 代码编译成 Sass,浏览器会显示如下内容:

CSS嵌套的优势

我认为嵌套 CSS 有其合理用途:

  • CSS 更易于阅读。.
  • 将风格组合在一起
  • 限制特定风格
  • 对没有类或 ID 的 HTML 元素进行样式设置。.

CSS嵌套规则

为了帮助大家了解 CSS 嵌套,我将尝试提供各种 CSS 问题的可视化示例,以及嵌套如何帮助解决这些问题。.

首先,你需要了解符号“&”。在很多情况下,这个符号都至关重要。.

嵌套没有类名或 ID 的元素

在这个例子中,元素 <a> 通过 .nav__item 设置样式。使用 &lt;head&gt; 标签对于 CSS 的有效性是可选的。.

.nav__item {
  & a {
    display: block;
    padding: 1.5rem 1rem;
  }
}

/* Same as: */
.nav__item a {
}

您也可以选择不勾选:

.nav__item {
a {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item a {
}

请注意,这是最近更新的内容,称为“宽松 CSS 嵌套”。它适用于最新的 Chrome Canary 和 Safari 技术预览版。您可以查看 Adam Argyle 撰写的关于宽松嵌套的文章。.

嵌套带有类名的元素

考虑与之前相同的例子,但假设元素 <a> 它有一个HTML类。.

.nav__item {
.link {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item .link {
}

这里不需要使用符号,类名就可以了。.

嵌套 CSS 组合器

CSS原生嵌套的优势之一在于可以使用组合器。让我们来看一些例子。.

在下面的示例中,我想选择所有类名为 `.nav__item` 且其前面还有一个具有相同类名的元素的元素。为此,我使用了相邻兄弟选择器。.

在原生 CSS 嵌套中,我们可以使用 & 符号来模拟嵌套。请注意,我重复使用了两次。.

.nav__item {
& + & {
border-left: 2px solid;
}
}

神奇之处在于 & 符号的第二次迭代。在这里,浏览器意识到我想使用相邻兄弟选择器。下面我举个例子来说明:

嵌套的另一个例子是子元素组合器。它可以选择一个元素的直接子元素。.

.nav__item {
> a {
padding: 1rem;
}
}

和符号

.nav__item {
& a {
color: blue;
}
}

这是最初 CSS 嵌套规范中的要求。在 Safari TP 179+ 和 Chrome Canary 120 中,嵌套元素不再需要 & 符号。.

因此,以下方法有效:

.nav__item {
a {
color: blue;
}
}

唯一的问题是,您必须恢复到规范的先前版本,该版本必须包含标记和标记。.

嵌套示例:活动、聚焦、悬停

:active、:focus 和 :hover 是 CSS 伪类,由用户操作激活。.

通过 CSS 嵌套,我们可以一次性嵌套所有样式,避免代码重复。以 `:hover` 为例:

button {
&:hover {
background-color: var(--bg-color);
}
&:focus {
outline: solid 2px;
}
}

使用预处理器进行嵌套时的区别在于,浏览器会按如下方式渲染:

button:hover {
background-color: var(--bg-color);
}
button:focus {
outline: solid 2px;
}

让我们来看看 CSS 嵌套在 Chrome、Safari 和 Firefox 中的显示效果。.

关于 CSS 嵌套的 DevTools 用户体验,我有一些想法,稍后会在文章中讨论。.

嵌套示例:发布内容

测试嵌套 CSS 的最早例子之一是为文章正文内容设置样式。想象一下,一篇文章包含标题、正文、图片、引用等等。.

标题

我们通常采用以下这种标题格式:

.post-content h1,
.post-content h2,
.post-content h3,
.post-content h4 {
/* styles here */
}

使用嵌套 CSS 就容易多了:

.post-content {
h1,
h2,
h3,
h4 {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}

我们也可以使用 :is() 选择器来实现同样的功能。.

.post-content {
:is(h1, h2, h3, h4) {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}

段落元素

常见的例子是给段落内的链接设置样式。在这种情况下,CSS 嵌套非常有效。.

.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
}
}
}

链接可能还需要悬停或聚焦效果。.

.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
&:hover {
/* hover styles */
}
}
}
}

我们还可以嵌套媒体查询。.

.post-content {
& p {
/* base styles */
@media (min-width: 400px) {
/* do something */
}
}
}

在某些情况下,内容管理系统 (CMS) 可能是一个要素。 <p> 将其包裹在另一个元素中,并且出于样式考虑,它应该仅用于直接元素。 <p> 打造你的风格。.

.post-content {
/* Select the direct <p> elements */
> p {
/* base styles */
}
}

引用块

在这个例子中,引用拥有自己的自定义样式和元素 <p> 在引用中,选择将底部边距重置为零。.

.post-content {
& blockquote {
/* custom quote styling */
& p {
margin-bottom: 0;
}
}
}

后形

帖子表单包含一张图片和一个

可选择是否显示图片描述。.

在我的例子中,如果

它有一个标题,我需要对它进行不同的样式设置。这可以通过添加 CSS :has() 来实现。.

.post-content {
& figure {
& img {
/* the figure's image styles */
}
/* changes to the <figure> container, if it has a figcaption element */
&:has(figcaption) {
display: flex;
align-items: start;
}
& figcaption {
/* caption styling */
}
}
}

帖子列表

我需要给除最后一个列表项之外的所有列表项添加边框。为此,我使用了 :not() 选择器。.

.post-content {
li {
&:not(:last-child) {
border-bottom: 1px solid;
}
}
}

要使用 :not(),我们需要在其前面添加一个 & 符号。.

自定义标题间距

以下距离应为 <h3> 和 <h4> 如果其中一条评论后面跟着代码片段,我会减少评论的金额。.

.post-content {
& h3 + [class*="language-"],
& h4 + [class*="language-"] {
margin-top: 0.5rem;
}
}

正如你在这个实际例子中看到的,使用 CSS 嵌套很简单,特别是如果你有 CSS 预处理器方面的经验。.

嵌套示例:卡片组件

我将展示一个简单的卡片组件,它使用 CSS 嵌套来实现所需的样式。.

假设有一个具有默认或基本样式的 .card 元素,我将演示嵌套 CSS 的用法。.

.card {
/* default card styles */
}

嵌套容器查询

如果容器宽度大于 400px,我希望卡片转换为弹性容器。.

.card {
/* default card styles */
/* if the container width is 400px or bigger */
@container card (min-width: 400px) {
display: flex;
}
}

设置段落元素样式

我想通过以下方式使用段落元素 <h3> 这样,我就可以给元素添加边距和内边距了。 <p> 我来补充。如果没有这个元素,用户界面就不会有额外的间距。.

.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
}

当容器宽度为 400 像素或更大时,.card__content 元素也应转换为弹性容器。.

.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
@container card (min-width: 400px) {
display: flex;
flex-direction: column;
justify-content: center;
}
}

嵌套示例:表单输入

一个常见的例子是设置输入框占位符的样式。问题在于每个浏览器厂商都有自己的前缀(哦,现在都2023年了)。.

由于前缀样式需要冒号,因此我们必须使用 & 符号,否则样式将失效。.

input {
--placeholder-color: #969696;
/* other styles */
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
&::-moz-placeholder {
color: var(--placeholder-color);
opacity: 1;
}
&:-moz-placeholder {
color: var(--placeholder-color);
}
}

你可能想知道使用嵌套 CSS 和直接编写前缀样式有什么区别。.

/********** Option 1: native nesting **********/
input {
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
}
/********** Option 2: without nesting **********/
input::-webkit-input-placeholder {
color: var(--placeholder-color);
}

两者之间没有区别。它们都具有相同的属性(0、1、1)。.

嵌套示例:通过父元素设置元素样式

我们可以使用 CSS 嵌套来根据子元素所在的位置改变其样式。例如,如果一个 `.button` 元素位于一个 `.box` 父元素中,它应该占据整个宽度。.

<div class="box">
<h2>Get access to all features</h2>
<p>Create an account now and get access to all exclusive features.</p>
<a href="/offer" class="button">Create an account</a>
</div>
.button {
.box & {
width: 100%;
}
}
/* equivalent to */
.box .button {
}

我在探索 CSS 嵌套时遇到的错误

使用无符号全局选择器

假设我们有一个卡片,并且想要选中卡片内的所有元素。使用 CSS 原生嵌套,以下代码应该可以实现:

.card {
* {
/* styles here */
}
}

我注意到这在 Chrome 稳定版中不起作用,但在 Chrome Canary 121、Safari 17.1 和 Firefox 119 中运行良好。.

解决方法是添加标点符号。.

.card {
& * {
/* styles here */
}
}

使用无符号数据属性

在这个问题中,选择没有勾选标记的数据属性并不能得到预期的结果。.

.card {
[data-type="featured"] {
/* styles here */
}
}

我注意到它在 Chrome 稳定版中无法正常工作,但在 Chrome Canary 121、Safari 17.1 和 Firefox 119 中运行良好。.

要解决这个问题,我们需要添加一个逗号:

.card {
&[data-type="featured"] {
/* styles here */
}
}

这两个错误都在 Chrome Canary 版本中针对宽松的 CSS 嵌套进行了修复。.

识别 CSS 嵌套支持

`@supports` 可以用来检查 CSS 嵌套是否受支持。在本例中,我们要检查浏览器是否识别 `&` 符号。.

@supports selector(&) {
.post-content {
& h2 {
/* styles here. */
}
}
}

您可以在 Bramus 的 Codepen 示例中探索其他识别支撑的方法。.

今天我会使用 PostCSS 嵌套插件,它可以将嵌套 CSS 编译成普通 CSS。等到安全后,我会移除这个插件。.

CSS嵌套的DevTools用户体验

我不太喜欢目前浏览器开发者工具中 CSS 嵌套的用户体验。.

我曾撰写过一篇单独的文章,探讨了我对 DevTools 中 CSS 嵌套实现方式的一些建议。.

结果

CSS嵌套是一项重要的特性,它显著提升了CSS的编写方式。目前,嵌套功能已经可以使用,但由于其支持尚处于起步阶段,因此在实际应用中需要谨慎考虑受众群体。.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

您可能也喜欢