Sass 是什么

CSS 预处理器,它允许您使用变量,嵌套规则,混合,函数等,所有这些都使用完全 CSS 兼容的语法。Sass 有助于保持大型样式表的组织良好,并且可以轻松地在项目内和项目间共享设计。

安装

  1. npm install -g sass

Sass 编译

自动编译 Sass

  1. sass --watch sass:css

image.png

修改编译输出的 CSS 格式

Sass 编译输出的格式有四种:

  • nested(嵌套,默认格式)
  • compact(紧凑)
  • expanded(拓展)
  • compressed(压缩)

Sass 编译后的格式为拓展

  1. sass --watch sass:css --style expanded

编译后输出的代码:

  1. ul {
  2. font-size: 15px;
  3. }
  4. ul li {
  5. list-style: none;
  6. }

语法

SASS/SCSS

Sass 支持两种不同的语法,SCSS 和 SASS 。

SCSS 是 CSS 的超集,所有合法的 CSS,都是 SCSS 的语法。它不是严格的 CSS 超集。当 Sass 在样式表中遇到无效语法时,解析将失败,并且将向用户显示错误语法的位置及其原因。请注意,这与 CSS 不同,CSS 从大多数错误中恢复而不是立即失败。

  1. @mixin button-base() {
  2. @include typography(button);
  3. @include ripple-surface;
  4. @include ripple-radius-bounded;
  5. display: inline-flex;
  6. position: relative;
  7. height: $button-height;
  8. border: none;
  9. vertical-align: middle;
  10. &:hover { cursor: pointer; }
  11. &:disabled {
  12. color: $mdc-button-disabled-ink-color;
  13. cursor: default;
  14. pointer-events: none;
  15. }
  16. }

Sass 使用缩进语法,而不是花括号和分号。

  1. @mixin button-base()
  2. @include typography(button)
  3. @include ripple-surface
  4. @include ripple-radius-bounded
  5. display: inline-flex
  6. position: relative
  7. height: $button-height
  8. border: none
  9. vertical-align: middle
  10. &:hover
  11. cursor: pointer
  12. &:disabled
  13. color: $mdc-button-disabled-ink-color
  14. cursor: default
  15. pointer-events: none

注释

SCSS

  1. /*
  2. * 多行注释会被保留,在压缩输出时不会保留。
  3. */
  4. /*!
  5. * 强制注释,一直保留在 CSS 里。
  6. */
  7. // 不会出现在编译后的 CSS 中。

文档注释

使用 Sass 编写样式库时,可以使用注释来记录 库提供的 mixins,function,变量和占位符选择器,以及库本身。这些注释由 SassDoc 工具读取,它使用它们生成漂亮的文档。

文档注释是静默注释,在需要注释正上方写三个斜杠 /// 。SassDoc 将注释中的文本解析为 Markdown,并支持许多有用的注释来详细描述它。

  1. /// 幂运算
  2. ///
  3. /// @param {number} $base
  4. /// 基数
  5. /// @param {integer (unitless)} $exponent
  6. /// 指数
  7. /// @return {number} `$base` to the power of `$exponent`.
  8. @function pow($base, $exponent) {
  9. $result: 1;
  10. @for $_ from 1 through $exponent {
  11. $result: $result * $base;
  12. }
  13. @return $result;
  14. }

特殊功能

CSS 定义了许多函数,大多数函数都可以使用 Sass 的普通函数语法。它们被解析为函数调用,解析为纯 CSS 函数,并按原样编译为 CSS。但是有一些特殊的语法,不能仅被解析为 SassScript 表达式。所有特殊函数调用都返回不带引号的字符串。

url()

如果 url() 参数为不带引号的 URL,则 Sass 原样解析它。

  1. $roboto-font-path: "../fonts/roboto";
  2. @font-face {
  3. // 这将被解析为一个普通的函数调用,它接受一个带引号的字符串
  4. src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
  5. font-family: "Roboto";
  6. font-weight: 100;
  7. }
  8. @font-face {
  9. // 这被解析为一个普通的函数调用,它接受一个算术表达式
  10. src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
  11. font-family: "Roboto";
  12. font-weight: 300;
  13. }
  14. @font-face {
  15. // 解析为特殊的插入函数
  16. src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
  17. font-family: "Roboto";
  18. font-weight: 400;
  19. }

calc()、element()、progid:…()、expression()

