css预处理器之scss

170 阅读4分钟

一、css预处理器


1. 什么是css预处理器?

  • css预处理器定义了一种新的语言并将css作为目标生成文件,然后开发者就只要使用这种语言就可以进行编码工作了。预编译器通常可以实现浏览器兼容、变量、结构体等功能,代码更加简洁易于维护。
  • 目前比较流行的三种预处理器是sass、less和stylus,其他还有dtcss等。

2. 什么是scss?

scss是sass3引入的新的语法,是sassy css的简写;简单说就是scss就是sass的升级版,其语法完全兼容css3,并且继承了sass的强大的功能;

3. scss与sass的区别?

scss是sass的升级版,两者其实就是一种东西,我们平时都称之为sass,两者的不同之处主要有以下两点:

  • 文件扩展名不同,sass是以".sass"后缀为扩展名,而scss是以".scss"后缀为扩展名。

  • 语法书写方式不同,sass是以严格的缩进语法规则来书写,不带大括号{}和分号;的;而scss的语法书写和我们的css语法书写方式非常类似。

  • 注意:在uniapp和vue项目中,如果需要指明预编译语言为sass时,需要写成 lang='scss' 而不是 lang='sass';

  • 可以这么理解:sass是一种css预编译器,编译sass预编译语言,后来版本3的sass升级为sassy css,简称scss,因为scss语法与css语法相同,所以更多人使用,但是scss的预编译器还是sass;

4. sass、less、stylus三者的异同?

  • 三者都是开源项目
  • sass诞生是最早也是最成熟的css预处理器,有Ruby社区和Compass支持;stylus早期服务nodejs项目,在该社区得到一定支持者;less出现于2009年,支持者远超于Ruby和nodejs社区;
  • sass和less语法较为严谨、严密,而stylus语法相当散漫,其中less学习起来更快一些,因为他更像css标准;
  • sass和less相互影响较大,其中sass受less影响,已经全面进化到了全面兼容css的scss;
  • sass和less都有第三方工具提供转译,特别是sass和compass是绝配;
  • sass、less、stylus都具有变量、作用域、混合、嵌套、继承、运算符、颜色函数、导入和注释等基本特性,而且以‘变量’,‘混合’,‘嵌套’,‘继承’和‘颜色函数’称为五大基本特性,各自特性实现功能基本相似,只是使用规则上有所不同;
  • sass和stylus具有类似于语言处理的能力,比如说条件语句、循环语句等,而less需要通过when等关键词模拟这些功能,在这一方面略逊一筹。

二、scss的语法


1. 变量(Variables)

  • 变量名以 $ 开头,变量的值无需加引号,变量名与变量值之间用冒号
  • 一个变量中可以使用其他变量
    // 变量名以 $ 开头,变量的值无需加引号,变量名与变量值之间用冒号
    $baseColor: pink;
    $bg_color: #ccc;
    
    // 一个变量中可以使用其他变量
    $base-border: 1px solid $baseColor;
    
    
    .box {  
      color: $baseColor;
      background-color: $bg_color;
      border: $base-border;
    }
    
    .box {
      color: pink;
      background-color: #ccc;
      border: 1px solid pink;
    }
    

2. 嵌套(Nesting)

  • 普通后代选择器的嵌套

    .box {
      background-color: pink;
        
      ul {
        /* ul 样式 */
        list-style: none;
            
        li {
            /* li 样式 */
            font-size: 1rem;
        }
      }
    }
    
    @charset "UTF-8";
    .box {
      background-color: pink;
    }
    .box ul {
      /* ul 样式 */
      list-style: none;
    }
    .box ul li {
      /* li 样式 */
      font-size: 1rem;
    }
    
  • 伪类选择器的嵌套需要使用&符号, &的一个作用就是让两个元素之间没有空格,让他们紧密连接在一起;

    .box{
      width: 300px;
      
      a{
        color:red;  
        
        &:hover {
          font-size: 30px;
        }
      }
    }
    
    .box {
      width: 300px;
    }
    .box a {
      color: red;
    }
    .box a:hover {
      font-size: 30px;
    }
    
  • 属性嵌套

    .box {
      font:{
        size:12px;
        weight: 400;
      }
    }
    
    .box {
      font-size: 12px;
      font-weight: 400;
    }
    

3. @mixin 和 @include

可以理解为js的函数 ``` // 声明:如果没有参数,括号可省略 @minxin 名字(参1,参2,..) { // 样式代码,里面也可以写任何标签嵌套 }

// 调用,可以在某个标签下调用,也可单独调用;没有参数可以省略括号;
.box {
  @include 名字
}

@include 名字
```
  • 无参数

    // 定义不带参mixin
    @mixin my() {
      border:1px solid red;
      color: pink;
    
      p {
        font-size: 24px;
      }
    }
    
    .box {
      @include my()
    }
    
    
    .box {
      border: 1px solid red;
      color: pink;
    }
    .box p {
      font-size: 24px;
    }
    
  • 有参数

    // 定义带参mixin
    @mixin info($text-color, $bg-color) {
      color: $text-color;
      background-color: $bg-color;
    }
    
    .box {
      // 按顺序传实参,传递的参数必须保持一致
      @include info(red, gray)
    }
    
    .box {
      // 这样传参可以不考虑顺序,但是数量要一一对应,不能少写
      @include info($bg-color: red, $text-color:gray)
    }
    
    .box {
      color: red;
      background-color: gray;
    }
    
    .box {
      color: gray;
      background-color: red;
    }
    
  • 有参数且带默认值

    @mixin btn($color:pink, $bg:orange) {
        color: $color;
        background-color: $bg;
    }
    
    .box {
      // 带默认值的参数,可以不填,等于默认值
      @include btn;
    }
    
    .box {
      // 也可以按顺序填,填一个值,对应@mixin的第一个形参
      @include btn(blue)
    }
    
    .box {
      // 也可指定某个值
      @include btn($bg: black)
    }
    
    .box {
      color: pink;
      background-color: orange;
    }
    
    .box {
      color: blue;
      background-color: orange;
    }
    
    .box {
      color: pink;
      background-color: black;
    }
    

