Sass 使用

Sass(Syntactically Awesome Stylesheets)是一种CSS预处理器,也是一种CSS扩展语言。

特色功能 (Features)

  • 完全兼容 CSS3
  • 在 CSS 基础上增加变量、嵌套 (nesting)、混合 (mixins) 等功能
  • 通过函数进行颜色值与属性值的运算
  • 提供控制指令 (control directives)等高级功能
  • 自定义输出格式

语法格式 (Syntax)

Sass有两种语法格式:

  1. SCSS (Sassy CSS):这种格式的文件以.scss为扩展名,它的语法完全兼容CSS,并且增加了Sass的新特性。

  2. 缩进语法(或简称"Sass"):这种格式的文件以.sass为扩展名,它使用缩进而不是大括号来分隔代码块,且属性定义时不使用冒号。


CSS 功能拓展 (CSS Extensions)

嵌套规则 (Nested Rules)

Sass 允许将一套 CSS 样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器,例如:

css 复制代码
// 嵌套功能避免了重复输入父选择器,而且令复杂的 CSS 结构更易于管理
#main p {
  color: #00ff00;
  width: 97%;

  .redbox {
    background-color: #ff0000;
    color: #000000;
  }
}


//编译为

#main p {
  color: #00ff00;
  width: 97%; }
  #main p .redbox {
    background-color: #ff0000;
    color: #000000; }

父选择器 & (Referencing Parent Selectors: &)

在嵌套 CSS 规则时,有时也需要直接使用嵌套外层的父选择器,例如,当给某个元素设定 hover 样式时,或者当 body 元素有某个 classname 时,可以用 & 代表嵌套规则外层的父选择器。

css 复制代码
// 编译后的 CSS 文件中 & 将被替换成嵌套外层的父选择器
a {
  font-weight: bold;
  text-decoration: none;
  &:hover { text-decoration: underline; }
  body.firefox & { font-weight: normal; }
}

// 编译为
a {
  font-weight: bold;
  text-decoration: none; }
  a:hover {
    text-decoration: underline; }
  body.firefox a {
    font-weight: normal; }


// 如果含有多层嵌套,最外层的父选择器会一层一层向下传递
#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; }
  }
}


//编译为
#main {
  color: black; }
  #main a {
    font-weight: bold; }
    #main a:hover {
      color: red; }


//& 必须作为选择器的第一个字符,其后可以跟随后缀生成复合的选择器
#main {
  color: black;
  &-sidebar { border: 1px solid; }
}

// 编译为
// 当父选择器含有不合适的后缀时,Sass 将会报错。
#main {
  color: black; }
  #main-sidebar {
    border: 1px solid; }

属性嵌套 (Nested Properties)

有些 CSS 属性遵循相同的命名空间 (namespace),比如 font-family, font-size, font-weight 都以 font 作为属性的命名空间。为了便于管理这样的属性,同时也为了避免了重复输入,Sass 允许将属性嵌套在命名空间中,例如:

css 复制代码
.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}
// 编译为
.funky {
  font-family: fantasy;
  font-size: 30em;
  font-weight: bold; }

// 命名空间也可以包含自己的属性值
.funky {
  font: 20px/24px {
    family: fantasy;
    weight: bold;
  }
}
// 编译为
.funky {
  font: 20px/24px;
    font-family: fantasy;
    font-weight: bold; }

占位符选择器 %foo (Placeholder Selectors: %foo)


注释 /* */// (Comments: /* */ and //)

Sass 支持标准的 CSS 多行注释 /* */,以及单行注释 //,前者会 被完整输出到编译后的 CSS 文件中,而后者则不会

css 复制代码
/* This comment is
 * several lines long.
 * since it uses the CSS comment syntax,
 * it will appear in the CSS output. */
body { color: black; }

// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }

// 编译为
/* This comment is
 * several lines long.
 * since it uses the CSS comment syntax,
 * it will appear in the CSS output. */
body {
  color: black; }

a {
  color: green; }

SassScript

SassScript 可作用于任何属性,允许属性使用变量、算数运算等额外功能。

Interactive Shell

Interactive Shell 可以在命令行中测试 SassScript 的功能。在命令行中输入 sass -i,然后输入想要测试的 SassScript 查看输出结果

css 复制代码
$ sass -i
>> "Hello, Sassy World!"
"Hello, Sassy World!"
>> 1px + 1px + 1px
3px
>> #777 + #777
#eeeeee
>> #777 + #888
white

变量 $ (Variables: $)

