帮助为 CSS 嵌套选择语法

您需要帮助确定两种相互冲突的语法,以推进规范的候选。

Adam Argyle
Adam Argyle
米丽亚姆·苏珊 (Miriam Suzanne)
Miriam Suzanne

CSS 嵌套是一种便捷的语法添加方式,允许将 CSS 添加到规则集内。如果您使用过 SCSSLessStylus,那么肯定看到了此类的几种风格:

.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

在预处理器将其编译为常规 CSS 后,该转换会转换为常规 CSS,如下所示:

.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

我们强烈考虑此语法的官方 CSS 版本,并且有一项优先权衡,我们希望借助社区的帮助来打破这种局面。本博文的其余部分将会介绍语法选项,以便您在最后能够了解完成问卷调查的知识。

为什么上面显示的确切嵌套示例不能是 CSS 嵌套的语法?

最流行的嵌套语法无法按原样使用的原因有以下几种:

  1. 解析不明确
    某些嵌套选择器可能看起来与属性和预处理器非常相似,能够在构建时解析和管理。各浏览器引擎将提供相同的功能,因此绝不应对选择器进行宽松的解释。

  2. 预处理器解析冲突
    CSS 的嵌套方式不应破坏预处理器或现有的开发者嵌套工作流。这会造成干扰,且会忽视这些生态系统和社区。

  3. 等待 :is()
    基本嵌套不需要 :is(),但更复杂的嵌套需要。请参阅示例 3,简要了解选择器列表和嵌套。假设该选择器列表位于选择器的中间位置(而不是开头),在这种情况下,需要使用 :is() 才能对位于另一个选择器中间的选择器进行分组。

比较对象概述

我们希望实现正确的 CSS 嵌套,本着这一精神,我们希望将社区纳入其中。以下部分将帮助介绍我们正在评估的三个可能版本。然后,我们会介绍一些用于进行比较的用法示例,最后会有一份简短的调查问卷,询问您总体上更喜欢哪种用法。

方法 1:@nest

这是 CSS 嵌套 1 中当前指定的语法。它通过使用 & 启动新的嵌套选择器,提供了一种嵌套附加样式的便捷方式。它还提供 @nest,以便将 & 上下文放置在新选择器中的任意位置,例如,当您不只是附加主题时。该 API 非常灵活且最少,但代价是您需要记住 @nest&,具体取决于您的用例。

方法 2:@nest 受限

这是一种更严格的替代方法,旨在减少提到的需要记住两种嵌套方法的开销。此受限语法只允许在 @nest 之后进行嵌套,因此没有“纯附加便捷模式”。消除了选择的歧义,创建一种容易记住的嵌套方法,但为了遵循惯例,牺牲了简洁性。

选项 3:括号

为了避免 @nest 方案涉及双重语法或额外杂乱,Miriam SuzanneElika Etemad 提出了一种依赖于额外大括号的替代语法。这样就提高了语法清晰度,只有两个额外的字符,并且没有新的 @ 规则。它还允许按所需的嵌套类型对嵌套规则进行分组,以简化多个嵌套类似的选择器。

示例 1 - 直接嵌套

@nest

.foo {
  color: #111;

  & .bar {
    color: #eee;
  }
}

始终添加 @nest

.foo {
  color: #111;

  @nest & .bar {
    color: #eee;
  }
}

括号

.foo {
  color: #111;

  {
    & .bar {
      color: #eee;
    }
  }
}

等效 CSS

.foo {
  color: #111;
}

.foo .bar {
  color: #eee;
}

示例 2 - 复合嵌套

@nest

.foo {
  color: blue;

  &.bar {
    color: red;
  }
}

始终添加 @nest

.foo {
  color: blue;

  @nest &.bar {
    color: red;
  }
}

括号

.foo {
  color: blue;

  {
    &.bar {
      color: red;
    }
  }
}

等效 CSS

.foo {
  color: blue;
}

.foo.bar {
  color: red;
}

示例 3 - 选择器列表和嵌套

@nest

.foo, .bar {
  color: blue;

  & + .baz,
  &.qux {
    color: red;
  }
}

始终添加 @nest

.foo, .bar {
  color: blue;

  @nest & + .baz,
  &.qux {
    color: red;
  }
}

括号

.foo, .bar {
  color: blue;

  {
    & + .baz,
    &.qux {
      color: red;
    }
  }
}

等效 CSS

.foo, .bar {
  color: blue;
}

:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
  color: red;
}

示例 4 - 多个级别

@nest

figure {
  margin: 0;

  & > figcaption {
    background: lightgray;

    & > p {
      font-size: .9rem;
    }
  }
}

