前言:本文是对于,如何在 vue-cli3.x 创建的 vue 前端项目中使用 scss 的具体步骤和相关基础语法的相关总结 。


 sass 依赖包安装

// 推荐版本 :"sass": "^1.27.1","sass-loader": "8.0.0"
npm install --save-dev node-sass;
npm install --save-dev sass-loader;

sass 概念 ,特色功能,语法格式

  • 概念

sass: 是一款强化 css 的辅助工具,它在 css 语法的基础之上增加了变量(variables),嵌套(nested rules),混合(mixins),导入(inline imports) 等高级功能,这些扩展使 css 更加强大与优雅。使用 sass 以及 sass 的样式库(如 compass)有助于更好的组织管理样式文件,以及更高效的开发项目 。

  • 特色功能
  1. 完全兼容 css3 。
  2. 在 css 基础上增加了变量,嵌套,混合等功能 。
  3. 通过函数进行颜色值和属性值的运算 。
  4. 提供控制指令(control directives)等高级功能 。
  5. 自定义输出格式 。
  • 语法格式(sass 有两种语法格式)

scss(sassy css ),这种格式仅在 css3 语法的基础上扩展,所有 css3 语法在 scss 中都是通用的,同时加入 sass 的特色功能。Scss 也支持大多数 css hacks 写法以及浏览器前缀写法(vendor-specific syntax),以及早期的 ie 滤镜写法。 这种格式以 .scss 作为扩展名 。

sass 语法格式,被称为缩进格式(indented sass)通常称为 sass ,是一种简化格式。它使用缩进代替花括号,表示属性属于某个选择器,用换行代替分号,分隔属性,很多人认为这样做比 scss 更容易阅读,书写也更加快速。缩进格式也可以使用 sass 的全部功能,只是与 scss 相比个别地方采取了不同的表达方式,这种格式以 .sass 作为扩展名 。

任何一种格式可以直接导入 (@import) 到另一种格式中使用,或者通过 sass-convert 命令行工具转换为另一种格式 。

# Convert Sass to SCSS
$ sass-convert style.sass style.scss

# Convert SCSS to Sass
$ sass-convert style.scss style.sass

Sass 相关语法

  • 嵌套规则

sass 允许将一套 css 样式嵌套进另一套样式中,内层样式将它外层选择器作为父选择器 。

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

嵌套功能避免了重复输入父选择器,而且使复杂的 css 解构更易于管理 。

#main {
   width: 97%;
   p, div {
      font-size: 2em;
      a { font-weight: bold; }
   }
   pre { font-size: 3em; }
}
  • 父选择器 &

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

a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body.firefox & { font-weight: normal; }
}

编译后的 css 文件中 & 将被替换成嵌套外层的父选择器,如果含有多层嵌套,最外层的父选择器会一层层向下传递 。

#main {
  color: black;
  a {
       font-weight: bold;
       &:hover { color: red; }
    }
}

& 必须作为选择器的第一个字符,其后可以跟随后缀生成复合的选择器, 当父选择器含有不合适的后缀时,sass 将会报错 。

#main {
    color: black;
    &-sidebar { border: 1px solid; }
 }
  • 属性嵌套

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

.funky {
     font: {
         family: fantasy;
         size: 30em;
         weight: bold;
      }
  }

命名空间也可以包含自己的属性值 。

.funky {
     font: 20px/24px {
         family: fantasy;
         weight: bold;
     }
}
  • 占位符选择器 %

sass 提供了一种特殊类型的选择器:占位符选择器。与常用的 id 和 class 选择器写法相似。只是 # 或者 . 换成了 % 。必须通过 @extend 指令调用。当占位符选择器单独使用时(未通过 @extend 调用),不会编译到 css 文件中 。

  • 注释

sass 支持标准的 css 多行注释 /* */,以及单行注释 //,前者会 被完整输出到编译后的 css 文件中,而后者则不会 。 将  !  作为多行注释的第一个字符表示在压缩输出模式下保留这条注释并输出到 css 文件中, 通常用于添加版权信息。插值语句 (interpolation) 也可写进多行注释中输出变量值 。

