《记一忘三二》Scss学习笔记

42 阅读6分钟

选择器

嵌套

.container {
  .header {
    .title {
      font-size: 20px;
      font-weight: bold;
    }
  }
}

连接父选择器

.item {
  background-color: red;
  &:hover {
    background-color: blue;
  }
}

属性嵌套

.title {
  font: {
    size: 50px;
    weight: bold;
  }
}

编译结果:

.title {
  font-size: 50px;
  font-weight: bold;
}

注释

多行注释

/** 
这是scss多行注释
*/

单行注释

// 这是scss单行注释

不会编译到最终css文件,因为在css文件中不存在单行注释

变量

分隔符

$color_primary: yellow;
$color-primary: red;

p {
  color: $color_primary; // red
}

在scss中,_-是同一个符号,也就是$color-primary$color_primary代表同一个变量,所以在使用scss时,最好只选用其中一种作为分隔符

作用域

注意:scss变量作用域和css变量作用域规则是不一致,scss变量作用域规则是按照选择器嵌套关系决定的,而css变量作用域是按照Dom元素嵌套关系决定的

局部作用域

header {
  $color-primary: yellow;
  p {
    color: $color-primary;
  }
}

全局作用域

$color-primary: yellow;
header {
  p {
    color: $color-primary;
  }
}
!global

加上!global关键字代表设置为全局变量

header {
  $color-primary: red !global;
}

p {
  color: $color-primary;
}

值类型

// 颜色类型
$color: red;
// 单位像素
$size: 16px;
// 数组
$padding: 12px 15px;
// rgb颜色
$background: rgb(255, 0, 0);
// 数组
$font-family: "Arial", "Helvetica";
// null
$content: null;
// 布尔值
$boolean: true;
// Map
$colorMap: (
  "red": #ff0000,
  "green": #00ff00,
  "blue": #0000ff,
);

p {
  color: map-get($colorMap, "red");
}

默认值

$color-primary: yellow !default;
$color-primary: red;

p {
  color: $color-primary; // red
}

!default代表变量默认值,也可以理解为替补值

在编译到!default定义的变量时,会先校验是否已经存在当前名称的变量,如果存在就忽略这个定义,不存在就定义当前变量

@import

规则

要使用scss的@import语法导入时,需要按照特定规则书写

@import "./theme.scss"
    
@import "./theme.css"

@import "./theme"
// index.scss
@import "./theme";
p {
  color: $color;
}

// theme.scss
$color: red;

.title {
  color: $color;
}

编译结果:

.title {
  color: red;
}

p {
  color: red;
}

在使用scss的@import导入时,编译结果是将被导入文件的内容导入到当前文件,进行合并输出

注意:如果不按照上述规则导入,将会编译为css导入

// index.scss
@import url("./theme.scss");

编译结果:

// index.scss
@import url("./theme.scss");

scss就不会处理这种导入语句,会编译成css的导入语句

局部文件

scss会编译所有的scss文件,并且生成对应的css文件,如果项目中某个文件只负责声明全局变量,那么也会生成应该空的css文件,这显然是不合理的

如果在文件命名时以_开头,比如_theme.scss文件,那么就不会单独生成theme.css文件了

嵌套

header {
  @import "./_theme.scss";
  color: $color;
}

@import语法还可以写在选择器内部,但是并不常用

@use

@use@import的编码规范是一样的,在使用时,必须按照固定规则

@use "./uses/variable.scss";

不能出现url关键字

@use导出和esModel模块化导出差不多,有命名空间、首次执行等

重复执行

@import

image-20240811003630276

在重复导入同一个模块时,会重复执行模块的内容,也就会导出多个样式表

@use

image-20240811003736729

模块只会在第一次导入时执行,并且缓存导出的变量、混入特性,后续的导出语句只会再导出这些特性的引用

内容覆盖

在两个模块中定义相同的变量名称

image-20240811005714802

使用@import导入两个文件,按照执行顺序,后面定义的变量会覆盖前面相同名称的变量

@use是根据命名空间访问变量,所以不会覆盖

image-20240811005920151

模块

模块名称

@use "./uses/_variable.scss" as variable;

.button {
  &--primary {
    color: variable.$color-primary;
  }
}

在导入其他模块时,需要通过模块名称访问器内部暴露的变量、混入等,所以as variable就是给被导入的模块设置模块名称,如果在导入时,不特意去给模块命名,编译器也会按照模块的名称自动加上模块导出名称

@use "./uses/_variable.scss"
// 等同于
@use "./uses/_variable.scss" as variable;

as是给模块取别名

模块名称唯一