SassScript 最普遍的用法就是变量,变量以美元符号开头,赋值方法与 CSS 属性的写法一样

css 复制代码
$width: 5em;

#main {
  width: $width;
}

变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量则可在任何地方使用(全局变量)。将局部变量转换为全局变量可以添加 !global 声明

css 复制代码
#main {
  $width: 5em !global;
  width: $width;
}

#sidebar {
  width: $width;
}

// 编译为

#main {
  width: 5em;
}

#sidebar {
  width: 5em;
}

数据类型 (Data Types)

SassScript 支持 6 种主要的数据类型:

  • 数字,1, 2, 13, 10px
  • 字符串,有引号字符串与无引号字符串,"foo", 'bar', baz
  • 颜色,blue, #04a3f9, rgba(255,0,0,0.5)
  • 布尔型,true, false
  • 空值,null
  • 数组 (list),用空格或逗号作分隔符,1.5em 1em 0 2em, Helvetica, Arial, sans-serif
  • maps, 相当于 JavaScript 的 object,(key1: value1, key2: value2)

SassScript 也支持其他 CSS 属性值,比如 Unicode 字符集,或 !important 声明。然而Sass 不会特殊对待这些属性值,一律视为无引号字符串。

字符串 (Strings)

SassScript 支持 CSS 的两种字符串类型:有引号字符串 (quoted strings),如 "Lucida Grande" 'http://sass-lang.com';与无引号字符串 (unquoted strings),如 sans-serif bold,在编译 CSS 文件时不会改变其类型。只有一种情况例外,使用 #{} (interpolation) 时,有引号字符串将被编译为无引号字符串,这样便于在 mixin 中引用选择器名

css 复制代码
@mixin firefox-message($selector) {
  body.firefox #{$selector}:before {
    content: "Hi, Firefox users!";
  }
}
@include firefox-message(".header");

// 编译为

body.firefox .header:before {
  content: "Hi, Firefox users!"; }
数组 (Lists)

数组 (lists) 指 Sass 如何处理 CSS 中 margin: 10px 15px 0 0 或者 font-face: Helvetica, Arial, sans-serif 这样通过空格或者逗号分隔的一系列的值。事实上,独立的值也被视为数组 ------ 只包含一个值的数组。

nth 函数可以直接访问数组中的某一项;join 函数可以将多个数组连接在一起;append 函数可以在数组中添加新值;而 @each 指令能够遍历数组中的每一项。

运算 (Operations)

所有数据类型均支持相等运算 ==!=,此外,每种数据类型也有其各自支持的运算方式。

数字运算 (Number Operations)

SassScript 支持数字的加减乘除、取整等运算 (+, -, *, /, %),如果必要会在不同单位间转换值。

css 复制代码
p {
  width: 1in + 8pt;
}

// 编译为

p {
  width: 1.111in; }

如果需要使用变量,同时又要确保 / 不做除法运算而是完整地编译到 CSS 文件中,只需要用 #{} 插值语句将变量包裹。

css 复制代码
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}

// 编译为

p {
  font: 12px/30px; }
颜色值运算 (Color Operations)
css 复制代码
// 颜色值的运算是分段计算进行的,也就是分别计算红色,绿色,以及蓝色的值:

p {
  color: #010203 + #040506;
}
// 计算 01 + 04 = 05 02 + 05 = 07 03 + 06 = 09,然后编译为

