讲解 CSS Nesting 原生嵌套语法 🥳

1,024 阅读4分钟

来自 Web 开发者的呼声.png

CSS 预处理器

概述/简介

CSS Houdini 提案之前,CSS 本身不属于可编程语言。当前端项目逐渐庞大之后,CSS 的维护也越来越困难,这时我们就需要 CSS 预处理器通过 工程化 的手段让 CSS 更易维护,提升开发效率。CSS 预处理器本质上是通过 变量嵌套语法逻辑函数 等为 CSS 增加一些可编程的特性。

目前主流的 CSS 预处理器主要有

  • Sass
  • Less
  • Stylus
  • PostCSS

CSS 预处理器.png

调研/统计

据统计过使用 CSS 预处理器首要原因:

  • 嵌套语法: 35%
  • 变量: 35%
  • 函数: 25%
  • 其他: 5%
  pie title 
  "嵌套语法" : 35
  "变量" : 35
  "函数" : 25
  "其他" : 5

如果不使用 CSS 预处理器,如何精简 CSS 样式?

  • :is()
  • :where()
  /* Normal 样式 */
  #card img,
  #footer img {
    /* 优先级权重 = (1,0,1) */
  }


  /* 使用 :is() 样式 */
  :is(#card, #footer) img {
    /* 优先级权重 = (1,0,1) */
  }


  /* 使用 :where() 样式 */
  :where(#card, #footer) img {
    /* 优先级权重 = (0,0,1) */
  }

注意 :is():where() 的 CSS 优先级权重!


CSS 原生嵌套语法

就如上个小节所述,嵌套语法是使用 Sass/Less 等 CSS 预处理器的核心原因之一。但在小型项目(HTML + CSS + JS)开发中,使用 CSS 预处理器却有些不便且过于厚重,虽然可以通过 :is():where() 进行简化,但始终无法做到嵌套语法开发时体验和效率。不过现在有了 CSS 原生嵌套语法的支持,一切都迎刃而解。

兼容性

目前主流浏览器都已支持 CSS Nesting 这个特性。查看最新

注意: 该规范的早期版本不允许在没有 &@:.>~+#[* 等选择器的情况下嵌套类型选择器。新版已更新,不再需要嵌套选择器。但是支持度如下:

  • 目前 Firefox 支持新版本的规范
  • 目前 Chrome 和 Safari 支持旧版本的规范,必须使用嵌套选择器进行类型选择器嵌套,具体后面会进行讲解

image.png

基本概念

CSS 嵌套语法

定义了嵌套选择器的语法,提供了将一个样式规则嵌套在另一个样式规则中的功能,子规则的选择器相对于父规则的选择器。

  /* 使用嵌套语法,但不使用嵌套选择器,根据兼容性情况,目前只有 Firefox 支持 */
  parent {
    /* parent styles */
    
    child {
      /* child of parent styles */
    }
  }


  /* 使用嵌套语法,且使用嵌套选择器,主流浏览器都支持 */
  parent {
    /* parent styles */
    
    & child {
      /* child of parent styles */
    }
  }
  

与预处理器区别

  • CSS 嵌套语法是由浏览器解析识别
  • CSS 预处理器是在构建期间进行预编译成css

嵌套规则

  • CSS选择器
  • @media
  • @layer
  • @scope (暂不提供范例)
  • @supports (暂不提供范例)
  • @container (暂不提供范例)

范例 - CSS选择器

  /* 例 1 */
  h2 {
    & p {
      /* h2 p 样式 */
    }
  }
  
  /* 例 2 */
  h2 {
    &.p {
      /* h2.p 样式 */
    }
  }
  
  /* 例 3 */
  .card { 
    & h2 {
      .featured & {
        /* .featured .card h2 */
      }
    }
  }
  

范例 - @media

  /* 使用嵌套语法 */
  .foo {
    display: grid;
    
    @media (orientation: landscape) {
      grid-auto-flow: column;
      
      @media (min-width > 1024px) {
        max-inline-size: 1024px;
      }
    }
  }
  
  
  /* 等效于下面的语法 */
  
  
  .foo {
    display: grid;
  }
  
  @media (orientation: landscape) {
    .foo {
      grid-auto-flow: column;
    }
  }
  
  @media (orientation: landscape) and (min-width > 1024px) {
    .foo {
      max-inline-size: 1024px;
    }
  }
  

范例 - @layer

  .foo {
    @layer base {
      block-size: 100%;
      
      @layer support {
        & .bar {
          min-block-size: 100%;
        }
      }
    }
  }
  
  
  /* 等效于下面的语法 */
  

  @layer base {
    .foo {
      block-size: 100%;
    }
  }
  
  @layer base.support {
    .foo .bar {
      min-block-size: 100%;
    }
  }

特异性权重

嵌套选择器的特异性是使用关联选择器列表中的最大特异性计算的。这与使用 :is() 函数时计算特异性的方式相同。

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <style type="text/css">
        #a, b {
          & c {
            /* 优先级权重 = (1,0,1) */
          }
        }

        .foo c {
          /* 优先级权重 = (0,1,1) */
        }
  
        /* 等效于下面的语法 */
  
        :is(#a, b) {
          & c {
            /* 优先级权重 = (1,0,1) */
          }
        }

        .foo c {
          /* 优先级权重 = (0,1,1) */
        }
      </style>
    </head>
    
    <body>
      <b class="foo">
        <c>Blue text</c>
      </b>
    </body>
  </html>

CSS 预处理器的优势还在吗?

  • CSS Nesting 原生嵌套语法,主流浏览器均已支持
  • CSS 自定义属性/变量,主流浏览器均已支持,详情
  • CSS Houdini 允许通过JS编程,相比 CSS-In-JS 更加出色,不过兼容性有待提高
  • CSS 原生有众多函数(如 clampcolor-mix)。虽然离 CSS 预处理器有距离,但越来越稳健。

也许不久的将来,我们可以完全不再依赖 CSS 预处理器,做到更好开发体验和效率。