在一个文件内中模块名称必须保持唯一

@use "./uses/_variable1.scss" as variable;
@use "./uses/_variable2.scss" as variable;

虽然导入的是不同的文件,但是因为设置模块名称重复,这里会报错

image-20240811005405568

取消模块空间

@use "./uses/_var.scss" as *;

button {
  color: $color-primary;
}

as *就是把模块中的特性全部平铺到导入文件中,一般使用入口文件在合并导出中

// _index.scss

@use "./_var.scss" as *;
@use "./_reset.scss" as *;
@use "./_theme.scss" as *;

这样在其他文件使用这些基础特性时,只需要导入_index.scss就可以了

@use "./uses/_index.scss" as base;

注意:无法在引入_index.scss时,使用到_var.scss_reset.scss_theme.scss导出的特性,如果需要使用,则需要使用@forward关键字

私有成员

在引入模块时,会自动引入变量、混入等特性,但有时定义特性只想在当前空间使用,不对外暴露,在定义需在可以名称以_-开头

// _var.scss

$-color-primary: red;

// index.scss

@use "./uses/_var.scss";
button {
  color: var.$-color-primary;  // 报错,访问不到私有变量
}

修改默认值

// _var.scss
$color-primary: red !default;

// index.scss

@use "./uses/_var.scss" as * with($color-primary: yellow);

button {
  color: $color-primary;
}

with中的代码会预先加载到模块代码之前,也就是提前定义模块变量,当遇到!default关键字时,判断之前已经定义了变量,就不会采用默认变量

模块之间访问

image-20240811170414895

模块之间是相互独立的空间,就算import.scss在上面导入了_var.scss,在_mixin.scss还是需要使用导入_var.scss 才能使用特性

@forward

上面讲过@use也能实现合并,但是不能实现转发,如果需要转发必须

// _index.scss
@use "./_reset.scss";
@use "./_var.scss";
@use "./_theme.scss";

// 转发语法
$color-primary: var.$color-primary;

// use.scss
@use "./uses/_index.scss" as base;
header {
  color: base.$color-primary;
}

显然如果对每个特性都要单独写转发语句,这是得不偿失的, @forward可以实现特性合并转发一体

// _index.scss
@forward "./_reset.scss";
@forward "./_var.scss";
@forward "./_theme.scss";

// use.scss
@use "./uses/_index.scss" as base;
header {
  color: base.$color-primary;
}

合并文件使用特性

@forward "./_var.scss";

$copy-color-primary: var.$color-primary;  // 报错,访问不到

@forward只是用于合并转发,如果要在合并文件访问模块变量,必须使用@use

@use "./_var.scss";

@forward "./_var.scss";

$copy-color-primary: var.$color-primary;

@use和@forward同时使用

定义with必须只有一种语法,并且必须放在上面

@use "./_var.scss" with (
  $color-primary: green
);

@forward "./_var.scss";

导出别名

当多个模块出现同名变量时会产生报错

@forward "./_base.scss";
@forward "./_var.scss";

image-20240811164428980

这里会产生报错,我们可以给不同的模块特性添加不同的前缀

// _index.scss
@forward "./_base.scss" as base-*;
@forward "./_var.scss" as var-*;

// use.scss
@use "./uses/_index.scss" as *;
header {
  color: $var-color-primary;
}

限制转发特性

只想转发模块中部分特性

@forward "./_var.scss" show $color-primary;

也可以使用排除语法

// _index.scss
@forward "./_var.scss" hide $color-primary;

注意:如果设置了导出别名,那么在限制导出变量时,也要更具导出别名限制

@forward "./_var.scss" as var-* show $color-primary;

原理

// _var.scss
$color-primary: #409eff;
$color-success: #67c23a;
$color-warning: #e6a23c;
// _index.scss
@forward "./_var.scss" as var-* show $var-color-primary;

使用@use来实现

@use "./_var.scss" as var;

$var-color-primary: var.$color-primary;

默认值

image-20240811172838229

注意:虽然使用了别名,但是因为with是将内容嵌入到原文件,所以变量还是要使用原来的变量名称

image-20240811173041202

如需在use.scss 设置默认值,那么必须在_index.scss文件中使用!default关键字定义默认值

还需注意的是,在use.scss默认的名称要加上别名前缀

mixin混入

无参数

@mixin title-style {
  font-size: 16px;
  font-weight: bold;
  text-align: center;
}

.title {
  @include title-style;
}

带参数

@mixin button-style($color, $hover-color) {
  color: $color;
  &:hover {
    color: $hover-color;
  }
}

button {
  @include button-style(red, blue);
}

指定名称传参

