使用 CSS 嵌套

CSS 嵌套 模块允许您编写样式表,使其更易于阅读、更模块化且更易于维护。由于您没有不断重复选择器,因此文件大小也可以减小。

CSS 嵌套与 Sass 等 CSS 预处理器不同,因为它由浏览器解析,而不是由 CSS 预处理器预编译。此外,在 CSS 嵌套中,& 嵌套选择器的特异性 类似于 :is() 函数;它是使用关联选择器列表中最高的特异性计算的。

本指南展示了在 CSS 中排列嵌套的不同方法。

子选择器

您可以使用 CSS 嵌套创建父元素的子选择器,然后可以使用这些子选择器来定位特定父元素的子元素。这可以通过使用或不使用 & 嵌套选择器 来完成。

在某些情况下,使用 & 嵌套选择器可能是必要的或有帮助的

  • 当将选择器组合在一起时,例如使用 复合选择器伪类
  • 为了向后兼容。
  • 作为视觉指示以帮助提高可读性,当看到 & 嵌套选择器时,您就知道正在使用 CSS 嵌套。
css
/* Without nesting selector */
parent {
  /* parent styles */
  child {
    /* child of parent styles */
  }
}

/* With nesting selector */
parent {
  /* parent styles */
  & child {
    /* child of parent styles */
  }
}

/* the browser will parse both of these as */
parent {
  /* parent styles */
}
parent child {
  /* child of parent styles */
}

示例

在这些示例中,一个不使用 & 嵌套选择器,另一个使用 & 嵌套选择器,<label> 内部的 <input> 的样式与作为 <label> 同级元素的 <input> 的样式不同。这演示了省略 & 嵌套选择器的影响。

注意:此示例演示了实现原始规范与当前嵌套规范的浏览器中的不同输出。Chrome 或 Safari 中实现的原始(2023 年 8 月之前的)嵌套规范需要 & 嵌套组合器。如果您的浏览器支持当前规范,则两个示例的输出都与第二个示例的输出匹配。

不使用嵌套选择器

HTML
html
<form>
  <label for="name">Name:
    <input type="text" id="name" />
  </label>
  <label for="email">email:</label>
  <input type="text" id="email" />
</form>
CSS
css
input {
  /* styles for input not in a label  */
  border: tomato 2px solid;
}
label {
  /* styles for label */
  font-family: system-ui;
  font-size: 1.25rem;
  input {
    /* styles for input in a label  */
    border: blue 2px dashed;
  }
}
结果

使用嵌套选择器

HTML
html
<form>
  <label for="name">Name:
    <input type="text" id="name" />
  </label>
  <label for="email">email:</label>
  <input type="text" id="email" />
</form>
CSS
css
input {
  /* styles for input not in a label  */
  border: tomato 2px solid;
}
label {
  /* styles for label */
  font-family: system-ui;
  font-size: 1.25rem;
  & input {
    /* styles for input in a label  */
    border: blue 2px dashed;
  }
}
结果

组合器

CSS 组合器 也可以在使用或不使用 & 嵌套选择器的情况下使用。

示例

嵌套同级组合器

在此示例中,每个 <h2> 之后的第一个段落使用 下一个同级组合器 (+) 和 CSS 嵌套进行定位。

HTML
html
<h2>Heading</h2>
<p>This is the first paragraph.</p>
<p>This is the second paragraph.</p>
CSS
css
h2 {
  color: tomato;
  + p {
    color: white;
    background-color: black;
  }
}
/* this code can also be written with the & nesting selector */
/* 
h2 {
  color: tomato;
  & + p {
    color: white;
    background-color: black;
  }
}
*/
结果

复合选择器

在嵌套 CSS 中使用 复合选择器 时,**必须**使用 & 嵌套选择器。这是因为浏览器会在不使用 & 嵌套选择器的选择器之间自动添加空格。

为了定位具有 class="a b" 的元素,需要 & 嵌套选择器,否则空格将破坏复合选择器。

css
.a {
  /* styles for element with class="a" */
  .b {
    /* styles for element with class="b" which is a descendant of class="a" */
  }
  &.b {
    /* styles for element with class="a b" */
  }
}

/* the browser parses this as */
.a {
  /* styles for element with class="a" */
}
.a .b {
  /* styles for element with class="b" which is a descendant of class="a" */
}
.a.b {
  /* styles for element with class="a b" */
}

示例

嵌套和复合选择器

在此示例中,& 嵌套选择器用于创建复合选择器,以设置具有多个类的元素的样式。

