51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

CSS Nesting嵌套与@scope规则也太雷同了吧?


封面占位图

一、居然还有个CSS嵌套

年前有介绍CSS @scope规则,可以实现CSS的选择器内外嵌套,简化选择器的书写:

@scope(nav) {
  ul {
    list-style: none;
    padding: 0;margin: 0;
  }
  li {
    display: inline-block;
  }
  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
    background: skyblue;
  }
}

最近发现,几乎同一时间,现代浏览器还支持了专门用来嵌套书写的CSS Nesting语法,借鉴自Sass/Less/Stylus等预编译语言。

使用示意:

nav {
  ul {
    list-style: none;
    padding: 0; margin: 0;
  }
  li {
    display: inline-block;
  }
  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
    background: skyblue;
  }
}

可以看到和@scope(nav)的语法极为相似,所实现的效果也是一样的,假设有如下所示的HTML代码:

<nav>
  <ul>
    <li><a href="">链接1</a></li>
    <li><a href="">链接2</a></li>
    <li><a href="">链接3</a></li>
  </ul>
</nav>
<p><a>我呢?</a></p>

可以看到,nav元素内的链接有背景色等样式,外部的a元素则依然是默认样式。

嵌套样式渲染效果

并且两种写法的选择器的优先级也是一样的。

以a元素为说明对象,两种写法的选择器优先级均等同于 nav a

这就让我陷入了深深的沉思......为什么要弄两套规则如此相似的东西呢?

二、@scope和Nesting的不同

在我看来,CSS Nesting就是纯粹的语法糖,也就是就是纯粹的语法上的变化,本身并不具备任何新的特性。

@scope则不一样,@scope规则中想要生效的选择器,一定属于@scope的子元素,带有"局部上下文"的性质在里面。

我们可以通过一个例子感受下两者的不同。

假设有两个无需列表<ul>元素:

<ul>
  <li>列表1</li>
  <li>列表2</li>
  <li>列表3</li>
</ul>
<ul>
  <li>列表2-1</li>
  <li>列表2-2</li>
  <li>列表2-3</li>
</ul>

那么,@scope规则中使用:scope伪类(表示ul元素自身)和兄弟选择器,是无法匹配后面的ul元素的。

@scope(ul) {
  :scope + ul {
    color: red;
    font-weight: bold;
  }
}

此时,所有的列表文字样式都是默认状态,如下图所示:

列表样式效果

但若是换成CSS嵌套写法(使用&符号表示祖先选择器):

ul {
  & + ul {
    color: red;
    font-weight: bold;
  }
}

则可以看到后面一个<ul>列表的文字均是红色加粗:

红色加粗

由于CSS Nesting语法中的&符号就是纯粹的选择器替代,因此,上面的CSS写作这样效果也是一样的:

ul {
  & + & {
    color: red;
    font-weight: bold;
  }
}

区别2:完整CSS规则和随意嵌套

如果使用@scope语法,那么,规则中的每一行代码,都应该属于一个完整的规则,而不能是某一条单独的CSS声明。

例如,下面的写法会让整段CSS规则无效:

@scope(ul) {
  border: 1px solid;  
li {
color: red;
font-weight: bold;
}
}

但是CSS原生的嵌套语法都没有此顾虑,直接上:

ul {
  border: 1px solid;  
li {
color: red;
}
}

可以得到如下截图所示效果,列表有边框,文字是红色:

列表边框和颜色

三、不同规则见的相互嵌套?

首先,CSS @scope范围和CSS Nesting嵌套是可以同时使用的,例如:

@scope(body) {
  ul {
    border: 1px solid;
    li {
      color: red;
    }
  }
}

同样可以让列表出现边框,内容颜色是红色。

列表边框和颜色

两种特性都支持和其他@规则互相嵌套。

CSS @scope范围可以嵌套其他@scope范围,例如下面的写法是合法的:

@scope(body) {
  ul {
    border: 1px solid;
  }
@scope(li) {
:scope {
color: red;
}
}
}

也支持和@media媒体查询一起使用,例如:

@scope(ul) {
  :scope {
    border: 1px solid;
  }
@media(width < 640px) {
li {
color: red;
}
}
}

和这段代码:

ul {
  & {
    border: 1px solid;
  }
@media(width < 640px) {
li {
color: red;
}
}
}

均可以在窄屏下让列表文字颜色红色,如下图所示:

列表边框和颜色

四、究竟什么时候用哪个?

什么时候用范围,什么使用用嵌套呢?

我琢磨了下,似乎绝大多数场景两者是可以随意替换的。

思来想去,总感觉最大的区别反而是语义上的区别。

你如果仅仅是想让书写更加简洁,代码更加装逼,使用嵌套。

如果是单独的某个组件的开发,使用范围。

这么一想,心里舒服多了。

好了,就扯这么多吧,如果你有其他想法,欢迎评论交流。

???

(本篇完)

赞(0)
未经允许不得转载:工具盒子 » CSS Nesting嵌套与@scope规则也太雷同了吧?