@mixin padding($top, $right, $bottom, $left) {
  padding-top: $top;
  padding-right: $right;
  padding-bottom: $bottom;
  padding-left: $left;
}

header {
  @include padding($top: 10px, $right: 20px, $bottom: 30px, $left: 40px);
}

参数默认值

@mixin padding($top: 0, $right: 0, $bottom: 0, $left: 0) {
  padding-top: $top;
  padding-right: $right;
  padding-bottom: $bottom;
  padding-left: $left;
}

header {
  @include padding(20px);
}

剩余参数

@mixin linear-gradient($direction, $colors...) {
  color: nth($list: $colors, $n: 2);
  background-image: linear-gradient($direction, $colors);
}

$colors: red, blue, yellow;

header {
  @include linear-gradient(to right, $colors...);
}

extend继承

.button {
  display: inline-block;
  padding: 12px 25px;
  cursor: pointer;
  color: white;
  border-radius: 5px;
}

.buuton--info {
  @extend .button;
  background-color: red;
}

.button--success {
  @extend .button;
  background-color: green;
}

占位符%

.button在这里只是当作基础样式,并不需要编译至css代码中,所以可以使用占位符

%button {
  display: inline-block;
  padding: 12px 25px;
  cursor: pointer;
  color: white;
  border-radius: 5px;
}

.buuton--info {
  @extend %button;
  background-color: red;
}

.button--success {
  @extend %button;
  background-color: green;
}

这样在最后的css编译结果中就没有.button样式表了

继承和混入的区别

image-20240810042612775

image-20240810042650728

  • 混入会把样式合并到当前@include位置上,但继承是建立在不影响当下情况下,创建一个样式表
  • 继承通过扩展选择器来实现样式的复用,‌而混入则通过定义可重用的代码块并按照需要引入来实现

运算符

相等运算

@mixin button-size($size) {
  @if $size == small {
    padding: 5px 10px;
  } @else if $size == medium {
    padding: 10px 20px;
  } @else if $size == large {
    padding: 15px 30px;
  }
}

button {
  @include button-size(medium);
}

比较运算

@mixin text-line($line) {
  @if ($line == 1) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  } @else {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: $line;
    -webkit-box-orient: vertical;
  }
}

.titel {
  @include text-line(2);
}

逻辑运算

and

@mixin button-style($size, $type) {
  @if ($size == "small" and $type == "info") {
    background-color: red;
  }
}

button {
  @include button-style("small", "info");
}

or

@mixin button-style($is-loading, $is-disabled) {
  @if ($is-disabled or $is-loading) {
    color: #ccc;
  }
}

button {
  @include button-style(true, false);
}

not

@mixin button-style($isdisabled) {
  @if (not $isdisabled) {
    background-color: red;
  }
}

button {
  @include button-style(false);
}

算术运算

运算限制

  • %不能和其他单位一起运算
  • 纯数字和带有单位的值进行运算时,结果是转为对应的单位

除法

因为在css中/被当作分隔符,所以在使用/进行运算时,需要区分使用

  • 运算表达式被括号包裹
  • 属于算术表达式的一部分
  • 操作符两边的值是变量或者来自函数的返回值
$num: 1.5;

.title {
  font: (12px / 1.5) "微软雅黑";
  font: 12px / 1.5 + 1 "微软雅黑";
  font: 12px / $num "微软雅黑";
}

字符串运算

单位拼接

.title {
  font-size: 10 + px;
}

字符串拼接

.title {
  content: "hello" + " " + "world";
}

插值运算

插值运算允许你在选择器、属性名或者属性值中插入动态内容,通常是变量或者其他表达式的值。插值使用 #{} 语法来进行。

选择器

$namespace: "el";

.#{$namespace}-button {
}

属性名

$font: "font";

.title {
  #{$font}-size: 16px;
  #{$font}-weight: bold;
}

注释

$data: "2024-01-01";

/** #{$data} */

属性值

$size: "16px";
$line: 32px;

.title {
  font-size: #{$size};
  line-height: #{$line};
}

注意:

  • 在属性值中使用插值时,如果值本身是一个有效的 CSS 值,则不需要使用 #{}

    $size: 16px;
    
    .title {
      font-size: $size; 	  // 16px
    }
    
    
  • 在插入字符串值时,会自动转为非字符串值

    $size: "16px";
    
    .title {
      font-size: #{$size}; 		// 16px
    }
    
    
  • 插入的值不会再参加后续运算

$size: "16px";

.title {
  font-size: #{$size} + 15px;   // 16px + 15px;
}

常用函数

