Sass速通(二):嵌套与作用域

2021-09-26 11:35:38 浏览数 (1)

Sass 提供了嵌套的书写方式,用以简化选择器的书写,同时也带来了“作用域”。

嵌套

选择器嵌套

在 Sass 中,可以在父选择器中写子选择器,以嵌套的形式来表达关联的关系,这样做可以减少我们重复书写父选择器的工作量。

代码语言:javascript复制
#content {
  #article {
    h1 {
      color: red;
    }
    p {
      color: grey;
    }
  }
}

编译后

代码语言:javascript复制
#content #article h1 {
  color: red;
}
#content #article p {
  color: grey;
}

在编译时,Sass 会递归遍历所有嵌套关系,从最内层选择器开始,逐层在前面加上父选择器

父选择器 &

在 CSS 中,基本选择器分为以下几种:

  • ID 选择器,如 #id
  • 类选择器,如 .class
  • 标签选择器,如 div、p
  • 属性选择器,如 [lang='en']
  • 伪类选择器,如 a:hover、div:first-child
  • 伪元素选择器,如 p::before、p::after

其中,伪类和伪元素选择器需要与别的选择器复合使用,以确定是哪些元素的伪类或伪元素。而其它选择器也可以复合使用,如 div#id、div.class、div[lang='en'] 等。

Sass 为了在嵌套中更好地表达这些复合关系,提供了父选择器 &。

代码语言:javascript复制
div {
  content: '#{&}';      // 将 & 当做变量使用
  &#app { color: green; }
  &.app { color: blue; }
  &:hover { color: red; }
  &:first-child { color: grey; }
  &::before { content: ''; }
}

编译后

代码语言:javascript复制
div { content: "div"; }
div#app  { color: green; }
div.app  { color: blue; }
div:hover  { color: red; }
div:first-child  { color: grey; }
div::before  { content: ''; }

可以看到,如果把 & 当做变量使用,它被编译为了父选择器。 要注意的是,在复合选择器中,& 只能放在开头使用。

群组选择器

在 CSS 中,可以用逗号分隔多个选择器,形成一个群组。元素只要满足群组中任何一个选择器,都会使用群组对应的样式进行渲染,如

代码语言:javascript复制
a, span, label { 
    color: grey;
}

在 Sass 中,我们可以使用嵌套的形式来简写群组。

代码语言:javascript复制
.container {
  h1, h2, h3 { margin-bottom: .8em; }
}

nav, aside {
  a { color: blue; }
}

编译后

代码语言:javascript复制
.container h1, .container h2, .container h3 {
  margin-bottom: .8em;
}
nav a, aside a {
  color: blue;
}
组合选择器 >、 、~

组合选择器:

  • > 为子选择器,如 div > p,选中条件:
    1. 节点为 div 的邻层子节点
    2. 节点标签为 p
  • 为相邻兄弟选择器,如 div p,选中条件:
    1. 节点为 div 后面的第一个节点
    2. 节点标签为 p
  • ~ 为同层后续选择器,如 div ~ p,选中条件:
    1. 节点为 div 后面的同层节点
    2. 节点标签为 p

对于组合选择器,直接嵌套就可以了。

