用了这么久的scss语法写css,发现有许多知识点是我之前一直没用上的,现在又看了看,发现...... 可恶啊原来还能这么方便的,所以我在这里就正式的学一下scss的语法和技巧吧!!

# 介绍文档:

单文件编译可以在下面的网站进行操作

  • 中文文档:https://www.sass.hk
  • 英文文档:https://sass-lang.com/documentation
  • CSSScss:https://www.sass.hk/css2sass
  • ScssCSS:https://www.sassmeister.com

首先,我发现每次在新项目使用scss的时候,比如vue3中常写<style setup lang="scss"></style>,这多顺手,然后就要安装npm install sass --save-dev这个才能使用,但是呢我发现我用的不是scss吗?怎么怎么用的是sass的命令呢?欸这个就下面展开说说啦

你要知道不仅js有框架,css也是有框架的,像sass就是其中的一种

而SCSS 是 Sass 的一种语法格式,也就是第三代的sass,本质上需要安装的是 sass 编译器


# 监听运行:

如果是单页面比如.scss的,要转换成css才能被页面编译,操作命令:执行后就不用关,你后面改scss代码的时候会自动更新css的

sass --watch style.scss:style.css # 这样就会将scss的文件转换成css

当然你也可以在vscode上安装一个插件Live Sass Compiler

配置如下:

"liveSassCompile.settings":{
        "generateMap":false,
        "formats":[
            {
                "format": "expanded",
                "savePath": "~/css/",
            }
        ]
}

还有一些输出的规则

sass --watch style.scss:style.css --style compressed

# :nested

nestedscss默认的输出格式,选择器与属性等单独占用一行,缩进量与 scss文件中一致,每行的缩进量反映了其在嵌套规则内的层数

#main {
  color: #fff;
  background-color: #000; }
  #main p {
    width: 10em; }
 
.p {
  font-size: 10em;
  font-weight: bold;
  text-decoration: underline; }

# :expanded

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

#main {
  color: #fff;
  background-color: #000;
}
#main p {
  width: 10em;
}
 
.p {
  font-size: 10em;
  font-weight: bold;
  text-decoration: underline;
}

# :compact

compact会将每条 css 规则归纳为一行。嵌套过的选择器在输出时没有空行,不嵌套的选择器会输出空白行作为分隔符。

#main { color: #fff; background-color: #000; }
#main p { width: 10em; }
 
.p { font-size: 10em; font-weight: bold; text-decoration: underline; }

# :compressed

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

#main{color:#fff;background-color:#000}#main p{width:10em}.p{font-size:10em;font-weight:bold;text-decoration:underline}

# 语法嵌套

# 选择器嵌套

反正css中重复写选择器非常烦人,而且那个选择器的逻辑很难理清楚,嵌套太深就很难避免重复的选择器,一直写看得都麻

scss的选择器嵌套可以避免重复输入父选择器,可以有效的提高开发效率

然后呢我也是只用了scss这个功能哈哈哈服了,以为自己会了

这个是正常的css结构