/* 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; }
  • Interactive Shell

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

$ sass -i
 >> "Hello, Sassy World!"
 "Hello, Sassy World!"
 >> 1px + 1px + 1px
 3px
 >> #777 + #777
 #eeeeee
 >> #777 + #888
 white
  • 变量 $ (Variables: $)

sassScript 最普遍用法就是变量,变量以美元符号开头,赋值方法与 css 属性的写法一样 ,直接使用即调用变量 。

$width:5em;

 #main{
    width:$width;
 }

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

#main {
     $width: 5em !global;
     width: $width;
 }

 #sidebar {
       width: $width;
 }
  • 数据类型

sassScript 支持 7 种主要的数据类型 。

// 数字:
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)
  • 运算

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

width: 1em + (2em * 3);

圆括号可以用来影响运算的顺序 。

p {
    width: 1em + (2em * 3);
 }
  • 函数 (Functions)

sassScript 定义了多种函数,有些甚至可以通过普通的 css 语句调用 。

p {
     color: hsl(0, 100%, 50%);
  }

关键词参数,sass 函数允许使用关键词参数 (keyword arguments) 。

p {
     color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
 }
  • 插值语句 #{}

通过 #{} 插值语句可以在选择器或属性名中使用变量 。

$name: foo;
 $attr: border;
 p.#{$name} {
    #{$attr}-color: blue;
 }

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

p {
     $font-size: 12px;
     $line-height: 30px;
     font: #{$font-size}/#{$line-height};
 }
  • 变量定义 !default (默认值)

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

$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;

#main {
     content: $content;
     new-content: $new_content;
}

变量是 null 空值时将视为未被 !default 赋值 。

$content: null;
 $content: "Non-null content" !default;

 #main {
     content: $content;
 }
  • @import

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

// 导入单个文件
 @import "foo.scss";

 // 同时导入多个文件
 @import "rounded-corners", "text-shadow";
  • @media

 sass 中 @media 指令与 css 中用法一样,只是增加了一点额外的功能: 允许其在 css 规则中嵌套。如果 @media 嵌套在 css 规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器。 这个功能让 @media 用起来更方便,不需要重复使用选择器,也不会打乱 css 的书写流程 。

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

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

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

 @media 甚至可以使用变量,函数,以及运算符等代替条件的名称或者值 。

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

   @media #{$media} and ($feature: $value) {
      .sidebar {
          width: 500px;
       }
   }
  • @extend

将一个选择器下的所有样式继承给另一个选择器 。

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

@extend 的作用是将重复使用的样式 ,延伸 (extend)  给需要包含这个样式的特殊样式 。

.error {
      border: 1px #f00;
      background-color: #fdd;
  }
  .error.intrusion {
      background-image: url("/image/hacked.png");
  }
   .seriousError {
      @extend .error;
      border-width: 3px;
  }
  • @if

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

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

@if 声明后面可以跟多个 @else if 声明,或者一个 @else 声明。如果 @if 声明失败,sass 将逐条执行 @else if 声明,如果全部失败,最后执行 @else 声明 。

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

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

@for $i from 1 through 3 {
      .item-#{$i} { width: 2em * $i; }
  }
  • @each

@each 指令的格式是 $var in <list>, $var 可以是任何变量名,比如 $length 或者 $name,而<list> 是一连串的值,也就是值列表。@each 将变量 $var 作用于值列表中的每一个项目,然后输出结果 。

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

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

$i: 6;
@while $i > 0 {
   .item-#{$i} { width: 2em * $i; }
    $i: $i - 2;
}
  • 定义混合指令 @mixin

混合指令(mixin)用于定义可重复使用的样式,避免了使用无语意的 class,混合指令可以包含所有的 css 规则,绝大部分 sass 规则,甚至通过参数功能引入变量,输出多样化的样式 。 

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

  混合也需要包含选择器和属性,甚至可以用 & 引用父选择器 。

@mixin clearfix {
    display: inline-block;
    &:after {
       content: ".";
       display: block;
       height: 0;
       clear: both;
       visibility: hidden;
    }
    * html & { height: 1px }
 }
  • 引用混合样式 @include

@include 指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选)。

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

可以在最外层引用混合样式,不会直接定义属性,也可以不使用父选择器 。

@mixin silly-links {
     a {
          color: blue;
          background-color: red;
     }
 }
 @include silly-links;

混合样式中包含其他混合样式 。

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

参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候, 按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时, 按照参数的顺序,再将所赋的值对应写进括号 。

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

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

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

 sass 支持自定义函数,并能在任何属性值或 sass script 中使用 。

$grid-width: 40px;
  $gutter-width: 10px;

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

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