HTML
html
<div class="notices">
  <div class="notice">
    <h2 class="notice-heading">Notice</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
  </div>
  <div class="notice warning">
    <h2 class="warning-heading">Warning</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
  </div>
  <div class="notice success">
    <h2 class="success-heading">Success</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
  </div>
</div>
CSS

.notices 的样式,使用 Flexbox 布局 创建一列。

css
.notices {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 90%;
  margin: auto;
}

在下面的 CSS 代码中,嵌套用于创建带和不带&的复合选择器。顶级选择器定义了具有class="notice"元素的基本样式。然后使用&嵌套选择器为具有class="notice warning"class="notice success"的元素创建复合选择器。此外,在选择器.notice .notice-heading::before中可以看到使用嵌套创建复合选择器而不显式使用&

css
.notice {
  width: 90%;
  justify-content: center;
  border-radius: 1rem;
  border: black solid 2px;
  background-color: #ffc107;
  color: black;
  padding: 1rem;
  .notice-heading::before {
    /* equivalent to `.notice .notice-heading::before` */
    content: "ℹ︎ ";
  }
  &.warning {
    /* equivalent to `.notice.warning` */
    background-color: #d81b60;
    border-color: #d81b60;
    color: white;
    .warning-heading::before {
      /* equivalent to `.notice.warning .warning-heading::before` */
      content: "! ";
    }
  }
  &.success {
    /* equivalent to `.notice.success` */
    background-color: #004d40;
    border-color: #004d40;
    color: white;
    .success-heading::before {
      /* equivalent to `.notice.success .success-heading::before` */
      content: "✓ ";
    }
  }
}
结果

附加嵌套选择器

&嵌套选择器也可以附加到嵌套选择器,这会反转上下文。

当我们有子元素的样式,并且当父元素被赋予不同的类时这些样式会发生变化时,这很有用。

html
<div>
  <span class="foo">text</span>
</div>

html
<div class="bar">
  <span class="foo">text</span>
</div>
css
.foo {
  /* .foo styles */
  .bar & {
    /* .bar .foo styles */
  }
}

示例

附加嵌套选择器

在这个例子中,有 3 张卡片,其中一张是特色卡片。除了特色卡片的标题将具有替代颜色外,所有卡片都完全相同。通过附加&嵌套选择器,.featured .h2的样式可以嵌套在h2的样式中。

HTML
html
<div class="wrapper">
  <article class="card">
    <h2>Card 1</h2>
    <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p>
  </article>
  <article class="card featured">
    <h2>Card 2</h2>
    <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p>
  </article>
  <article class="card">
    <h2>Card 3</h2>
    <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p>
  </article>
</div>
CSS
css
.wrapper {
  display: flex;
  flex-direction: row;
  gap: 0.25rem;
  font-family: system-ui;
}

在以下 CSS 中,我们正在创建.card.card h2的样式。然后,在h2样式块中,我们将.featured类与附加的&嵌套选择器嵌套,这会为.card :is(.featured h2)创建样式,这等效于:is(.card h2):is(.featured h2)

css
.card {
  padding: 0.5rem;
  border: 1px solid black;
  border-radius: 0.5rem;
  & h2 {
    /* equivalent to `.card h2` */
    color: slateblue;
    .featured & {
      /* equivalent to `:is(.card h2):is(.featured h2)` */
      color: tomato;
    }
  }
}
结果

连接(不可行)

在 Sass 等 CSS 预处理器中,可以使用嵌套将字符串连接起来以创建新的类。这在 BEM 等 CSS 方法中很常见。

css
.component {
  &__child-element {
  }
}
/* In Sass this becomes */
.component__child-element {
}

警告:这在 CSS 嵌套中是不可能的:当不使用组合器时,嵌套选择器将被视为类型选择器。允许连接将破坏这一点。

复合选择器中,类型选择器必须放在第一位。编写&Element(一个类型选择器)会使 CSS 选择器和整个选择器块无效。由于类型选择器必须放在第一位,因此复合选择器必须写成Element&

css
.my-class {
  element& {
  }
}

/* the browser parses this to become a compound selector */
.my-class {
}
element.my-class {
}

无效的嵌套样式规则

如果嵌套的 CSS 规则无效,则所有包含的样式都将被忽略。这不会影响父级或前面的规则。

在下面的示例中,有一个无效的选择器(%不是选择器的有效字符)。包含此选择器的规则将被忽略,但后续的有效规则不会。

css
.parent {
  /* .parent styles these work fine */
  & %invalid {
    /* %invalid styles all of which are ignored */
  }
  & .valid {
    /* .parent .valid styles these work fine */
  }
}

另请参阅