.container {
    width: 1200px;
    margin: 0 auto;
}
.container .header .img {
    width: 100px;
    height: 60px;

编译成scss的样子,子元素向父元素内部嵌套了。

.container {
    width: 1200px;
    margin: 0 auto;
    .header {
        .img {
            width: 100px;
            height: 60px;
        }
    }
}

# 属性嵌套

有些css属性遵循相同的命名空间 (相同的开头),比如font-familyfont-sizefont-weight都以font作为属性的命名空间

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

编译成css

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

# 父选择器&

在嵌套 css规则时,有时会需要使用嵌套外层的父选择器,例如,当给某个元素设定 hover 样式时,可以用& 代表嵌套规则外层的父选择器,scss在编译时会把&替换成父选择器名

.container {
    a {
        color: #333;
        &:hover {
             text-decoration: underline;
             color: #f00;
        }
    }
}

转化成scss

.container a {
    color:#333;
}
.container a:hover {
    text-decoration:underline;
    color:#F00;
}

换个思路,也可以使用&进行选择器名称拼接。

.main {
    color: black;
    &-sidebar { border: 1px solid; }
}

然后scss有两种注释的方法,爱用那种用哪种,但是一般用//

# scss变量

原生css中的变量,使用--变量名:变量值定义,var(--变量名)进行使用

:root {
    --color: #F00;
}
p {
    color: var(--color);
}

scss中的变量,以美元符号$开头,赋值方法与 css属性的写法一样

$color:#F00;
p {
    color: $color;
}

# 5条变量规则

下文的mixinfunction命名也遵循1234条规则:

  1. 变量以美元符号$开头,后面跟变量名;
  2. 变量名是不以数字开头的可包含字母、数字、下划线、横线(连接符);
  3. 通过连接符-与下划线_定义的同名变量为同一变量;
  4. 变量一定要先定义,后使用;
  5. 写法同css,即变量名和值之间用冒号:分隔;

# 2种变量作用域

  1. 变量作用域分为全局变量域局部变量域
  • 全局变量:声明在最外层的变量,可在任何地方使用;
  • 局部变量:嵌套规则内定义的变量只能在嵌套规则内使用。

将局部变量转换为全局变量可以添加!global 声明。

# 7种主要的数据类型

scss支持7种主要的数据类型:

  1. 数字,1rem、2vh、13、 10px
  2. 字符串,分有引号字符串与无引号字符串,"foo"、 'bar'、baz
  3. 颜色,blue, #04a3f9, rgba(255,0,0,0.5)
  4. 布尔型,truefalse
  5. 空值,null是其类型的唯一值。表示缺少值,通常由函数返回以表示缺少结果;
  6. 数组 (list),用空格或逗号作分隔符,1.5em 1em 0 2em,Helvetica,Arial,sans-serif
  7. maps, 相当于 JavaScriptobject(key1: value1, key2: value2)

# !default

可以在变量的结尾添加!default来给变量设置默认值,有点类似Javascript的逻辑运算符let content=content || "Second content"。注意,变量是 null时将视为未被!default赋值。

# 圆括号

圆括号()可以用来影响运算的顺序,和数学中的效果是一致的。

运算符

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

# 关系运算符

四个关系运算符< > >= <=

布尔运行符

三个布尔运算符and or not

# 数字操作符

+ - * / %

css中有分隔数字的用途,在scss中,以下三种情况会进行除法运算:

  1. 如果值或值的一部分,是变量或者函数的返回值;
  2. 如果值被圆括号包裹;
  3. 如果值是算数表达式的一部分。
$width: 1000px;
div {
    font: 16px/30px Arial, Helvetica, sans-serif; // 不运算
    width: ($width/2); // 使用变量与括号
    width: (#{$width}/2); // 使用 #{} 插值语句将变量包裹,避免运算。
    z-index: round(10)/2; // 使用了函数
    height: (500px/2); // 使用了括号
    margin-left: 5px + 8px/2px; // 使用了+表达式
}

编译成css

div {
    font: 16px/30px Arial, Helvetica, sans-serif;
    width: 500px;
    width: 1000px/2;
    z-index: 5;
    height: 250px;
    margin-left: 9px;
}

# 字符串运算

  1. +可用于连接字符串;
  2. 如果有引号字符串(位于 + 左侧)连接无引号字符串,运算结果是有引号的;
  3. 无引号字符串(位于 + 左侧)连接有引号字符串,运算结果则没有引号。
.container {
    content: "Foo " + Bar;
    font-family: sans- + "serif";
}

# 插值语句

文章上面有讲到插值语句,这里来解释一下。 通过 #{} 插值语句可以在选择器、属性名、注释中使用变量,使用#{}插值语句将变量包裹起来即可,和js中的模板字符串很像

$font-size: 12px;
$line-height: 30px;
$class-name: danger;
$attr: color;
$author: "福大命大";
 
p {
    font: #{$font-size}/#{$line-height} Arial Helvetica, sans-serif;
}
 
/* 
* 这是文件的说明部分
* @author: #{$author}
*/
 
a.#{$class-name} {
    border-#{$attr}: #f00;
}

# 流程控制

sass中流程控制包含四类,也是我们在js中常见的@if、@for、@each、@while

# @if

@if语法和js类似,基本格式是@if...@else if...@else

使用

$theme:3;
.container {
    @if $theme >= 5 {
        background-color: red;
    }
    @else {
        background-color: blue;
    }
}

编译为css

.container {
    background-color: blue;
}

# @for

for在条件范围内重复操作,这个指令包含两种格式:

  1. @for $var from <start> through <end>
  2. @for $var from <start> to <end>

两者区别在于 throughto的含义:

  1. 使用 through时,条件范围包含 <start><end>的值;
  2. 使用 to时条件范围只包含<start>的值不包含<end>的值;
  3. $var 可以是任何变量,比如$i<start><end> 必须是整数值。
@for $i from 1 to 3 {
  #loading span:nth-child(#{$i}) {
      width: 20 * ($i - 1) + px;
  }
}