代码语言:javascript复制
article {
  ~ article { border-top: 1px dashed #ccc }
  > section { background: #eee }
  dl > {
    dt { color: #333 }
    dd { color: #555 }
  }
  nav   & { margin-top: 0 }
}

编译后

代码语言:javascript复制
article ~ article { border-top: 1px dashed #ccc }
article > footer { background: #eee }
article dl > dt { color: #333 }
article dl > dd { color: #555 }
nav   article { margin-top: 0 }

属性嵌套

除了可以嵌套书写选择器,还可以嵌套书写属性,如

代码语言:javascript复制
nav {
  border: {
  style: solid;
  width: 1px;
  color: #ccc;
  }
}

编译后

代码语言:javascript复制
nav {
  border-style: solid;
  border-width: 1px;
  border-color: #ccc;
}

作用域

Sass 引入了嵌套,出现了嵌套层级,自然也就有了“层级作用域”。

变量作用域

在 Sass 中,变量只能在它被声明的层级和子层级访问;如果一个变量在不同层级中被重复定义,在使用时会从下到上寻找最近的定义。这与 JS 中的函数作用域相似。

代码语言:javascript复制
.inner {
  $width: 10px;
  width: $width;
  p {
    width: $width / 2;
  }
}

编译后

代码语言:javascript复制
.inner { width: 10px; }
.inner p { width: 5px; }

如果变量仅在子级被定义,而在父级被访问,编译时会报错。

代码语言:javascript复制
Undefined variable: "$width".

@import

@import 是 CSS2 原生支持的指令,由于 CSS 只有在执行到这条指令时,才会去加载对应的文件,这样会导致页面闪烁和加载变慢,所以平时并不常用。

Sass 改进了这条指令,它会在编译时将导入的资源直接替换并插入指令所在的位置

因此,如果 @import 导入的资源位置在嵌套层级中,那么:

  • 资源中的变量只在当前层级中可用
  • 资源中的选择器在编译时会带上父级前缀
代码语言:javascript复制
// _source.scss
$width: 10px;
p {
    color: red;
    font-size: 14px;
}
代码语言:javascript复制
// index.scss
@import '_source';
$width: 20px;
.outer {
  width: $width;
  .inner {
    @import '_source';
    width: $width;
  }
}

编译后

代码语言:javascript复制
p { color: red; font-size: 14px; }

.outer { width: 20px; }
.outer .inner { width: 10px; }
.outer .inner p { color: red; font-size: 14px; }

在使用 @import 导入文件时,可以不写 .scss 或 .sass 后缀。

如果资源是作为专被引用的公共资源,规范的命名方法是在名称前加下划线。

以下几种情况,Sass 会将 @import 编译为原生的 CSS 指令:

  • 资源文件后缀为 .css
  • 资源以 URL 地址的形式导入
  • 资源以 CSS 的 url() 方法导入

@media

@media 是 CSS 原生支持的指令,用于查询设备媒体,以便做响应式布局。

Sass 对 @media 做了一些改进,允许我们在嵌套的过程中书写媒体查询和响应代码。在编译时, Sass 会把媒体查询编译到文件最外层,并为子选择器加上父选择器前缀。

代码语言:javascript复制
$media-prop: min-width;
$media-middle-width: 1200px;
$media-large-width: 1980px;
.container {
  .left {
    font-size: 12px;
    @media screen and ($media-prop: $media-middle-width) {
      font-size: 14px;
    }
  }
  .right {
    font-size: 14px;
    @media screen {
      @media ($media-prop: $media-middle-width) {
        font-size: 18px;
      }
      @media ($media-prop: $media-large-width) {
        font-size: 22px;
      }
    }
  }
}

编译后

代码语言:javascript复制
.container .left {
  font-size: 12px;
}
@media screen and (min-width: 1200px) {
  .container .left {
    font-size: 14px;
  }
}
.container .right {
  font-size: 14px;
}
@media screen and (min-width: 1200px) {
  .container .right {
    font-size: 18px;
  }
}
@media screen and (min-width: 1980px) {
  .container .right {
    font-size: 22px;
  }
}

使用 Sass 媒体查询的好处:

  • 以前使用原生 CSS 做响应式布局时,我们需要先写好不同的媒体查询区块,整理出元素在不同设备的特殊样式,然后写入对应的区块。一个元素的样式分散在不同的媒体查询中,维护起来比较麻烦。
  • 在 Sass 中,我们可以在写完一个元素的公共样式之后,直接在下面嵌套媒体查询,所有的响应代码和这个元素都写在同一块地方,维护起来非常方便。

0 人点赞