progid:…(),expression() 在新版浏览器被废弃,Sass 为了向下兼容解析。calc()、element() 在 CSS 规范中
,需要特殊解析。

  1. .logo {
  2. $width: 800px;
  3. width: $width;
  4. position: absolute;
  5. left: calc(50% - #{$width / 2});
  6. top: 0;
  7. }

min()、max()

  1. $padding: 12px;
  2. .post {
  3. // 在插值解析后直接编译为 CSS
  4. padding-left: max(#{$padding}, env(safe-area-inset-left));
  5. padding-right: max(#{$padding}, env(safe-area-inset-right));
  6. }
  7. .sidebar {
  8. // 在插值解析后直接编译为 CSS
  9. padding-left: max($padding, 20px);
  10. padding-right: max($padding, 20px);
  11. }

样式规则

概述

样式规则是 Sass 的基础,就像它们用于CSS一样,它们的工作方式相同。

  1. .button {
  2. padding: 3px 10px;
  3. font-size: 12px;
  4. border-radius: 3px;
  5. border: 1px solid #e1e4e8;
  6. }

嵌套

Sass 让你编写更少的代码。您可以在另一个内部编写一个样式规则,而不是一遍又一遍地重复相同的选择器。Sass 会自动将外部规则的选择器与内部规则组合在一起。

  1. nav {
  2. ul {
  3. margin: 0;
  4. padding: 0;
  5. list-style: none;
  6. }
  7. li { display: inline-block; }
  8. a {
  9. display: block;
  10. padding: 6px 12px;
  11. text-decoration: none;
  12. }
  13. }

⚠️注意

嵌套规则非常有用,但难以直观地显示您实际生成的 CSS 数量。嵌套越深,提供 CSS 所需的代码就越多,浏览器渲染它所需的工作就越多。要注意嵌套的层次不要太深!

选择器列表

嵌套规则很聪明地处理选择器列表(即逗号分隔的选择器)。每个复杂选择器(逗号之间的选择器)分别嵌套,然后将它们组合回选择器列表。

  1. .alert, .warning {
  2. ul, p {
  3. margin-right: 0;
  4. margin-left: 0;
  5. padding-bottom: 0;
  6. }
  7. }

选择器组合器

您也可以嵌套使用组合子选择器。您可以将组合子选择器放在外部选择器的末尾,内部选择器的开头,或者甚至是两者之间。

  1. ul > {
  2. li {
  3. list-style-type: none;
  4. }
  5. }
  6. h2 {
  7. + p {
  8. border-top: 1px solid gray;
  9. }
  10. }
  11. p {
  12. ~ {
  13. span {
  14. opacity: 0.8;
  15. }
  16. }
  17. }

插值

您可以使用插值将变量和函数调用等表达式中的值注入选择器。这在您编写 mixins 时特别有用,因为它允许您根据用户传入的参数创建选择器。

  1. @mixin define-emoji($name, $glyph) {
  2. span.emoji-#{$name} {
  3. font-family: IconFont;
  4. font-variant: normal;
  5. font-weight: normal;
  6. content: $glyph;
  7. }
  8. }
  9. @include define-emoji("women-holding-hands", "👭");

💡有趣的事实

Sass 仅解析插值后解析选择器。这意味着您可以安全地使用插值生成选择器的任何部分,而不必担心它不会解析。
您可以将插值与父选择器 &@at-root 规则和选择器功能结合使用,以在动态生成选择器时发挥一些强大的功能。

属性声明

声明的值可以是任何 SassScript 表达式,它将被评估并包含在结果中。

  1. .circle {
  2. $size: 100px;
  3. width: $size;
  4. height: $size;
  5. border-radius: $size / 2;
  6. }

插值

属性的名称可以包含插值,这使得可以根据需要动态生成属性。您甚至可以插入整个属性名称!

  1. @mixin prefix($property, $value, $prefixes) {
  2. @each $prefix in $prefixes {
  3. -#{$prefix}-#{$property}: $value;
  4. }
  5. #{$property}: $value;
  6. }
  7. .gray {
  8. @include prefix(filter, grayscale(50%), moz webkit);
  9. }

嵌套

许多 CSS 属性以相同的前缀开头,作为一种命名空间。例如 font-familyfont-sizefont-weight 所有的开始 font-。通过允许嵌套属性声明,Sass 使这更容易,更少冗余。外部属性名称被添加到内部,由连字符分隔。

  1. .enlarge {
  2. font-size: 14px;
  3. transition: {
  4. property: font-size;
  5. duration: 4s;
  6. delay: 2s;
  7. }
  8. &:hover { font-size: 36px; }
  9. }

其中一些 CSS 属性具有使用命名空间作为属性名称的简写版本。对于这些,您可以编写速记值和更明确的嵌套版本。

  1. .info-page {
  2. margin: auto {
  3. bottom: 10px;
  4. top: 2px;
  5. }
  6. }

隐藏的声明

有时你只想要一些属性声明出现在某些时候。如果声明的值是 null 或者是一个空的不带引号的字符串,Sass 根本不会将该声明编译为 CSS。

  1. $rounded-corners: false;
  2. .button {
  3. border: 1px solid black;
  4. border-radius: if($rounded-corners, 5px, null);
  5. }

自定义属性

CSS 自定义属性(也称为 CSS 变量)具有不同寻常的声明语法:它们在声明值中几乎允许任何文本。更重要的是,JavaScript 可以访问这些值,因此任何值都可能与用户相关。这包括通常被解析为 SassScript 的值。

因此,Sass 以不同于其他属性声明的方式解析自定义属性声明。所有令牌,包括那些看起来像 SassScript 的令牌,都按原样传递给 CSS。唯一的例外是插值,这是将动态值注入自定义属性的唯一方法。

  1. $primary: #81899b;
  2. $accent: #302e24;
  3. $warn: #dfa612;
  4. :root {
  5. --primary: #{$primary};
  6. --accent: #{$accent};
  7. --warn: #{$warn};
  8. // Even though this looks like a Sass variable, it's valid CSS so it's not
  9. // evaluated.
  10. --consumed-by-js: $primary;
  11. }

⚠️注意

不幸的是,插值会从字符串中删除引号,这使得当它们来自 Sass 变量时,很难将引用的字符串用作自定义属性的值。作为解决方法,您可以使用该 inspect() 函数来保留引号。

  1. $font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
  2. $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;
  3. :root {
  4. --font-family-sans-serif: #{inspect($font-family-sans-serif)};
  5. --font-family-monospace: #{inspect($font-family-monospace)};
  6. }

父选择器

当在内部选择器中使用父选择器时,它将替换为相应的外部选择器。

  1. .alert {
  2. &:hover {
  3. font-weight: bold;
  4. }
  5. [dir=rtl] & {
  6. margin-left: 0;
  7. margin-right: 10px;
  8. }
  9. :not(&) {
  10. opacity: 0.8;
  11. }
  12. }

添加后缀

您还可以使用父选择器向外部选择器添加额外的后缀。当使用像 BEM 这样使用高度结构化类名的方法时,这尤其有用。只要外部选择器以字母数字名称(如类,ID和元素选择器)结尾,就可以使用父选择器追加其他文本。

  1. .accordion {
  2. max-width: 600px;
  3. margin: 4rem auto;
  4. width: 90%;
  5. font-family: "Raleway", sans-serif;
  6. background: #f4f4f4;
  7. &__copy {
  8. display: none;
  9. padding: 1rem 1.5rem 2rem 1.5rem;
  10. color: gray;
  11. line-height: 1.6;
  12. font-size: 14px;
  13. font-weight: 500;
  14. &--open {
  15. display: block;
  16. }
  17. }
  18. }

在 SassScript 中

如果 & 表达式在任何样式规则之外使用,则返回 null。由于 null 是假,这意味着您可以轻松地使用它来确定是否在样式规则中调用 mixin。

  1. @mixin app-background($color) {
  2. #{if(&, '&.app-background', '.app-background')} {
  3. background-color: $color;
  4. color: rgba(#fff, 0.75);
  5. }
  6. }
  7. @include app-background(#036);
  8. .sidebar {
  9. @include app-background(#c6538c);
  10. }

高级嵌套

您可以将其 & 用作普通的 SassScript 表达式,这意味着您可以将其传递给函数或将其包含在插值中 - 即使在其他选择器中也是如此!将它与选择器功能和 @at-root 规则结合使用,可以以非常强大的方式嵌套选择器。

例如,假设您要编写与外部选择器和元素选择器匹配的选择器。你可以写一个像这样的 mixin,它使用该 selector-unify() 函数 & 与用户的选择器结合。

  1. @mixin unify-parent($child) {
  2. @at-root #{selector-unify(&, $child)} {
  3. @content;
  4. }
  5. }
  6. .wrapper .field {
  7. @include unify-parent("input") {
  8. /* ... */
  9. }
  10. @include unify-parent("select") {
  11. /* ... */
  12. }
  13. }

⚠️注意

当 Sass 嵌套选择器时,它不知道使用什么插值来生成它们。这意味着即使您用作 &SassScript 表达式,它也会自动将外部选择器添加到内部选择器。这就是为什么你需要明确地使用 @at-root 规则来告诉 Sass 不要包含外部选择器。

占位符选择器

占位符选择器不会被编译为 CSS

  1. .alert:hover, %strong-alert {
  2. font-weight: bold;
  3. }
  4. %strong-alert:hover {
  5. color: red;
  6. }

它一般和继承 @extend 一起使用

  1. %toolbelt {
  2. box-sizing: border-box;
  3. border-top: 1px rgba(#000, .12) solid;
  4. padding: 16px 0;
  5. width: 100%;
  6. &:hover { border: 2px rgba(#000, .5) solid; }
  7. }
  8. .action-buttons {
  9. @extend %toolbelt;
  10. color: #4285f4;
  11. }
  12. .reset-buttons {
  13. @extend %toolbelt;
  14. color: #cddc39;
  15. }

参考

【1】Sass 官网文档