编译为

#loading span:nth-child(1) {
    width: 0px;
}
 
#loading span:nth-child(2) {
    width: 20px;
}

# @each

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

$color-list:red green blue turquoise darkmagenta;
@each $color in $color-list {
    $index: index($color-list, $color);
    .p#{$index - 1} {
        background-color: $color;
    }
}

编译为

.p0 {
    background-color: red;
}
 
.p1 {
    background-color: green;
}
 
.p2 {
    background-color: blue;
}
 
.p3 {
    background-color: turquoise;
}
 
.p4 {
    background-color: darkmagenta;
}

# @while

@while 指令循环输出直到表达式返回结果为 false。这样可以实现比@for 更复杂的循环。

比如,可以借此生成栅格化布局。

$column:12;
@while $column>0 {
   .col-sm-#{$column} {
      width: $column / 12 * 100%;
   }
    $column:$column - 1;
}

编译为

.col-sm-12 {
    width: 100%;
}
 
.col-sm-11 {
    width: 91.6666666667%;
}
 
.col-sm-10 {
    width: 83.3333333333%;
}
 
.col-sm-9 {
    width: 75%;
}
 
.col-sm-8 {
    width: 66.6666666667%;
}
 
.col-sm-7 {
    width: 58.3333333333%;
}
 
.col-sm-6 {
    width: 50%;
}
 
.col-sm-5 {
    width: 41.6666666667%;
}
 
.col-sm-4 {
    width: 33.3333333333%;
}
 
.col-sm-3 {
    width: 25%;
}
 
.col-sm-2 {
    width: 16.6666666667%;
}
 
.col-sm-1 {
    width: 8.3333333333%;
}

# @import

使用

common.scss

$color:red;

index.scss

@import "common.scss";
.container {
    border-color: $color;
}

编译成

.container {
  border-color: red;
}

以下情况下,@import 仅作为普通的css语句,不会导入scss文件:

  1. 文件拓展名是.css
  2. 文件名以 http://开头;
  3. 文件名是url()
  4. @import包含媒体查询。
@import "common.css";
@import url(common);
@import "http://xxx.com/xxx";
@import 'landscape' screen and (orientation:landscape);

scss允许同时导入多个文件,例如同时导入 rounded-cornerstext-shadow 两个文件,不用再单独写个import引入。

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

导入文件也可以使用 #{} 插值语句

如果需要导入 scss或者 sass文件,但又不希望将其编译为 css,只需要在文件名前添加下划线,这样会告诉 scss不要编译这些文件。注意:

  1. 导入语句中却不需要添加下划线;
  2. 不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。

# @Partials

Partials主要是用来定义公共样式的,专门用于被其他的 scss文件 import进行使用的。

# 嵌套@import