颜色相关的函数

  • lighten()darken(): 改变颜色的亮度。
  • saturate()desaturate(): 改变颜色的饱和度。
  • adjust-hue(): 改变颜色的色调角度。
  • rgb(), rgba(), hsl(), hsla(): 创建颜色值。
  • transparentize(): 使颜色透明化。
  • opacity(): 获取颜色的不透明度。
  • color(): 获取颜色的 RGB 或 HSL 值。
  • alpha(): 获取颜色的 Alpha 值。
  • mix(): 创建两种颜色的混合色。
  • complement(): 计算颜色的补色。
  • invert(): 计算颜色的反色。

数学相关的函数

  • percentage(): 将数值转换为百分比。
  • round(): 四舍五入一个数字。
  • ceil(): 向上取整。
  • floor(): 向下取整。
  • abs(): 返回一个数的绝对值。
  • min(), max(): 返回一组数中的最小值或最大值。
  • pi(): 返回圆周率 π 的值。

字符串相关的函数

  • str-length(): 返回字符串长度。
  • str-insert(): 在指定位置插入字符串。
  • str-index(): 返回子字符串的位置。
  • str-lower(): 将字符串转换为小写。
  • str-upper(): 将字符串转换为大写。
  • str-trim(): 删除字符串首尾的空白字符。
  • str-quote(): 添加引号到字符串两端。
  • str-replace(): 替换字符串中的子字符串。
  • escape(): 对字符串进行 URL 编码。

列表相关的函数

  • length(): 返回列表的长度。
  • nth(): 获取列表中的某个元素。
  • append(): 向列表末尾添加元素。
  • prepend(): 向列表开头添加元素。
  • join(): 连接两个列表。
  • index(): 返回列表中元素的位置。
  • sort(): 对列表排序。
  • unique(): 移除列表中的重复项。

其他有用的函数

  • unit(): 获取一个数值的单位。
  • unitless(): 检查一个数值是否无单位。
  • type-of(): 获取一个值的数据类型。
  • inspect(): 输出一个值的调试信息。
  • call(): 调用其他函数。
  • if(): 执行条件判断。

流程控制

if

header {
  color: if(theme == "dark", "white", "black");
}

@if

$theme-list: "light", "dark";

@mixin theme-title-style($theme-type) {
  @if ($theme-type == nth($theme-list, 1)) {
    .title {
      background-color: red;
    }
  } @else if ($theme-type == nth($theme-list, 2)) {
    .title {
      background-color: blue;
    }
  }
}

@include theme-title-style("dark");

@for

@for $i from 1 through 3 {
  .item-#{$i} {
    width: 100px * $i;
  }
}

@for $i from 1 to 3 {
  .item-#{$i} {
    width: 100px * $i;
  }
}

to和through差异

through关键字时,循环范围是**[start,end]**

to关键字时,循环范围是**[start,end)**

@each

用于遍历listmap类型的数据

$button-size-map: (
  "small": (
    font-size: 12px,
  ),
  "medium": (
    font-size: 14px,
  ),
  "large": (
    font-size: 16px,
  ),
);

@each $type, $value in $button-size-map {
  .button-#{$type} {
    @each $prop, $val in $value {
      #{$prop}: $val;
    }
  }
}

@while

@mixin create-cols($max-cols: 12) {
  $current-cols: 1;
  @while ($current-cols <= $max-cols) {
    .col-#{$current-cols} {
      width: $current-cols / $max-cols * 100 * 1%;
    }
    $current-cols: $current-cols + 1;
  }
}

@include create-cols(12);

@function

@function px2pw($value) {
  @return $value / 750 * 100 + vw;
}

header {
  height: px2pw(100);
  font-size: px2pw(750);
}

函数和混入的调用方式一样,同样拥有参数、默认参数、按照参数名称传值、剩余参数等

函数和混入的区别

  • 混入是封装公共的操作,生成结果是一系列的样式表
  • 函数是处理某些计算操作,返回结果是一个数据的值

@at-root

用于将嵌套规则提升到当前作用域的根级别

image-20240811180347044

疑难问题

Sass 和 Scss 区别

Sass和Scss是两种不同阶段提出的语法规则,也就是两种不同的预处理语言,就和Less和Sass区别是一样的

在先项目中使用Sass或Scss编译器任意一种,都可以编译两种语言

比如:在项目中安装Sass编译器

pnpm install sass -D

也可以在编译Scss语法

<style lang="scss"></style>

list类型

在scss中以空格或逗号分隔的多个值是list类型数据

$theme-list: "light", "dark";

引号与字符串

header {
  content: top == "top";   // true
}

top和*"top"*都是scss的字符串类型