Sacc @规则

102 阅读5分钟

@规则

在原生 CSS 中,存在一些 @ 开头的规则,例如 @import、@media,Sass 对这些 @ 规则完全支持,不仅支持,还在原有的基础上做了一些扩展。

@import

在原生的 CSS 里面,@import 是导入其他的 CSS 文件,Sass 再此基础上做了一些增强:

  1. 编译时合并:Sass 在编译时将导入的文件内容合并到生成的 CSS 文件中,这意味着只会生成一个 CSS 文件,而不是像原生 CSS 那样需要额外的 HTTP 请求去加载导入的文件。

  2. 变量、函数和混合体共享:Sass 允许在导入的文件之间共享变量、函数和混合体,这有助于组织代码并避免重复。

  3. 部分文件:Sass 支持将文件名前缀为 _ 的文件称为部分文件(partials)。当使用 @import 指令导入部分文件时,Sass 不会生成一个单独的 CSS 文件,而是将其内容合并到主文件中。这有助于更好地组织项目。

  4. 文件扩展名可选:在 Sass 中,使用 @import 指令时可以省略文件扩展名(.scss 或 .sass),Sass 会自动识别并导入正确的文件。

  5. 嵌套导入:Sass 允许在一个文件中嵌套导入其他文件,但请注意,嵌套导入的文件将在父级上下文中编译,这可能会导致输出的 CSS 文件中的选择器层级不符合预期。

接下来,我们来看一个具体的例子:

src/
  ├── _variable.scss
  ├── _mixins.scss
  ├── _header.scss
  └── index.scss
// _variable.scss
$primary-color: #007bff;
$secondary-color: #6c757d;
// _mixins.scss
@mixin reset-margin-padding {
    margin: 0;
    padding: 0;
}
// _header.scss
header {
    background-color: $primary-color;
    color: $secondary-color;
    @include reset-margin-padding;
}

可以看出,在 _header.scss 里面使用了另外两个 scss 所定义的变量以及混合体,说明变量、函数和混合体是可以共享的。

之后我们在 index.scss 里面导入了这三个 scss

@import "variable";
@import "mixins";
@import "header";

body{
  background-color: $primary-color;
  color: $secondary-color;
  @include reset-margin-padding;
}

最终生成的 css 如下:

header {
  background-color: #007bff;
  color: #6c757d;
  margin: 0;
  padding: 0;
}

body {
  background-color: #007bff;
  color: #6c757d;
  margin: 0;
  padding: 0;
}

最终只会生成一个 css。

通常情况下,我们在通过 @import 导入文件的时候,不给后缀名,会自动的寻找 sass 文件并将其导入。但是有一些情况下,会编译为普通的 CSS 语句,并不会导入任何文件:

  • 文件拓展名是 .css
  • 文件名以 http:// 开头;
  • 文件名是 url();
  • @import 包含 media queries

例如:

@import "foo.css"
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);

@media

这个规则在原生 CSS 里面是做媒体查询,Sass 里面是完全支持的,并且做了一些增强操作。

  1. Sass里面允许你讲 @media 嵌套在选择器内部
.navigation {
  display: flex;
  justify-content: flex-end;

  @media (max-width: 768px) {
    flex-direction: column;
  }
}
.navigation {
  display: flex;
  justify-content: flex-end;
}
@media (max-width: 768px) {
  .navigation {
    flex-direction: column;
  }
}
  1. 允许使用变量
$mobile-breakpoint: 768px;

.navigation {
  display: flex;
  justify-content: flex-end;

  @media (max-width: $mobile-breakpoint) {
    flex-direction: column;
  }
}
.navigation {
  display: flex;
  justify-content: flex-end;
}
@media (max-width: 768px) {
  .navigation {
    flex-direction: column;
  }
}
  1. 可以使用混合体
@mixin respond-to($breakpoint) {
  @if $breakpoint == "mobile" {
    @media (max-width: 768px) {
      @content;
    }
  } @else if $breakpoint == "tablet" {
    @media (min-width: 769px) and (max-width: 1024px) {
      @content;
    }
  } @else if $breakpoint == "desktop" {
    @media (min-width: 1025px) {
      @content;
    }
  }
}

