CSS预处理器之:SCSS

1,433 阅读12分钟

世界上最成熟、最稳定、最强大的专业级CSS扩展语言!

  1. 兼容CSS: Sass完全兼容所有版本的CSS。我们对此严格把控,所以你可以无缝地使用任何可用的CSS库。
  2. 特性丰富: Sass拥有比其他任何CSS扩展语言更多的功能和特性。Sass核心团队不懈努力,一直使其保持领先地位。
  3. 成熟: Sass已经经过其核心团队超过13年的精心打造。
  4. 行业认可: 一次又一次地,行业把Sass作为首选CSS扩展语言。
  5. 社区庞大: 数家科技企业和成百上千名开发者为Sass提供支持。
  6. 框架:有无数的框架使用Sass构建。比如Compass,Bourbon,和Susy。

安装和编译

SASS 支持多种语言: ruby/node-sass/dart-sass

# npm
yarn global add sass
# Windows (Chocolatey)
choco install sass
# Mac OS X (Homebrew)
brew install sass/sass/sass

另外也有图形化的编译工具 (GUI):

调试

CSS 调试与其他的编译类型一样使用 source-map。

sass --sourcemap a.scss:a.css

输出方式

sass 支持 4 中输出方式:嵌套输出方式 - nested / 展开输出方式 - expanded / 紧凑输出方式 - compact / 压缩输出方式 - compressed

div {
  margin: 20px;
  background: red;
  .bav {
    padding: 20px;
    height: 40px;
    background: blue;
  }
}

嵌套输出方式 - nested

# node 8.x node-sass 4.9.3
node-sass --output-style nested test.scss > ./test.css

结果

div {
  margin: 20px;
  background: red; }
  div .bav {
    padding: 20px;
    height: 40px;
    background: blue; }

展开输出方式 - expanded

# node 8.x node-sass 4.9.3
node-sass --output-style expanded test.scss > ./test.css

结果

div {
  margin: 20px;
  background: red;
}

div .bav {
  padding: 20px;
  height: 40px;
  background: blue;
}

紧凑输出方式 - compact

# node 8.x node-sass 4.9.3
node-sass --output-style compact test.scss > ./test.css
div { margin: 20px; background: red; }

div .bav { padding: 20px; height: 40px; background: blue; }

压缩输出方式 - compressed

# node 8.x node-sass 4.9.3
node-sass --output-style compressed test.scss > ./test.css
div{margin:20px;background:red}div .bav{padding:20px;height:40px;background:blue}

变量

1. 变量

SASS 中的变量使用 $ 开头,表示变量声明,变量的赋值使用 :

2. 普通变量

$bg: red;
div {
  background: $bg;
}
// 编译结果
div {
  background: red;
}

3. 默认值变量

$bg: red;
$bg: blue !default;
div {
  background: $bg;
  .bav {
    background: $bg;
  }
}
// 编译结果
div {
  background: red;
}

div.bav {
  background: red;
}

默认值的价值: 组件开发时默认值只起到了初始化的作用,后可以根据实际情况重新赋值。

4. 局部变量

div {
  $bg: teal;
  $bg: yellow !default;
  margin: 20px;
  background: $bg;
  .bav {
    padding: 20px;
    height: 40px;
    background: $bg;
  }
}

以括号为分界,只能在 yellow 内部使用。

5. 全局变量

一般会有一个专门的保存全局变量的文件,一般的命名是 var.scss, 在需要的时候使用。

// var.scss
$bg-color: #fff;
// other

选择器嵌套

为了良好的 CSS 表述结构,SCSS 中支持了选择器嵌套。嵌套与 html 的结构息息相关。

1. 选择器嵌套

<div class="abc">
  <span class="inr">this is inner</span>
</div>

对应的 scss 嵌套写法

.abc {
  background: red;
  .inr {
    color: blue;
  }
}

2. 选择器属性嵌套

.abc {
  background: red;
  .inr {
    color: blue;
    font-size: 20px;
  }
}

属性也是可以嵌套的,编译的规则是以 {} 为界限,

3. 伪类嵌套

.abc {
  background: red;
  .inr:hover {
    color: blue;
    font-size: 20px;
  }
}
.abc {
  background: red;
}

.abc .inr:hover {
  color: blue;
  font-size: 20px;
}

4. 伪元素嵌套

.abc {
  background: red;
  .inr::after {
    content: '';
    position: 'absolute';
    color: blue;
    font-size: 20px;
  }
}
.abcd {
  background: red;
}

.abcd .inrs::after {
  content: '';
  position: 'absolute';
  color: blue;
  font-size: 20px;
}

混合宏