大多数情况下,一般在文件的最外层(不在嵌套规则内)使用@import,其实,也可以将@import 嵌套进内层选择器或者 @media 中,与平时的用法效果相同,只是这样导入的样式只能出现在嵌套的层中,存在作用域

common.scss

.example {
    color: red;
}

index.scss

#main {
    @import "example";
}

被编译成

#main .example {
    color: red;
}

注意:@import不能嵌套使用在控制指令或混入中(带有@符号的叫指令)

# @media 媒体查询增强

scss中,@media 指令与 css中用法一样,只是增加了一点额外的功能,允许在css规则中嵌套。

如果@media 嵌套在 css规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器。

使用

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

编译为

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

# 嵌套

@media允许互相嵌套使用,编译时,scss自动添加 and

# @mixin

混合指令(Mixin)用于定义可重复使用的样式。混合指令可以包含所有的css规则,绝大部分 scss规则,甚至可以通过参数功能引入变量,输出多样化的样式。有点像函数吧

注意:函数命名和变量命名规则一致。

使用

   @mixin mixin-name() {
       /* css 声明 */
   }
   // 使用
   @include mixin-name;

标准形式

// 定义一个区块基本的样式
@mixin block {
    width: 96%;
    margin-left: 2%;
    border-radius: 8px;
    border: 1px #f6f6f6 solid;
}
// 使用混入 
.container {
    .block {
        @include block;
    }
}

# 嵌入选择器


@mixin warning-text {
    font-size: 12px;
    .warn-text {
        color: rgb(255, 253, 123);
        line-height: 180%;
    }
}
 