p {
  color: #050709; }


p {
  color: #010203 * 2;
}
// 计算 01 * 2 = 02 02 * 2 = 04 03 * 2 = 06,然后编译为

p {
  color: #020406; }


p {
  color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
// 编译为

p {
  color: rgba(255, 255, 0, 0.75); }
字符串运算 (String Operations)
css 复制代码
// + 可用于连接字符串

p {
  cursor: e + -resize;
}
// 编译为

p {
  cursor: e-resize; }

// 注意,如果有引号字符串(位于 + 左侧)连接无引号字符串,运算结果是有引号的,相反,无引号字符串
// (位于 + 左侧)连接有引号字符串,运算结果则没有引号。

p:before {
  content: "Foo " + Bar;
  font-family: sans- + "serif";
}
// 编译为

p:before {
  content: "Foo Bar";
  font-family: sans-serif; }

// 在有引号的文本字符串中使用 #{} 插值语句可以添加动态的值:

p:before {
  content: "I ate #{5 + 10} pies!";
}
// 编译为

p:before {
  content: "I ate 15 pies!"; }
布尔运算 (Boolean Operations)

SassScript 支持布尔型的 and or 以及 not 运算。

数组运算 (List Operations)

数组不支持任何运算方式,只能使用 list functions 控制。

圆括号 (Parentheses)

css 复制代码
// 圆括号可以用来影响运算的顺序:

p {
  width: 1em + (2em * 3);
}
// 编译为

p {
  width: 7em; }

函数 (Functions)

css 复制代码
// SassScript 定义了多种函数,有些甚至可以通过普通的 CSS 语句调用:

p {
  color: hsl(0, 100%, 50%);
}
// 编译为

p {
  color: #ff0000; }

插值语句 #{} (Interpolation: #{})

css 复制代码
// 通过 #{} 插值语句可以在选择器或属性名中使用变量:

$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}
// 编译为

p.foo {
  border-color: blue; }

// #{} 插值语句也可以在属性值中插入 SassScript,大多数情况下,这样可能还不如使用变量方便,但是使
// 用 #{} 可以避免 Sass 运行运算表达式,直接编译 CSS。

p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}
// 编译为

p {
  font: 12px/30px; }

变量定义 !default (Variable Defaults: !default)

可以在变量的结尾添加 !default 给一个未通过 !default 声明赋值的变量赋值,此时,如果变量已经被赋值,不会再被重新赋值,但是如果变量还没有被赋值,则会被赋予新的值

css 复制代码
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;

#main {
  content: $content;
  new-content: $new_content;
}
// 编译为

#main {
  content: "First content";
  new-content: "First time reference"; }

@-Rules 与指令 (@-Rules and Directives)

@import

Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。

css 复制代码
// Sass 将会试着寻找文件名相同,拓展名为 .scss 或 .sass 的文件并将其导入。

@import "foo.scss";

// 或

@import "foo";

// 都会导入文件 foo.scss,但是

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

// 编译为

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

// Sass 允许同时导入多个文件,例如同时导入 rounded-corners 与 text-shadow 两个文件:

@import "rounded-corners", "text-shadow";

// 导入文件也可以使用 #{ } 插值语句,但不是通过变量动态导入 Sass 文件,只能作用于 CSS 的 url() // 导入方式:

$family: unquote("Droid+Sans");
@import url("http://fonts.googleapis.com/css?family=\#{$family}");

// 编译为

@import url("http://fonts.googleapis.com/css?family=Droid+Sans");
分音 (Partials)

如果需要导入 SCSS 或者 Sass 文件,但又不希望将其编译为 CSS,只需要在文件名前添加下划线,这样会告诉 Sass 不要编译这些文件,但导入语句中却不需要添加下划线。

css 复制代码
// 例如,将文件命名为 _colors.scss,便不会编译 _colours.css 文件。

@import "colors";
// 上面的例子,导入的其实是 _colors.scss 文件
// 注意,不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。
嵌套 @import
css 复制代码
// 假设 example.scss 文件包含以下样式:

.example {
  color: red;
}

// 然后导入到 #main 样式内

#main {
  @import "example";
}

// 将会被编译为

#main .example {
  color: red;
}

// 不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import。

@media

css 复制代码
.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}

// 编译为

.sidebar {
  width: 300px; }
  @media screen and (orientation: landscape) {
    .sidebar {
      width: 500px; } }

// @media 的 queries 允许互相嵌套使用,编译时,Sass 自动添加 and

@media screen {
  .sidebar {
    @media (orientation: landscape) {
      width: 500px;
    }
  }
}

// 编译为

@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px; } }


// @media 甚至可以使用 SassScript(比如变量,函数,以及运算符)代替条件的名称或者值:

$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;

@media #{$media} and ($feature: $value) {
  .sidebar {
    width: 500px;
  }
}
// 编译为

@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
  .sidebar {
    width: 500px; } }

@extend

使用 @extend 可以告诉 Sass 将一个选择器下的所有样式继承给另一个选择器。

css 复制代码
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

控制指令 (Control Directives)

SassScript 提供了一些基础的控制指令,比如在满足一定条件时引用样式,或者设定范围重复输出格式。控制指令是一种高级功能,日常编写过程中并不常用到,主要与混合指令 (mixin) 配合使用,尤其是用在 Compass 等样式库中。

@if

@if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码

css 复制代码
p {
  @if 1 + 1 == 2 { border: 1px solid; }
  @if 5 < 3 { border: 2px dotted; }
  @if null  { border: 3px double; }
}

// 编译为

p {
  border: 1px solid; }

$type: monster;
p {
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else if $type == monster {
    color: green;
  } @else {
    color: black;
  }
}