变量的能做的事情是很有限的,更何谈 scss 的代码复用的问题,这个时候 sass 就需要引入其他的特性,在编程世界里,mixins 是一种很常见的设计模式,在 sass 中同样也引入了混入,来解决 scss 代码复用的问题。

1. 声明宏

声明一个混入(也就是混合宏)需要使用指令 @mixins,比如我们有下面一段代码要复用, 使用 sass 混合宏 可以这么写

@mixins my-first-scss-mixins {
  background-color: red;
}

2. 调用宏

上面简单的说明了混合宏的定义,定义之后使用方法如下:

div {
  @include my-first-scss-mixins()
}

就如同上面的例子使用 @include 来调用数据。

3. 宏参数

混入宏的参数是可选的, 带有参数的混入宏需要在宏名后添加 ()

@mixins my-first-scss-mixins($color) {
  background-color: $color;
}

// usage
div {
  @include my-first-scss-mixins(red)
}

这里的要理解一点, 我们可能是使用其他的语言的,这里传入的参数 red 就是一个普通的 sass 字符串,不是 sass 变量,因为 sass 中的变量需要使用 $ 来声明。

上面的宏是一个特别简单的混合宏,其实混合宏参数是可以带默认值的,看虾米你的的例子:

// 默认值
@mixins my-first-scss-mixins($color: 'red') {
  background-color: $color;
}

混合宏可以很复杂,与 sass 的其他特性一起使用,能完成一些更为复杂的功能,解决更为复杂的代码复用问题。

多参数的使用如下:

// 默认值
@mixins my-first-scss-mixins($color: 'red', $textSize: 24px) {
  background-color: $color;
  font-size: $textSize;
}

混入解决css代码的复用问题,但是它也产生了新的问题,混入是在每一个需要它的地方混入指定的代码,正式因为每一个地方都混入相同的代码,使得重复代码随着混入的使用次数的增多会产生重复的代码。混入造成的重复可能是必要的。

4. 扩展和继承

扩展和集成是编程中的另一种思想,在面向对象的思想中用的尤为多。在 scss 中继承使用: @extend 指令完成:

.div {
  position: relative;
  top: 0;
}

.div .nav {
  background: red;
  width: 2px;
  @extend .div
}

继承指令 @extend 继承的是一个 scss 的选择器类, 同时继承没有混入宏的问题。继承会将具有相同代码的 CSS 选择器类全部单独的放在一起。

5. 占位符

占位符与继承的使用相似,有什么不同? 不同点在于占位符只是具有占位的作用,不会真实的存在,只有完成了继承之后才会存在继承类的属性当中,占位符属性不会被编译。

%myph {
  padding: 20px;
}

%myphq {
  margin-top: 32px;
}

.el {
  @extend %myph;
  @extend %myphq;
}

占位符同样不会存在 mixins 重复代码的问题。

6. 插值 Interpolation

插值类似于 es6 中的模板字符串,写法都比较类似, 一般用具计算动态的 CSS 属性, 而属性值直接使用变量即可,例如:

@mixins inter($cssProperty, $cssValue) {
  #{$Interpolation}: $cssValue;
}

用于动态的计算 css class 名, 例如:

@mixins func($name, $color, $bg) {
  #{$name}-a {
    color: $color;
  }
  #{$name}-bg {
    background: $bg;
  }
}

插值的本质是创建一个加了引号的字符串。例如:

$number: 123;
div {
  padding: #{$number}px
}
// 结果
.div2 {
  padding: 123px;
}

从结果来看是能够获取相同的结果的,但是本质上是不同的数据结构。

与占位符一起使用

%abc-a {
  padding: 123px;
  background: red;
}
%abc-b {
  color: red;
  font-size: 24px;
}

.div {
  $testA: a;
  $testB: b;
  .div.el {
    @extend %abc-#{$testA};
    @extend %abc-#{$testB};
  }
}

总结起来占位符可以使用的位置

  1. 选择器名
  2. 属性名
  3. 占位符名

数据类型

1. 字符串类型

类似于其他语言可使用 string 模块, sass 的模块的使用方法, string 模块对外暴露的一些方法

  • unquote
  • quote
  • index
  • slice
  • ...
@use "sass: string";

$hover: string.unquote(".div4");
$hover-hover: string.quote(.div5);

转义 Escapes

@debug "\""; // '"'
@debug \.widget; // \.widget
@debug "\a"; // "\a" (a string containing only a newline)
@debug "line1\a line2"; // "line1\a line2"
@debug "Nat + Liz \1F46D"; // "Nat + Liz 👭"

使用字符串

@debug "Helvetica Neue"; // "Helvetica Neue"
@debug "C:\\Program Files"; // "C:\\Program Files"
@debug "\"Don't Fear the Reaper\""; // "\"Don't Fear the Reaper\""
@debug "line1\a line2"; // "line1\a line2"