.container{
  width: 80%;
  @include respond-to("mobile"){
    width: 100%;
  }
  @include respond-to("desktop"){
    width: 70%;
  }
}
.container {
  width: 80%;
}
@media (max-width: 768px) {
  .container {
    width: 100%;
  }
}
@media (min-width: 1025px) {
  .container {
    width: 70%;
  }
}

@extend

我们在书写 CSS 样式的时候,经常会遇到一种情况:一个元素使用的样式和另外一个元素基本相同,但是又增加了一些额外的样式。这个时候就可以使用继承。Sass里面提供了@extend规则来实现继承,让一个选择器能够继承另外一个选择器的样式规则。

.button {
  display: inline-block;
  padding: 20px;
  background-color: red;
  color: white;
}


.primary-button{
  @extend .button;
  background-color: blue;
}
.button, .primary-button {
  display: inline-block;
  padding: 20px;
  background-color: red;
  color: white;
}

.primary-button {
  background-color: blue;
}

如果是刚接触的同学,可能会觉得 @extend 和 @mixin 比较相似,感觉都是把公共的样式提取出来了,但是两者其实是不同的。

  • 参数支持:@mixin 支持传递参数,使其更具灵活性;而 @extend 不支持参数传递。
  • 生成的 CSS:@extend 会将选择器合并,生成更紧凑的 CSS,并且所继承的样式在最终生成的 CSS 样式中也是真实存在的;而 @mixin 会在每个 @include 处生成完整的 CSS 代码,做的就是一个简单的 CSS 替换。
  • 使用场景:@extend 更适用于继承已有样式的情况,例如 UI 框架中的通用样式;而 @mixin 更适用于需要自定义参数的情况,例如为不同组件生成类似的样式。

接下来我们来看一个复杂的例子:

.box {
  border: 1px #f00;
  background-color: #fdd;
}

.container {
  @extend .box;
  border-width: 3px;
}

.box.a{
  background-image: url("/image/abc.png");
}
.box, .container {
  border: 1px #f00;
  background-color: #fdd;
}

.container {
  border-width: 3px;
}

.box.a, .a.container {
  background-image: url("/image/abc.png");
}

在上面的代码中,container 是继承了 box 里面的所有样式,假设一个元素需要有 box 和 a 这两个类才能对应一段样式(abc),由于 box 类所对应的样式,如果是挂 container 这个类的话,这些样式也会有,所以一个元素如果挂了 container 和 a 这两个类,同样应该应用对应 abc 样式。

有些时候,我们需要定义一套用于继承的样式,不希望 Sass 单独编译输出,那么这种情况下就可以使用 % 作为占位符。

%button {
  display: inline-block;
  padding: 20px;
  background-color: red;
  color: white;
}


.primary-button{
  @extend %button;
  background-color: blue;
}

.secondary-button{
  @extend %button;
  background-color: pink;
}
.secondary-button, .primary-button {
  display: inline-block;
  padding: 20px;
  background-color: red;
  color: white;
}

.primary-button {
  background-color: blue;
}

.secondary-button {
  background-color: pink;
}

@at-root

有些时候,我们可能会涉及到将嵌套规则移动到根级别(声明的时候并没有写在根级别)。这个时候就可以使用 @at-root

.parent{
  color: red;

  @at-root .child{
    color: blue;
  }
}
.parent {
  color: red;
}
.child {
  color: blue;
}

如果你想要移动的是一组规则,这个时候需要在 @at-root 后面添加一对大括号,将想要移动的这一组样式放入到大括号里面

.parent {
  color: red;

  @at-root {
    .child {
      color: blue;
    }
    .test {
      color: pink;
    }
    .test2 {
      color: purple;
    }
  }
}
.parent {
  color: red;
}
.child {
  color: blue;
}

.test {
  color: pink;
}

.test2 {
  color: purple;
}

@debug、@warn、@error

这三个规则是和调试相关的,可以让我们在编译过程中输出一条信息,有助于调试和诊断代码中的问题。