4. @extend 继承

```
.box {
  padding: 20px;
}
.box p {
  color: red;
}

// @extend 会继承你所继承的元素的样式以及该元素下面所有相关的元素的样式
.box-info {
  @extend .box;
  font-size: 30px;
}
```
```
.box, .box-info {
  padding: 20px;
}

.box p, .box-info p {
  color: red;
}

.box-info {
  font-size: 30px;
}
```

5. @import 与 Partials

  • 在传统的css中,就是使用@import导入其他css文件的,但是每次都会去发送http请求,浪费性能;
  • scss中,优化了@import,我们会先创建一个主要scss文件index.scss,然后根据需要去创建所需的每一部分的scss文件,我们称每一个部分为Partials;这样有益于模块化;

Partials条件与特点:

  • 创建文件时,以_开头
  • 使用@import导入文件时,名字不需要加_
  • 当你使用sass监听一个目录是,不会监听Partials文件
    // Partials 文件:_base.scss
    body {
      padding: 0;
      margin:0;
    }
    
    // 主要scss文件:index.scss
    // 导入_base.scss
    @import "base";
    
    .box {
      font-size: 30px;
      color: red;
    }
    
    body {
      margin: 0;
      padding: 0;
    }
    
    .box {
      font-size: 30px;
      color: red;
    }
    

6. @if

  • @if简单判断

    $flg: true;
    
    .box {
      @if $flg {
        font-size: 34px;
      }
      border:2px solid red;
    }
    
    .box {
      font-size: 34px;
      border: 2px solid red;
    }
    
  • @if复杂判断

    $body-color: red;
    
    body {
      @if $body-color == pink {
        background-color: pink;
      } @else if $body-color == red {
        background-color: red;
      } @else {
        background-color: gray;
      }
    }
    
    body {
      background-color: red;
    }
    

7. @each

循环一个list 或者一个map

//
$sizes:20px,22px,24px;
@each $size in $sizes {
.icon-#{$size} {
    font-size:$size
  }
}
$primary: #0d6efd !default;
$secondary: #6c757d !default;
$success: #52c41a !default;
	
$theme-colors:(
    "primary":$primary,
    "secondary":$secondary,
    "success":$success
);
	
@each $key,$val in $theme-colors {
    .icon-#{$key} {
        color: $val;
    }
}

8. @use

从其他Sass样式表加载mixin,function和变量,并将来自多个样式表的CSS组合在一起

// src/_corners.scss
$radius: 3px;
@mixin rounded {
  border-radius: $radius;
}
	
// style.scss
@use "src/corners" as corners;

.button {
  @include corners.rounded;
  padding: 5px + corners.$radius;
}

可通过with(…)修改默认值

@use "base-style" as baseStyle with($font-size: 20px);
div {
  font-size: baseStyle.$font-size;
}

9. @forward

通过@forward加载一个模块的成员,并将这些成员当作自己的成员对外暴露出去,类似于类似于 es6 的 export

// src/_list.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;

code {
  border-radius: $border-radius;
  box-shadow: $box-shadow;
}

@mixin reset {
  margin: 0;
  padding: 0;
  list-style: none;
}

// bootstrap.scss
@forward "src/list" as list-* with (
  $black: #222 !default,
  $border-radius: 0.1rem !default
);
//@forward "url" as prefix 为URL调用增加前缀
//@forward "url" with (...) 给URL所指向文件传递参数
//@forward "url" as prefix with (...)
	//as关键字必须放在whither之前

// styles.scss
@use "bootstrap" as corner with ($black: #333);
//向引用文件中传递参数

li {
  @include corner.list-reset;
}

可通过with(…)修改默认值

三、scss 和 js 的交互


1. scss中使用js变量

1.在js中定义变量:

<script setup>
import {computed, ref} from "vue";
 
const fileWidth = ref(150);
const cssVars = computed(() => {
    return (fileWidth.value - 10) + 'px'
});
</script>

2.在scss中使用

//直接使用
<style lang="scss" scoped>
.pendingImg {
  width: v-bind(cssVars);
}
</style>
  
//在scss中定义变量后再使用
<style lang="scss" scoped>
$baseWidth: v-bind(cssVars);
.pendingImg {
  width: $baseWidth;
}
</style>

2. js中使用scss变量

  1. 创建一个main.scss文件,定义变量并export
$titleColor: #FF0000;

:export {
  titleColor: $titleColor;
}

  1. js中引入,使用scss里的变量
<template>
  <div>
    <h1 :style="{color: color}">JS 获取 SCSS 变量值</h1>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import config from '@/scss/main.scss'

const color = ref(config.titleColor)
</script>