$roboto-variant: "Mono";
@debug "Roboto #{$roboto-variant}"; // "Roboto Mono"

字符串索引

1. 基本用法

@use "sass:string";

@debug string.index("Helvetica Neue", "Helvetica"); // 1
@debug string.index("Helvetica Neue", "Neue"); // 11
@debug string.slice("Roboto Mono", -4); // "Mono"

2. 数字类型

  • SASS 中的数字包含两个部分:数字本身和单位。
  • SASS 支持科学计数法
  • 单位

单位 Units

首先要明确一点,在我们编写 SCSS 代码的时候,一般不会用到复杂的单位(因为 CSS 不支持复杂的单位),但是我们应该知道复杂单位的规则:

  1. 复杂的单位,在进行乘除运算时,单位也同样进行进行乘除运算形成复杂的 SCSS 单位, 例如:
// 乘除运算
$one: 2px / 4px;
$two: 2px / 4s;

div {
  padding: $one;
  margin: $two; //  0.5px/s isn't a valid CSS value.\n
}

有一个特点:计算出的复杂的单位必须是 CSS 能够识别的,否则,编译器是会报错的。

  1. 加减运算

单位直接能互相转换的单位,能进行运行,编译器是不会报错的,但是单位最终的归属问题取决 SCSS 被后是如何实现的。

// px 与 em 是不能兼容的,当然如果你这么做了,编译器会议错误的方式提示你:

$unitPlusDec: 1px + 3em;

.div1 {
  padding: $unitPlusDec; // Error: Incompatible units: 'rem' and 'px'
}

使用兼容单位进行运算:

$transition-speed: 1s/50px;

@mixin move($left-start, $left-stop) {
  position: absolute;
  left: $left-start;
  transition: left ($left-stop - $left-start) * $transition-speed;

  &:hover {
    left: $left-stop;
  }
}

.slider {
  @include move(10px, 120px);
}

特殊的百分比单位,百分比是单位,造成了在 SCSS 中不能将百分比与小数互相转换。

$percentage: 50%;
@debug $percentage / 100%; // 0.5 得到是一个小数

数字精度:

  • 支持到小数点后 10 位

3. 颜色值

  • 颜色名
  • 16进制 颜色值
  • rgb/rgba 颜色值
  • hsl/hsla 颜色值
  • sass 内置一些颜色函数...

来一些例子:

@debug #fffeee;
@debug #b37399aa;
@debug midnightblue;
@debug rgb(204, 102, 153);
@debug rgba(107, 113, 127, 0.8);
@debug hsl(228, 7%, 86%);
@debug hsla(20, 20%, 85%, 0.7);

// 函数的例子
$venus: #998099;

@debug scale-color($venus, $lightness: +15%); // #a893a8
@debug mix($venus, midnightblue); // #594d85

4. 布尔类型

  • true/false

集合 SCSS 其他的特性,配合其他特性:

@use "sass:math";

@debug 1px == 2px; //false
@debug 1px == 1px; //false
@debug 10px < 3px; // false
@debug math.comparable(100px, 3in);

@debug true and true; // true
@debug true and false; // false
@debug true or false; // true
@debug true or false; // false
@debug not true; //false
@debug not false; // true

// @if 指令
@mixins avater($size, $circle: false) {
  width: $size;
  height: $size;

  @if $circle {
    border-radius: $size / 2;
  }
}

.square-av { @include avatar(100px, $circle: false);}
.circle-av {@include avatar(100px. $circle: true);}

// if() 函数
@debug if(true, 10px, 30px);
@debug if(false, 10px, 30px);

5. null

该值null是其类型的唯一值。它表示缺少值,通常由函数返回以表示缺少结果。

@use "sass:map";
@use "sass:string";

@debug string.index("Helvetica Neue", "Roboto"); // null
@debug map.get(("large": 20px), "small"); // null
@debug &; //

$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas");
h3 {
  font: 18px bold map-get($font, "sans") // null 这个属性将在编译时被忽略
}

null 在 SCSS 中是假值 falsy。这意味着它对false所有采用布尔值的规则或运算符都算在内。这使得它易于使用的值,可以是null作为条件@if和if()。

@mixins app-bakground($color) {
  #{if (&, '&.app-background', '.app-background') {
    background-color: $color;
    color: rgba(#fff, 0.75);
  }}
}