.container {
    @include warning-text;

# 单参数

// 定义flex布局元素纵轴的排列方式
@mixin flex-align($aitem) {
    align-items: $aitem;
}
 
// 只有一个参数,直接传递参数
.container {
    @include flex-align(center);
}

# 多参数

// 定义块元素内边距
@mixin block-padding($top, $right, $bottom, $left) {
    padding-top: $top;
    padding-right: $right;
    padding-bottom: $bottom;
    padding-left: $left;
}
 
// 按照参数顺序赋值
.container1 {
   @include block-padding(10px, 20px, 30px, 40px);
}
 
// 可指定参数赋值
.container2 {
   @include block-padding($left: 20px, $top: 10px, $bottom: 10px, $right: 30px);
}
 
// 可指定参数赋值,但是必须指定4个值,不能缺失
.container3 {
   @include block-padding($left: 10px, $top: 10px, $bottom: 0, $right: 0);
}

# 指定默认值

// 定义块元素内边距,参数指定默认值
@mixin block-padding($top:0, $right:0, $bottom:0, $left:0) {
    padding-top: $top;
    padding-right: $right;
    padding-bottom: $bottom;
    padding-left: $left;
}
 
// 可指定参数赋值
.container {
    /** 不带参数 */
    @include block-padding;
    /** 按顺序指定参数值 */
    @include block-padding(10px,20px);
    /** 给指定参数指定值 */
    @include block-padding($left: 10px, $top: 20px)
}

# 可变参数

@mixin linear-gradient($direction, $gradients...) {
    background-color: nth($gradients, 1);
    background-image: linear-gradient($direction, $gradients);
}
 
.table-data {
    @include linear-gradient(to right, #F00, orange, yellow);
}

编译为

.table-data {
    background-color: #F00;
    background-image: linear-gradient(to right, #F00, orange, yellow);
}

# @function

@function用于封装复杂的操作,可以很容易地以一种可读的方式抽象出通用公式和行为,函数提供返回值,常用来做计算方面的工作。

使用

注意:函数命名和变量命名规则一致。

@function square($base) {
    @return $base * $base * 1px;
}
 
.sidebar {
    float: left;
    margin-left: square(4);
}

编译为

.sidebar {
    float: left;
    margin-left: 16px;
}

# 可选参数

默认值可以是任何表达式,它们甚至可以引用前面的参数!

//change-color和hue是内置方法
//hue 返回$color的颜色为0到360度之间的一个数字。
//change-color 用于设置颜色的属性
@function invert($color, $amount: 100%) {
    //@error hue($color); 调试 210deg
    $inverse: change-color($color, $hue: hue($color) + 180);
    @return mix($inverse, $color, $amount);
}
 
$primary-color: #036;
.header {
    background-color: invert($primary-color, 80%);
}

# 指定参数

$primary-color: #036;
.banner {
    //scale-color Fluidly scales one or more properties of .$color
    background-color: $primary-color;
    color: scale-color($primary-color, $lightness: +40%);
}

# 可变参数

参数列表还可用于采用任意关键字参数,meta.keywords()函数采用参数列表

@function sum($numbers...) {
    $sum: 0;
    @each $number in $numbers {
        $sum: $sum + $number;
    }
    @return $sum;
}
 
$widths: 50px, 30px, 100px;
.micro {
    width: sum($widths...);
}

# @return

@return只允许在@function内使用,和js一样,遇到return就会返回。

@function red() {
    $is: true;
    @if $is {
        @return 'is';
    }
    @return red;
}
.con{
    color: red();
}

@function@mixin参数的使用方式没啥区别; @function用来计算,@mixin用来封装样式,@import用来抽离他们为一个模块。

# @extend继承

使用

我们以elementUIel-button组件为例,可以使用@extend继承已经存在的样式,原理是使用逗号选择器。

// # id选择器一样的
.button {
    display: inline-block;
    margin-bottom: 0;
    font-weight: normal;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    cursor: pointer;
    background-image: none;
    border: 1px solid transparent;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857143;
    border-radius: 4px;
    user-select: none;
}
 
.btn-default {
    @extend .button;
    color: #333;
    background-color: #fff;
    border-color: #ccc;
}
 
.btn-danger {
    @extend .button;
    color: #fff;
    background-color: #d9534f;
    border-color: #d43f3a;
}

编译成

.button, .btn-danger, .btn-default {
    display: inline-block;
    margin-bottom: 0;
    font-weight: normal;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    cursor: pointer;
    background-image: none;
    border: 1px solid transparent;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857143;
    border-radius: 4px;
    user-select: none;
}
 
.btn-default {
    color: #333;
    background-color: #fff;
    border-color: #ccc;
}
 
.btn-danger {
    color: #fff;
    background-color: #d9534f;
    border-color: #d43f3a;
}

# 可以使用多个@extend

.alert {
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid transparent;
    border-radius: 4px;
    font-size: 12px;
}
 
.important {
    font-weight: bold;
    font-size: 14px;
}
.alert-danger {
    @extend .alert;
    @extend .important;
    color: #a94442;
    background-color: #f2dede;
    border-color: #ebccd1;
}

# 多层继承

@extend可以多层继承,列如:.alert-danger继承自.important.important又继承自.alert

.alert {
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid transparent;
    border-radius: 4px;
    font-size: 12px;
}
 
.important {
    @extend .alert;
    font-weight: bold;
    font-size: 14px;
}
.alert-danger {
    @extend .important;
    color: #a94442;
    background-color: #f2dede;
    border-color: #ebccd1;
}

# 占位符选择器

占位符选择器%,与常用的idclass选择器写法相似,只是 #. 替换成了%,占位符选择器必须通过 @extend 指令调用。

# @use

# 私有模块

使用scss可以轻松地定义私有成员,私有成员命名以-或开头

# @forward

@forward语句可以引入另一个模块的所有变量、mixins和函数,将它们直接作为当前模块的API暴露出去,不会真的在当前模块增加代码。不同于 @use@forward不能给变量添加命名空间。

用法

注意,此时生成的bootstrap.css文件中,是不包含functionsvariablesmixins代码的,也不能直接在bootstrap.scss文件中使用这些模块。而是需要在另一个文件中 @import 'bootstrap'或者 @use bootstrap模块,再去使用这些方法。bootstrap.scss文件类似于一个传输中转站,把上下游的成员变量无缝连接起来。

/* bootstrap.scss */
@forward"functions";
@forward"variables";
@forward"mixins";

注意,直接写在上游模块的正常的样式仍然会被@forward进来。见下例:

a.scss

/* bootstrap.scss */
@forward"functions";
@forward"variables";
@forward"mixins";

b.scss

$radius: 3px;

c.scss

@forward "a";
@forward "b";

index.scss

@import "c.scss";
 
.button {
    @include rounded;
    padding: $radius;
}

编译为

footer {
    height: 1px;
}
 
.button {
    border-radius: 100px;
    padding: 3px;
}

# show/ hide

通过控制 showhide,可以决定模块中的哪些成员对引入后的模板可见。对隐藏的变量,在下游文件中不可以使用,相当于模块私有成员。

c.scss

@forward "a" show rounded;
@forward "b" hide $radius;

index.css

@import "c.scss";
 
.button {
    @include rounded;
    padding: $radius;
}
// Error: Undefined variable. padding: $radius;

# 使用as *号为子模块添加前缀

大多数情况下,一个样式库会存在一个入口文件index.scss,然后在index.scss中引入其他的子文件。这种结构类似于一个多合一模块。那么,如果要在某一文件中 @forward多个子模块,就可以使用as <prefix>-*语句,为子模块下的成员自动带上前缀以区分。

c.scss

@forward "a" as mixin-*;
@forward "b" as var-*;

index.css

@import "c.scss";
 
.button {
    @include mixin-rounded;
    padding: $var-radius;
}

很多内置的方法就是这样使用的,嘿嘿!

# @at-root

@at-root用来跳出嵌套,在多级嵌套时比较常用,包含withoutwith

//没有跳出
.parent-1 {
    color:#f00;
    .child {
        width:100px;
    }
}
 
//单个选择器跳出
.parent-2 {
    color:#f00;
    @at-root .child {
        width:200px;
    }
}
 
//多个选择器跳出
.parent-3 {
    background:#f00;
    @at-root {
        .child1 {
            width:300px;
        }
        .child2 {
            width:400px;
        }
    }
}

# @without和with

默认@at-root只会跳出选择器嵌套,而不能跳出@media@support,如果要跳出这两种,则需使用@at-root (without: media)@at-root (without: support)@at-root的关键词有四个:

  1. all表示所有;
  2. rule表示常规css选择器;
  3. media 表示media
  4. support表示support@support主要是用于检测浏览器是否支持css的某个属性)。

我们默认的@at-root@at-root (without:rule)

/*跳出父级元素嵌套*/
@media print {
    .parent1{
        color:#f00;
        @at-root .child1 {
            width:200px;
        }
    }
}
 
/*跳出media嵌套,父级有效*/
@media print {
    .parent2{
        color:#f00;
        @at-root (without: media) {
            .child2 {
                width:200px;
            }
        }
    }
}
 
/*跳出media和父级*/
@media print {
    .parent3{
        color:#f00;
        @at-root (without: all) {
            .child3 {
                width:200px;
            }
        }
    }
}

# @debug

@debug打印表达式的值,方便调试。

$font-sizes: 10px + 20px;
    $style: (
        color: #bdc3c7
    );
.container {
    @debug $style;
    @debug $font-sizes;
}

# @error

@error显示致命错误

$colors: (
    blue: #c0392b,
    black: #2980b9
);
 
@function style-variation($style) {
    @error "Invalid color: '#{$style}'.";
    @if map-has-key($colors, $style) {
        @return map-get($colors, $style);
    }
}
 
.container {
    color: style-variation(white);
}

# @warn

@warn显示警告性建议,会显示堆栈信息。

$colors: (
    blue: #c0392b,
    black: #2980b9
  );
 
@function style-variation($style) {
    @warn "Invalid color: '#{$style}'.";
    @if map-has-key($colors, $style) {
        @return map-get($colors, $style);
    }
}
 
.container {
    color: style-variation(white);
}