// 编译为

p {
  color: green; }

@for

@for 指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包含两种格式:@for $var from <start> through <end>,或者 @for $var from <start> to <end>,区别在于 throughto 的含义:当使用 through 时,条件范围包含 <start><end> 的值,而使用 to 时条件范围只包含 <start> 的值不包含 <end> 的值 。另外,$var 可以是任何变量,比如 $i<start><end> 必须是整数值。

css 复制代码
@for $i from 1 through 3 {
  .item-#{$i} { width: 2em * $i; }
}

// 编译为

.item-1 {
  width: 2em; }
.item-2 {
  width: 4em; }
.item-3 {
  width: 6em; }

@each

@each 指令的格式是 $var in <list>, $var 可以是任何变量名,比如 $length 或者 $name,而 <list> 是一连串的值,也就是值列表。

@each 将变量 $var 作用于值列表中的每一个项目,然后输出结果

css 复制代码
@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

// 编译为

.puma-icon {
  background-image: url('/images/puma.png'); }
.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); }
.egret-icon {
  background-image: url('/images/egret.png'); }
.salamander-icon {
  background-image: url('/images/salamander.png'); }

@while

@while 指令重复输出格式直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环,只是很少会用到。

css 复制代码
$i: 6;
@while $i > 0 {
  .item-#{$i} { width: 2em * $i; }
  $i: $i - 2;
}
.item-6 {
  width: 12em; }

.item-4 {
  width: 8em; }

.item-2 {
  width: 4em; }

混合指令 (Mixin Directives)

定义混合指令 @mixin (Defining a Mixin: @mixin)

混合指令的用法是在 @mixin 后添加名称与样式

css 复制代码
// 比如名为 large-text 的混合通过下面的代码定义:

@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}

引用混合样式 @include (Including a Mixin: @include)

css 复制代码
// 使用 @include 指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选):

.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

// 编译为

.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px; }

// 混合样式中也可以包含其他混合样式,比如

@mixin compound {
  @include highlighted-background;
  @include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }

参数 (Arguments)

css 复制代码
@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue, 1in); }

// 编译为

p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed; }

// 混合指令也可以使用给变量赋值的方法给参数设定默认值,然后,当这个指令被引用的时候,如果没有给参数
// 赋值,则自动使用默认值:

@mixin sexy-border($color, $width: 1in) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue); }
h1 { @include sexy-border(blue, 2in); }

// 编译为

p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed; }

h1 {
  border-color: blue;
  border-width: 2in;
  border-style: dashed; }


// 参数变量 (Variable Arguments)
@mixin box-shadow($shadows...) {
  -moz-box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
  box-shadow: $shadows;
}
.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

// 编译为

.shadowed {
  -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

函数指令 (Function Directives)

css 复制代码
$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar { width: grid-width(5); }

// 编译为

#sidebar {
  width: 240px; }

输出格式 (Output Style)

:nested

Nested (嵌套)样式是 Sass 默认的输出格式,能够清晰反映 CSS 与 HTML 的结构关系

css 复制代码
#main {
  color: #fff;
  background-color: #000; }
  #main p {
    width: 10em; }

.huge {
  font-size: 10em;
  font-weight: bold;
  text-decoration: underline; }

:expanded

Expanded 输出更像是手写的样式,选择器、属性等各占用一行,属性根据选择器缩进,而选择器不做任何缩进。

css 复制代码
#main {
  color: #fff;
  background-color: #000;
}
#main p {
  width: 10em;
}

.huge {
  font-size: 10em;
  font-weight: bold;
  text-decoration: underline;
}

:compact

Compact 输出方式比起上面两种占用的空间更少,每条 CSS 规则只占一行,包含其下的所有属性。嵌套过的选择器在输出时没有空行,不嵌套的选择器会输出空白行作为分隔符。

css 复制代码
#main { color: #fff; background-color: #000; }
#main p { width: 10em; }

.huge { font-size: 10em; font-weight: bold; text-decoration: underline; }

:compressed

Compressed 输出方式删除所有无意义的空格、空白行、以及注释,力求将文件体积压缩到最小,同时也会做出其他调整,比如会自动替换占用空间最小的颜色表达方式。

css 复制代码
#main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline}
相关推荐
To_OC4 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic4 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy4 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志5 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble6 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯7 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜7 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司7 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
kaiking_g8 小时前
vue项目中,静态导入 vs 动态导入 详解
前端·javascript·vue.js
江华森8 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http