@include app-background(#036)

6. map 映射类型

Map 的定义方法

  • (<key>: <value>, <key>: <value>)
  • key/value 都可以 expression
  • 为什么要使用 () 博包裹 key-value,而不使用 {}。很显然,编译器在编译 {} 需要判断是 scss Map 还是 css 属性 的开始,使用 () 可以避免这些问题。

读取 map 中值的方法:

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.get($font-weights, "medium"); // 500
@debug map.get($font-weights, "extra-bold"); // null

// 与循环一起使用
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f");

@each $name, $glyph in icons {
  .icon-#{$name}:before {
    display: inline-block;
    font-family: "Icon Font";
    content: $glyph;
  }
}

在 SCSS 中没有给我们提供很多的map功能,但是一个很重要的 merge 合并 map 相同:

@use "sass:map";
$list-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);

@debug map.merge($light-weight, $heavy-weights);

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.merge($font-weights, ("extra-bold": 900));
// ("regular": 400, "medium": 500, "bold": 700, "extra-bold": 900)

// 具有相同的值

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.merge($font-weights, ("medium": 600));
// ("regular": 400, "medium": 600, "bold": 700)

$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);

@mixins add-browser-perfix($browser, $prefix) {
  $prefixes-by-browser: map.merge($prefixes-by-browser, ($browser: $prefix));
}

@include add-browser-perfix("opera", o);
@debug $perfixes-by-brower;

7. list 列表

list 列表,也可理解为数组,和 JavaScript 数组一样

7.1 使用

Sass提供了一些功能,这些功能使您可以使用列表来编写功能强大的样式库,或者使应用程序的样式表更清洁,更可维护。

  1. 索引

通过索引,来检索 Sass 列表的值

  1. 访问元素
  • list.nth(list,n),获取指定列表,指定位置的索引值。
@debug list.nth(10px 12px 16px, 2); // 12px;
@debug list.nth([line1, line2, line3], -1); // line3
  1. 遍历列表

使用 @each 遍历列表

$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}
  1. 添加到列表

使用 list.append(list,val) 在列表末尾添加。

@debug append(10px 12px 16px, 25px); // 10px 12px 16px 25px
@debug append([col1-line1], col1-line2); // [col1-line1, col1-line2]
  1. 查找元素

使用 list.index(list,value) 获取指定索引。

@use "sass:list";

@debug list.index(1px solid red, 1px); // 1
@debug list.index(1px solid red, solid); // 2
@debug list.index(1px solid red, dashed); // null

@mixins attach($side) {
  @if not list.index($valid-sides, $side) {
    @error "#{$side} is not a valid side. Expected one of #{sides}"
  }
}
  1. 不变性

Sass中的列表是不可变的,这意味着列表值的内容永远不会改变。Sass的列表功能全部返回新列表,而不是修改原始列表。不变性有助于避免在样式表的不同部分共享同一列表时可能潜入的许多臭虫。

不过,您仍然可以通过将新列表分配给同一变量来随时更新状态。这通常在函数和mixin中使用,以将一堆值收集到一个列表中。

  1. 参数列表

当您声明接受任意参数的mixin或函数时,获得的值是一个称为参数列表的特殊列表。它的作用就像一个包含传递给混入或功能,一个额外的功能的所有参数列表:如果用户通过关键字参数,它们可以作为一个地图来访问相应的参数列表传递给meta.keywords()函数。

@use "sass:list";
@use "sass:map";

$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms);

@function prefixes-for-browsers($browsers) {
  $prefixes: ();
  @each $browser in $browsers {
    $prefixes: list.append($prefixes, map.get($prefixes-by-browser, $browser));
  }
  @return $prefixes;
}

@debug prefixes-for-browsers("firefox" "ie")

8. function 函数

Sass 流控制

1. 流控制指令

  1. @if-@else
  2. @each
  3. @for
  4. @while

Sass 规则

  1. @use
  2. @forward
  3. @mixins-@include
  4. @function
  5. @import
  6. @error
  7. @warn
  8. @media
  9. @extend

1. @use

2. @forward

3. @mixins-@include

4. @function

5. @import

6. @error

7. @warn

8. @media

9.@extend

10. @at-root

11. @debug

$color: red;

@debug "debug direction like JavaScript console.log or other language print function, next we will debug $color scss variable:; #{$color}"