始终添加 @nest

figure {
  margin: 0;

  @nest & > figcaption {
    background: lightgray;

    @nest & > p {
      font-size: .9rem;
    }
  }
}

括号

figure {
  margin: 0;

  {
    & > figcaption {
      background: lightgray;

      {
        & > p {
          font-size: .9rem;
        }
      }
    }
  }
}

等效 CSS

figure {
  margin: 0;
}

figure > figcaption {
  background: hsl(0 0% 0% / 50%);
}

figure > figcaption > p {
  font-size: .9rem;
}

示例 5 - 父级嵌套或主题变化

@nest

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

始终添加 @nest

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

括号

.foo {
  color: red;

  {
    .parent & {
      color: blue;
    }
  }
}

等效 CSS

.foo {
  color: red;
}

.parent .foo {
  color: blue;
}

示例 6 - 混合使用直接嵌套和父级嵌套

@nest

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    &.baz {
      color: green;
    }
  }
}

始终添加 @nest

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    @nest &.baz {
      color: green;
    }
  }
}

括号

.foo {
  color: blue;

  {
    .bar & {
      color: red;

      {
        &.baz {
          color: green;
        }
      }
    }
  }
}

等效 CSS

.foo {
  color: blue;
}

.bar .foo {
  color: red;
}

.bar .foo.baz {
  color: green;
}

示例 7 - 媒体查询嵌套

@nest

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

或者显式 / 扩展

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

@nest 始终(始终是显式的)

.foo {
  display: grid;

  @media (width => 30em) {
    @nest & {
      grid-auto-flow: column;
    }
  }
}

括号

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

或者显式 / 扩展

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

等效 CSS

.foo {
  display: grid;
}

@media (width => 30em) {
  .foo {
    grid-auto-flow: column;
  }
}

示例 8 - 嵌套组

@nest

fieldset {
  border-radius: 10px;

  &:focus-within {
    border-color: hotpink;
  }

  & > legend {
    font-size: .9em;
  }

  & > div {
    & + div {
      margin-block-start: 2ch;
    }

    & > label {
      line-height: 1.5;
    }
  }
}

始终添加 @nest

fieldset {
  border-radius: 10px;

  @nest &:focus-within {
    border-color: hotpink;
  }

  @nest & > legend {
    font-size: .9em;
  }

  @nest & > div {
    @nest & + div {
      margin-block-start: 2ch;
    }

    @nest & > label {
      line-height: 1.5;
    }
  }
}

括号

fieldset {
  border-radius: 10px;

  {
    &:focus-within {
      border-color: hotpink;
    }
  }

  > {
    legend {
      font-size: .9em;
    }

    div {
      + div {
        margin-block-start: 2ch;
      }

      > label {
        line-height: 1.5;
      }
    }}
  }
}

等效 CSS

fieldset {
  border-radius: 10px;
}

fieldset:focus-within {
  border-color: hotpink;
}

fieldset > legend {
  font-size: .9em;
}

fieldset > div + div {
  margin-block-start: 2ch;
}

fieldset > div > label {
  line-height: 1.5;
}

示例 9 - 复杂的嵌套组“厨房水槽”

@nest

dialog {
  border: none;

  &::backdrop {
    backdrop-filter: blur(25px);
  }

  & > form {
    display: grid;

    & > :is(header, footer) {
      align-items: flex-start;
    }
  }

  @nest html:has(&[open]) {
    overflow: hidden;
  }
}

始终添加 @nest

dialog {
  border: none;

  @nest &::backdrop {
    backdrop-filter: blur(25px);
  }

  @nest & > form {
    display: grid;

    @nest & > :is(header, footer) {
      align-items: flex-start;
    }
  }

  @nest html:has(&[open]) {
    overflow: hidden;
  }
}

括号

dialog {
  border: none;

  {
    &::backdrop {
      backdrop-filter: blur(25px);
    }

    & > form {
      display: grid;

      {
        & > :is(header, footer) {
          align-items: flex-start;
        }
      }
    }
  }

  {
    html:has(&[open]) {
      overflow: hidden;
    }
  }
}

等效 CSS

dialog {
  border: none;
}

dialog::backdrop {
  backdrop-filter: blur(25px);
}

dialog > form {
  display: grid;
}

dialog > form > :is(header, footer) {
  align-items: flex-start;
}

html:has(dialog[open]) {
  overflow: hidden;
}

投票时间

希望您对我们正在评估的语法选项进行了比较和示例。请仔细阅读,然后告诉我们您希望采用哪种方式。感谢您帮助我们改进 CSS 嵌套,使之成为我们所有人都会了解和喜爱的语法!

参加问卷调查!