@mixins inset-divider-offset($offset, $padding {
  $divider-offset: (2 * $padding) + $offset;
  @debug "devider offset: #$divider-offset}";

  margin-left: $divider-offset;
  width: calc(100% - #{$divider-offset});
})

在编译之后,就会在控制台中输出指定的内容。

运算

加减成除模

$width1: 20px;
$width2: 420px;

$wd: $width1 + $width2;
$wd1: $width2 - $width1;
$wd3: $width2 * $width1;
$wd3: $width2 / $width1;
$wd3: $width2 % $width1;

函数

函数与 sass 的数据类型基本对应。

内置模块

颜色模块 sass:color

color.adjust(
  <!-- 目标颜色 -->
  $color,

  <!-- rgb 颜色 -->
  $red: null, $green: null, $blue: null,

  <!-- hsl 颜色 -->
  $hue: null, $saturation: null, $lightness: null,

  <!-- 透明度 -->
  $alpha: null
  )

adjust-color() // color
  • color-scale()
  • color-change()
@debug color.adjust(#6b717f, $red: 15);
@debug color.adjust(#d2e1dd, $red: -10, $blue: 10);
@debug color.adjust(#998099, $lightness: -30%, $alpha: -0.4);
adjust-hue($color, $degrees);
color.alpha($color)
alpha($color)
opacity($color) //=> number
color.blue($color)
blue($color) //=> number 
color.change($color,
  $red: null, $green: null, $blue: null,
  $hue: null, $saturation: null, $lightness: null,
  $alpha: null)
change-color(...) //=> color 

暗度

darken($color, $amount) //=> color 

饱和度

desaturate($color, $amount) //=> color 

灰度

color.grayscale($color)
grayscale($color) //=> color 

绿色

color.green($color)
green($color) //=> number

色相

color.hue($color)
hue($color) //=> number

无引号的字符串

color.ie-hex-str($color)
ie-hex-str($color) //=> unquoted string

反值

color.invert($color, $weight: 100%)
invert($color, $weight: 100%) //=> color

亮度

lighten($color, $amount) //=> color

hsl 亮度

color.lightness($color)
lightness($color) //=> number

混合

color.mix($color1, $color2, $weight: 50%)
mix($color1, $color2, $weight: 50%) //=> color

透明度

opacify($color, $amount)
fade-in($color, $amount) //=> color

红色

color.red($color)
red($color) //=> number

饱和

saturate($color, $amount)
saturate($color, $amount) //=> color

hsl 饱和度

color.saturation($color)
saturation($color) //=> number

颜色缩放

color.scale($color,
  $red: null, $green: null, $blue: null,
  $saturation: null, $lightness: null,
  $alpha: null)
scale-color(...) //=> color

透明度

transparentize($color, $amount)
fade-out($color, $amount) //=> color 

sass:list

  1. 在列表中添加: append
list.append($list, $val, $separator: auto)
append($list, $val, $separator: auto) //=> list 
  1. 获取索引
list.index($list, $value)
index($list, $value) //=> number | null
  1. 是否是带有方括号的list
list.is-bracketed($list)
is-bracketed($list) //=> boolean
  1. join
list.join($list1, $list2, $separator: auto, $bracketed: auto)
join($list1, $list2, $separator: auto, $bracketed: auto) //=> list 
  1. 长度 length
list.length($list)
length($list) //=> number
  1. 分隔符
list.separator($list)
list-separator($list) //=> unquoted string 
  1. 索引位置元素
list.nth($list, $n)
nth($list, $n)
  1. 索引为$list的元素替换
list.set-nth($list, $n, $value)
set-nth($list, $n, $value) //=> list
  1. spring, expand
list.zip($lists...)
zip($lists...) //=> list

sass:map

map.get($map, $key);
map-get($map, $key);

map.has-key($map, $key);
map-has-key($map, $key); //=> boolean

map.key($map, $key)
map-has-key($map, $key) //=> boolean

map.merge($map1, $map2)
map-merge($map1, $map2) //=> map

map.remove($map, $keys...)
map-remove($map, $keys...) //=> map

map.values($map)
map-values($map) //=> list
  1. get
$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.get($font-weights, "medium"); // 500
@debug map.get($font-weights, "extra-bold"); // null
  1. has-key
$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.has-key($font-weights, "regular"); // true
@debug map.has-key($font-weights, "bolder"); // false
  1. key
$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.keys($font-weights); // "regular", "medium", "bold"
  1. merge
$light-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);

@debug map.merge($light-weights, $heavy-weights);
// (
//   "lightest": 100,
//   "light": 300,
//   "medium": 500,
//   "bold": 700
// )

// map.merge() can be used to add a single key/value pair to a map.
@debug map.merge($light-weights, ("lighter": 200));
// ("lightest": 100, "light": 300, "lighter": 200)

// It can also be used to overwrite a value in a map.
@debug map.merge($light-weights, ("light": 200));
// ("lightest": 100, "light": 200)
  1. remove
$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.remove($font-weights, "regular"); // ("medium": 500, "bold": 700)
@debug map.remove($font-weights, "regular", "bold"); // ("medium": 500)
@debug map.remove($font-weights, "bolder");
// ("regular": 400, "medium": 500, "bold": 700)
  1. values
$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.values($font-weights); // 400, 500, 700

数学模块 sass:math

// Variables
math.$e;

math.$pi;

// Bounding Functions
math.ceil($number);
ceil($number); //=> number

math.clamp($min, $number, $max); //=> number

math.floor($number);
floor($number); //=> number

math.max($number...);
max($number...); //=> number

math.min($number...);
min($number...); //=> number

math.round($number);
round($number); //=> number

// Distance Functions
math.abs($number);
abs($number); //=> number

math.hypot($number...); //=> number

// Exponential Functions
math.log($number, $base: null); //=> number

math.pow($base, $exponent) //=> number

math.sqrt($number) //=> number

// Trigonometric Functions
math.cos($number); //=> number
math.sin($number); //=> number
math.tan($number) //=> number
math.acos($number) //=> number
math.asin($number) //=> number
math.atan($number) //=> number
math.atan2($y, $x) //=> number

// permalinkUnit Functions
math.compatible($number1, $number2)
comparable($number1, $number2) //=> boolean

math.is-unitless($number)
unitless($number) //=> boolean

math.unit($number)
unit($number) //=> quoted string

// Other Functions
math.percentage($number)
percentage($number) //=> number

math.random($limit: null)
random($limit: null) //=> number

Variables

@debug math.$e; // 2.7182818285
@debug math.$pi; // 3.1415926536

permalinkBounding Functions

@debug math.ceil(4); // 4
@debug math.ceil(4.2); // 5
@debug math.ceil(4.9); // 5

@debug math.clamp(-1, 0, 1); // 0
@debug math.clamp(1px, -1px, 10px); // 1px
@debug math.clamp(-1in, 1cm, 10mm); // 10mm

@debug math.floor(4); // 4
@debug math.floor(4.2); // 4
@debug math.floor(4.9); // 4

@debug math.max(1px, 4px); // 4px

$widths: 50px, 30px, 100px;
@debug math.max($widths...); // 100px

@debug math.min(1px, 4px); // 1px

$widths: 50px, 30px, 100px;
@debug math.min($widths...); // 30px

@debug math.round(4); // 4
@debug math.round(4.2); // 4
@debug math.round(4.9); // 5

Distance Functions permalinkDistance Functions

@debug math.log(10); // 2.302585093
@debug math.log(10, 10); // 1

@debug math.pow(10, 2); // 100
@debug math.pow(100, 1/3); // 4.6415888336
@debug math.pow(5, -2); // 0.04

@debug math.sqrt(100); // 10
@debug math.sqrt(1/3); // 0.5773502692
@debug math.sqrt(-1); // NaN

@debug math.cos(100deg); // -0.1736481777
@debug math.cos(1rad); // 0.5403023059
@debug math.cos(1); // 0.5403023059

@debug math.sin(100deg); // 0.984807753
@debug math.sin(1rad); // 0.8414709848
@debug math.sin(1); // 0.8414709848

@debug math.tan(100deg); // -5.6712818196
@debug math.tan(1rad); // 1.5574077247
@debug math.tan(1); // 1.5574077247

@debug math.acos(0.5); // 60deg
@debug math.acos(2); // NaNdeg

@debug math.asin(0.5); // 30deg
@debug math.asin(2); // NaNdeg

@debug math.atan(10); // 84.2894068625deg

@debug math.atan2(-1, 1); // 135deg

Unit Functions

@debug math.compatible(2px, 1px); // true
@debug math.compatible(100px, 3em); // false
@debug math.compatible(10cm, 3mm); // true

@debug math.is-unitless(100); // true
@debug math.is-unitless(100px); // false

@debug math.unit(100); // ""
@debug math.unit(100px); // "px"
@debug math.unit(5px * 10px); // "px*px"
@debug math.unit(5px / 1s); // "px/s"

Other Functions

@debug math.percentage(0.2); // 20%
@debug math.percentage(100px / 50px); // 200%

@debug math.random(); // 0.2821251858
@debug math.random(); // 0.6221325814

@debug math.random(10); // 4
@debug math.random(10000); // 5373

sass:meta

Mixins

meta.load-css($url, $with: null)

Functions

meta.call($function, $args...);
call($function, $args...);

meta.content-exists();
content-exists(); //=> boolean

meta.feature-exists($feature);
feature-exists($feature); //=> boolean

meta.function-exists($name);
function-exists($name); //=> boolean

meta.get-function($name, $css: false, $module: null);
get-function($name, $css: false, $module: null); //=> function

meta.global-variable-exists($name, $module: null);
global-variable-exists($name, $module: null); //=> boolean

meta.inspect($value)
inspect($value) //=> unquoted string

meta.keywords($args)
keywords($args) //=> map

meta.keywords($args)
keywords($args) //=> map

meta.module-functions($module) //=> map

meta.module-variables($module) //=> map

meta.type-of($value)
type-of($value) //=> unquoted string

meta.variable-exists($name)
variable-exists($name) //=> boolean

load-css

// dark-theme/_code.scss
$border-contrast: false !default;

code {
  background-color: #6b717f;
  color: #d2e1dd;
  @if $border-contrast {
    border-color: #dadbdf;
  }
}

// style.scss
@use "sass:meta";

body.dark {
  @include meta.load-css("dark-theme/code",
      $with: ("border-contrast": true));
}

call

@use "sass:list";
@use "sass:meta";
@use "sass:string";

/// Return a copy of $list with all elements for which $condition returns `true`
/// removed.
@function remove-where($list, $condition) {
  $new-list: ();
  $separator: list.separator($list);
  @each $element in $list {
    @if not meta.call($condition, $element) {
      $new-list: list.append($new-list, $element, $separator: $separator);
    }
  }
  @return $new-list;
}

$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif;

content {
  @function contains-helvetica($string) {
    @return string.index($string, "Helvetica");
  }
  font-family: remove-where($fonts, meta.get-function("contains-helvetica"));
}

content-exists

@mixin debug-content-exists {
  @debug meta.content-exists();
  @content;
}

@include debug-content-exists; // false
@include debug-content-exists { // true
  // Content!
}

feature

@debug meta.feature-exists("at-error"); // true
@debug meta.feature-exists("unrecognized"); // false

function

@debug meta.function-exists("scale-color"); // true
@debug meta.function-exists("add"); // false

@function add($num1, $num2) {
  @return $num1 + $num2;
}
@debug meta.function-exists("add"); // true

get-function

@use "sass:list";
@use "sass:meta";
@use "sass:string";

/// Return a copy of $list with all elements for which $condition returns `true`
/// removed.
@function remove-where($list, $condition) {
  $new-list: ();
  $separator: list.separator($list);
  @each $element in $list {
    @if not meta.call($condition, $element) {
      $new-list: list.append($new-list, $element, $separator: $separator);
    }
  }
  @return $new-list;
}

$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif;

content {
  @function contains-helvetica($string) {
    @return string.index($string, "Helvetica");
  }
  font-family: remove-where($fonts, meta.get-function("contains-helvetica"));
}

global-variable

@debug meta.global-variable-exists("var1"); // false

$var1: value;
@debug meta.global-variable-exists("var1"); // true

h1 {
  // $var2 is local.
  $var2: value;
  @debug meta.global-variable-exists("var2"); // false
}

inspect

@debug meta.inspect(10px 20px 30px); // unquote("10px 20px 30px")
@debug meta.inspect(("width": 200px)); // unquote('("width": 200px)')
@debug meta.inspect(null); // unquote("null")
@debug meta.inspect("Helvetica"); // unquote('"Helvetica"')

keywords

@use "sass:meta";

@mixin syntax-colors($args...) {
  @debug meta.keywords($args);
  // (string: #080, comment: #800, variable: $60b)

  @each $name, $color in meta.keywords($args) {
    pre span.stx-#{$name} {
      color: $color;
    }
  }
}

@include syntax-colors(
  $string: #080,
  $comment: #800,
  $variable: #60b,
)

mixin

@debug meta.mixin-exists("shadow-none"); // false

@mixin shadow-none {
  box-shadow: none;
}

@debug meta.mixin-exists("shadow-none"); // true

module

// _functions.scss
@function pow($base, $exponent) {
  $result: 1;
  @for $_ from 1 through $exponent {
    $result: $result * $base;
  }
  @return $result;
}

@use "sass:map";
@use "sass:meta";

@use "functions";

@debug meta.module-functions("functions"); // ("pow": get-function("pow"))

@debug meta.call(map.get(meta.module-variables("functions"), "pow"), 3, 4); // 16

type-of

@debug meta.type-of(10px); // number
@debug meta.type-of(10px 20px 30px); // list
@debug meta.type-of(()); // list

variable

@debug meta.variable-exists("var1"); // false

$var1: value;
@debug meta.variable-exists("var1"); // true

h1 {
  // $var2 is local.
  $var2: value;
  @debug meta.variable-exists("var2"); // true
}

选择器模块 sass:selector

selector.is-superselector($super, $sub)
is-superselector($super, $sub) //=> boolean

selector.append($selectors...)
selector-append($selectors...) //=> selector

selector.extend($selector, $extendee, $extender)
selector-extend($selector, $extendee, $extender) //=> selector

selector.nest($selectors...)
selector-nest($selectors...) //=> selector

selector.nest($selectors...)
selector-nest($selectors...) //=> selector

selector.replace($selector, $original, $replacement)
selector-replace($selector, $original, $replacement) //=> selector

selector.unify($selector1, $selector2)
selector-unify($selector1, $selector2) //=> selector | null

selector.simple-selectors($selector)
simple-selectors($selector) //=> list
@debug ((unquote(".main") unquote("aside:hover")),
        (unquote(".sidebar") unquote("p")));
// .main aside:hover, .sidebar p

selector.is-superselector

@debug selector.is-superselector("a", "a.disabled"); // true
@debug selector.is-superselector("a.disabled", "a"); // false
@debug selector.is-superselector("a", "sidebar a"); // true
@debug selector.is-superselector("sidebar a", "a"); // false
@debug selector.is-superselector("a", "a"); // true

selector.append

@debug selector.append("a", ".disabled"); // a.disabled
@debug selector.append(".accordion", "__copy"); // .accordion__copy
@debug selector.append(".accordion", "__copy, __image");
// .accordion__copy, .accordion__image

selector.extend

@debug selector.extend("a.disabled", "a", ".link"); // a.disabled, .link.disabled
@debug selector.extend("a.disabled", "h1", "h2"); // a.disabled
@debug selector.extend(".guide .info", ".info", ".content nav.sidebar");
// .guide .info, .guide .content nav.sidebar, .content .guide nav.sidebar

selector.parse

@debug selector.nest("ul", "li"); // ul li
@debug selector.nest(".alert, .warning", "p"); // .alert p, .warning p
@debug selector.nest(".alert", "&:hover"); // .alert:hover
@debug selector.nest(".accordion", "&__copy"); // .accordion__copy

selector.replace

@debug selector.replace("a.disabled", "a", ".link"); // .link.disabled
@debug selector.replace("a.disabled", "h1", "h2"); // a.disabled
@debug selector.replace(".guide .info", ".info", ".content nav.sidebar");
// .guide .content nav.sidebar, .content .guide nav.sidebar

selector.unify

@debug selector.unify("a", ".disabled"); // a.disabled
@debug selector.unify("a.disabled", "a.outgoing"); // a.disabled.outgoing
@debug selector.unify("a", "h1"); // null
@debug selector.unify(".warning a", "main a"); // .warning main a, main .warning a

selector.simple-selector

@debug selector.simple-selectors("a.disabled"); // a, .disabled
@debug selector.simple-selectors("main.blog:after"); // main, .blog, :after

字符串模块 sass:string

// $string以带引号的字符串返回。
string.quote($string)
quote($string) //=> string

// 返回第一个指标的$substring中$string,或者null如果$string不包含  $substring。
string.index($string, $substring)
str-index($string, $substring) //=> number

// 传回的副本,$string其中$insert插入了$index。
string.insert($string, $insert, $index)
str-insert($string, $insert, $index) //=> string

// 返回中的字符数  $string。
string.length($string)
str-length($string) //=> number

// 返回$string从索引 开始到索引$start-at结束$end-at(包括两端)的切片。
string.slice($string, $start-at, $end-at: -1);
str-slice($string, $start-at, $end-at: -1); //=> string

// 返回的副本$string与ASCII字母转换为大写。
string.to-upper-case($string);
to-upper-case($string); //=> string

// 返回随机生成的不带引号的字符串,该字符串保证是有效的CSS标识符,并且在当前Sass编译中是唯一的。
string.unique-id()
unique-id() //=> string

// 返回$string为无引号的字符串。这可能会产生无效的CSS字符串,因此请谨慎使用。
string.unquote($string)
unquote($string) //=> string
// quote
@debug string.quote(Helvetica); // "Helvetica"
@debug string.quote("Helvetica"); // "Helvetica"

// index
@debug string.index("Helvetica Neue", "Helvetica"); // 1
@debug string.index("Helvetica Neue", "Neue"); // 11

// insert
@debug string.insert("Roboto Bold", " Mono", 7); // "Roboto Mono Bold"
@debug string.insert("Roboto Bold", " Mono", -6); // "Roboto Mono Bold"

// length
@debug string.length(bold); // 4
@debug string.index(""); // 0

// slice
@debug string.slice("Helvetica Neue", 11); // "Neue"
@debug string.slice("Helvetica Neue", 1, 3); // "Hel"
@debug string.slice("Helvetica Neue", 1, -6); // "Helvetica"

// upper
@debug string.to-upper-case("Bold"); // "BOLD"
@debug string.to-upper-case(sans-serif); // SANS-SERIF

// lower
@debug string.to-lower-case("Bold"); // "bold"
@debug string.to-lower-case(SANS-SERIF); // sans-serif

// id
@debug string.unique-id(); // uabtrnzug
@debug string.unique-id(); // u6w1b1def

// unquote
@debug string.unquote("Helvetica"); // Helvetica
@debug string.unquote(".widget:hover"); // .widget:hover

参考

  1. sass-lang
  2. Koala