CSS-预编译器-Sass

前言

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

官网地址:Sass教程 Sass中文文档 | Sass中文网

特色功能:

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

导入依赖

我这里使用的是vue2项目,所以会使用npm/yarn/pnpm安装依赖

安装好依赖后,可以使用npx sass ./src/....xxx.scss命令,来单独编译scss,并在命令提示符中输出

npm install sass sass-loader -D # npm

pnpm add sass sass-loader -D # pnpm

语法格式

Sass有两种语法格式(sass、scss)

  • 一种是scss:这种格式仅在 CSS3 语法的基础上进行拓展,所有 CSS3 语法在 SCSS 中都是通用的,同时加入 Sass 的特色功能

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

本案都是使用scss语法

/* scss 语法 */
.wrapper{
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    .inner{
        width: 100px;
        height: 100px;
        background: linear-gradient(#6FB1AC,#5899BD);
        &-text{
            color: red;
        }
    }
}

/* sass 语法 */
body
 widht: 100vw
 height: 100vh

语法拓展

1、嵌套规则

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

  • 嵌套功能避免了重复输入父选择器,而且令复杂的 CSS 结构更易于管理

1.1、html

<div class="wrapper">
    <div class="inner">div>
div>

1.2、编译前的scss

/* 指定语言 scss */

1.3、编译后的css

.wrapper {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
.wrapper .inner {
  width: 100px;
  height: 100px;
  background: linear-gradient(#6FB1AC, #5899BD);
}

1.4、效果

CSS-预编译器-Sass_第1张图片

2、父选择器 &

  • & 后面的选择器会直接拼接在父选择器后面
  • & 必须作为选择器的第一个字符,其后可以跟随后缀生成复合的选择器
  • 下面案例中,既能拼接类名&-text,又能拼接特殊的选择器&::first-letter

2.1、html

<div class="wrapper">
    <div class="inner">
        <p class="inner-text">Hello Worldp>
    div>
div>

2.2、编译前

.wrapper{
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  .inner{
    width: 100px;
    height: 100px;
    background: linear-gradient(#6FB1AC,#5899BD);
    &-text{
      color: red;
      &::first-letter{
        font-weight: bold;
        font-size: 16px;
        color: blue;
      }
    }
  }
}

2.2、编译后

.wrapper {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
.wrapper .inner {
  width: 100px;
  height: 100px;
  background: linear-gradient(#6FB1AC, #5899BD);
}
.wrapper .inner-text {
  color: red;
}
.wrapper .inner-text::first-letter {
  font-weight: bold;
  font-size: 16px;
  color: blue;
}

2.4、效果

CSS-预编译器-Sass_第2张图片

3、属性嵌套

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

3.1、编译前css

.inner-text{
  font: {
    weight: bold;
    size: 24px
  }
}

3.2、编译后css

.inner-text {
  font-weight: bold;
  font-size: 24px;
}

SassScript

在 CSS 属性的基础上 Sass 提供了一些名为 SassScript 的新功能。 SassScript 可作用于任何属性,允许属性使用变量、算数运算等额外功能。

1、变量

  • SassScript 最普遍的用法就是变量,变量以美元符号($)开头,赋值方法与 CSS 属性的写法一样,使用:分割
  • 变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量则可在任何地方使用(全局变量)
  • 将局部变量转换为全局变量可以添加 !global 声明
  • sass的变量是在编译前就转换好,css的变量是在使用的时候,浏览器编译

注意:

  • 变量名是不以数字开头的。可以包含字母、数字、下划线、横线(连接符)
  • 连接符(-)与下划线(_)定义的同名变量为同一变量,建议使用连接符

1.1、语法

// 定义变量
$label-width: 20px;
// 上面写法相当于 css的变量定义
--label-height: 20px;


// 使用变量
.inner{
    width: $label-width;
    height: var(--label-height)
}

1.2、html

<template>
  <div class="wrapper">
    <div class="inner-1">
      inner-1
    div>
    <div class="inner-2">
      inner-2
    div>
  div>
template>

1.3、编译前

.wrapper{
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  // scss 变量
  $inner-width: 100px;
  // css变量
  --inner-height: 100px;
  .inner-1{
    // 局部,添加!global 变为全局
    $inner-border: 1px solid #f39282 !global;
    width: $inner-width;
    height: var(--inner-height);
    border: $inner-border;
  }
  .inner-2{
    margin-left: 20px;
    width: $inner-width;
    height: var(--inner-height);
    border: $inner-border;
  }
}

1.4、编译后

.wrapper {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  --inner-height: 100px;
}
.wrapper .inner-1 {
  width: 100px;
  height: var(--inner-height);
  border: 1px solid #f39282;
}
.wrapper .inner-2 {
  margin-left: 20px;
  width: 100px;
  height: var(--inner-height);
  border: 1px solid #f39282;
}

1.5、效果

CSS-预编译器-Sass_第3张图片

1.6变量定义!default

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

1.1、编译前

.wrapper{
  // scss 变量
  $inner-width: 100px; // 使用这个
  $inner-width: 200px !default; // 由于上面定义了这个变量,所以这个变量不会生效
  // css变量
  --inner-height: 100px;
  --inner-height: 200px; // 使用这个

  // 如果上面没有定义,则默认使用这个
  $inner-border: 1px solid #f39282 !default;
  .inner-1{
    width: $inner-width;
    height: var(--inner-height);
    border: $inner-border;
  }
  .inner-2{
    margin-left: 20px;
    width: $inner-width;
    height: var(--inner-height);
    border: $inner-border;
  }
}

1.2、编译后

.wrapper {
  --inner-height: 100px;
  --inner-height: 200px;
}
.wrapper .inner-1 {
  width: 100px;
  height: var(--inner-height);
  border: 1px solid #f39282;
}
.wrapper .inner-2 {
  margin-left: 20px;
  width: 100px;
  height: var(--inner-height);
  border: 1px solid #f39282;
}

1.3、效果

CSS-预编译器-Sass_第4张图片

2、数据类型

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 不会特殊对待这些属性值,一律视为无引号字符串。

2.1、数字

2.1.1、编译前

// 数字
$heightAndWidth: 100px;
$domOpacity: .5;
.wrapper{
  .inner-1{
    width: $heightAndWidth;
    height: $heightAndWidth;
    border: 1px solid red;
    opacity: $domOpacity;
  }
}

2.1.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 1px solid red;
  opacity: 0.5;
}

2.2、字符串

  • SassScript 支持 CSS 的两种字符串类型:有引号字符串 (quoted strings),如 "Lucida Grande"
  • 与无引号字符串 (unquoted strings),如 sans-serif bold,在编译 CSS 文件时不会改变其类型。
  • 只有一种情况例外,使用 #{} (interpolation) 时,有引号字符串将被编译为无引号字符串(第五小节会讲)

2.2.1、编译前

.wrapper{
  // 有引号字符串 与 无引号字符串
  $fontFamaly: 'Courier New', Courier, monospace;
  .inner-1{
    font-family: $fontFamaly;
  }
}

2.2.2、编译后

.wrapper .inner-1 {
  font-family: "Courier New", Courier, monospace;
}

2.2.3、效果

CSS-预编译器-Sass_第5张图片

2.3、数组

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

2.3.1、编译前

// 数字
$heightAndWidth: 100px;
// 数组
$dom-border: 1px solid darkcyan;
// 数组
$dom-shadow: 2px 2px 3px rgba(0,0,0,.5);
.wrapper{
  .inner-1{
    width: $heightAndWidth;
    height: $heightAndWidth;
    border: $dom-border;
    box-shadow: $dom-shadow;
  }
}

2.3.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 1px solid darkcyan;
  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
}

2.3.3、效果

CSS-预编译器-Sass_第6张图片

2.4、颜色

2.4.1、编译前

// 数字
$heightAndWidth: 100px;
// 颜色
$dom-borderColor: rgb(112,159,123);
.wrapper{
  .inner-1{
    width: $heightAndWidth;
    height: $heightAndWidth;
    border: 1px solid $dom-borderColor;
  }
}

2.4.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 1px solid rgb(112, 159, 123);
}

2.5、布尔值

  • css中并没有值为布尔类型的样式
  • 可以搭配scss的==控制指令(@if…等)==一起使用

2.5.1、编译前

// 数字
$heightAndWidth: 100px;
// 布尔
$flag: true;
.wrapper{
  .inner-1{
    width: $heightAndWidth;
    height: $heightAndWidth;
    border: 2px solid red;
    @if $flag {
      color: darkcyan;
    }
    @else {
      color: fuchsia;
    }
  }
}

2.5.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 2px solid red;
  color: darkcyan;
}

2.5.3、效果

CSS-预编译器-Sass_第7张图片

2.6、空值

  • null其类型的唯一值,它表示缺少值,通常由函数返回。以指示缺少结果

2.6.1、编译前

// 数字
$heightAndWidth: 100px;
// 数组
$marg: 1px 2px 2px 2px;
// 布尔
$var: null;
.wrapper{
  .inner-1{
    width: $heightAndWidth;
    height: $heightAndWidth;
    border: 2px solid red;
    // 获取变量类型
    content: type-of($heightAndWidth);
    content: type-of($var);
    // 获取变量长度
    content: length($marg);
  }
}

2.6.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 2px solid red;
  content: number;
  content: null;
  content: 4;
}

2.7、maps

  • 相当于JavaScript的Object(key1:val1,key2:val2)
  • 使用map-get(mapName,keyName)获取值

2.7.1、编译前

// maps
$map: (heightAndWidth:100px, border:2px solid red);
.wrapper{
  .inner-1{
    width: map-get($map, heightAndWidth);
    height: map-get($map, heightAndWidth);
    border: map-get($map, border);
  }
}

2.7.2、编译后

.wrapper .inner-1 {
  width: 100px;
  height: 100px;
  border: 2px solid red;
}

3、运算

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

3.1、数字运算

  • SassScript 支持数字的加减乘除、取整等运算 (+, -, *, /, %),如果必要会在不同单位间转换值。
  • 关系运算 <, >, <=, >= 也可用于数字运算,相等运算 ==, != 可用于所有数据类型。

3.1.1、数学运算

// 编译前
.wrapper{
  $heightAndWIdht: 50px;
  .inner-1{
    width: $heightAndWIdht+20px;
    height: $heightAndWIdht+50px;
    border: 1px+1px solid red;
  }
}


// 编译后
.wrapper .inner-1 {
  width: 70px;
  height: 100px;
  border: 2px solid red;
}

3.1.2、除法运算

  • / 在 CSS 中通常起到分隔数字的用途,SassScript 作为 CSS 语言的拓展当然也支持这个功能,同时也赋予了 / 除法运算的功能。也就是说,如果 / 在 SassScript 中把两个数字分隔,编译后的 CSS 文件中也是同样的作用。
  • 以下三种情况 / 将被视为除法运算符号:
    • 如果值,或值的一部分,是变量或者函数的返回值
    • 如果值被圆括号包裹
    • 如果值是算数表达式的一部分
// 编译前
.wrapper{
  $heightAndWIdht: 100px;
  .inner-1{
    // 编译报错 样式 写法 失效
    font-size: 30px/3px;
    // 值 使用变量 视为 除法
    width: $heightAndWIdht/2;
    // 值 被圆括号包裹 视为除法
    height: (100px/2);
    // 值 是算数表达的一部分 视为除法
    border: 1px + 10px/10 solid red;
  }
}


// 编译后
.wrapper .inner-1 {
  font-size: 30px/3px;
  width: 50px;
  height: 50px;
  border: 2px solid red;
}

3.2、颜色值运算

1.62.1版本目前不支持,编译报错

3.3、字符串运算

  • + 可用于连接字符串
  • 注意,如果有引号字符串==(位于 + 左侧)连接无引号字符串,运算结果是有引号的==,相反,无引号字符串(位于 + 左侧)连接有引号字符串,运算结果则没有引号
  • 运算表达式与其他值连用时,用空格做连接符
  • 在有引号的文本字符串中使用 #{} 插值语句可以添加动态的值

3.3.1、编译前

.wrapper{
  $heightAndWIdht: 100px;
  .inner-1{
    width: $heightAndWIdht/2;
    height: (100px/2);
    // 字符串运算
    cursor: po + inter;
    content: sans- + "serif";
    font-family: 'Courier ' + New;
    // 空格为连接符
    margin: 10px - 1px auto;
    // 在有引号的文本字符串中使用 #{} 插值语句可以添加动态的值
    content: "i #{lo + ve} you"
  }
}

3.3.2、编译后

.wrapper .inner-1 {
  width: 50px;
  height: 50px;
  cursor: pointer;
  content: sans-serif;
  font-family: "Courier New";
  margin: 9px auto;
  content: "i love you";
}

4、圆括号

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

4.1、编译前

.wrapper{
  $heightAndWIdht: 100px;
  .inner-1{
    width: $heightAndWIdht/2;
    height: (100px/2);
    // 优先算 括号内的
    font-size: 10em + (5em - 3) *2;
  }
}

4.2、编译后

.wrapper .inner-1 {
  width: 50px;
  height: 50px;
  font-size: 14em;
}

5、插值语句

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

5.1、编译前

.wrapper{
  $heightAndWIdht: 100px;
  $name: inner-1;
  $var: font;
  .#{$name}{
    width: $heightAndWIdht/2;
    height: (100px/2);
    // 优先算 括号内的
    #{$var}-size: 10em + (5em - 3) *2;
  }
}

5.2、编译后

.wrapper .inner-1 {
  width: 50px;
  height: 50px;
  font-size: 14em;
}

@-Rules

Sass 支持所有的 CSS3 @-Rules,以及 Sass 特有的 “指令”(directives)

1、@import

  • Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中
  • 被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用
  • 通常,@import 寻找 Sass 文件并将其导入,但在以下情况下,@import 仅作为普通的 CSS 语句,不会导入任何 Sass 文件
  • 如果不在以下情况内,文件的拓展名是 .scss.sass,则导入成功。没有指定拓展名,Sass 将会试着寻找文件名相同,拓展名为 .scss.sass 的文件并将其导入
    • 文件拓展名是 .css
    • 文件名以 http:// 开头
    • 文件名是 url()
    • @import 包含 media queries
  • 如果不在上述情况内,文件的拓展名是 .scss.sass,则导入成功。没有指定拓展名,Sass 将会试着寻找文件名相同,拓展名为 .scss.sass 的文件并将其导入。
  • Sass 允许同时导入多个文件
  • 不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import
/* @import '@/assets/css/test2.scss'; 导入成功 */
// @import '@/assets/css/test2'; /* 含义同上 导入成功 */
// @import '@/assets/css/test2', '@/assets/css/test3'; /* 导入成功 */

// $urlfff: "family";
// @import url('http://fonts.googleapis.com/css?family=\#{$family}'); /* 导入成功 */

.wrapper{
  @import '@/assets/css/test2'; /* 导入成功 */
}

2、@media

Sass 中 @media 指令与 CSS 中用法一样,只是增加了一点额外的功能

  • 允许其在 CSS 规则中嵌套。如果 @media 嵌套在 CSS 规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器
  • 这个功能让 @media 用起来更方便,不需要重复使用选择器,也不会打乱 CSS 的书写流程。
  • @media 甚至可以使用 SassScript(比如变量,函数,以及运算符)代替条件的名称或者值
.wrapper {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}

// 编译为
.wrapper {
  width: 300px;
}
@media screen and (orientation: landscape) {
  .wrapper {
    width: 500px;
  }
}

// -------------------------------------------------------------------------

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

// 编译为
@media screen and (orientation: landscape) {
  .wrapper {
    width: 500px;
  }
}

// -------------------------------------------------------------------------

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

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

// 编译为
@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
  .wrapper {
    width: 500px;
  }
}

3、@extend

  • 在编写代码的时候,我们样式统一的地方一般会写一个公共样式,如果个别地方会根据公共的样式,增加一些自己的样式,就会编写两个类名(一个公共样式的,一个自己独特的)
  • 比如 如下案例:当前页面由很多标题,并且有很多样式一样,只不过标题颜色不同,那么我们肯定会把一样的样式,单独提取出来一个类名,然后在所有标题的标签类名上多添加一个title的类名,我们也可以使用如下方法,继承title的样式

3.1、基本使用

3.1.1、修改前

html

<template>
  <div class="wrapper">
    <h2 class="title">标题1h2>
    <p>Lorem ipsum dolor sit amet.p>

    <h2 class="title t2">标题2h2>
    <p>Lorem ipsum dolor sit amet.p>

    <h2 class="title t3">标题3h2>
    <p>Lorem ipsum dolor sit amet.p>
  div>
template>
<style lang="scss" scoped>
.wrapper{
  width: 100vw;
  height: 100vh;
}
@import '@/assets/css/test.scss'; /* 导入成功 */
style>

scss

.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    &::before{
      content: '';
      display: inline-block;
      width: 2px;
      height: 23px;
      background-color: darkcyan;
      margin-right: 10px;
    }
  }

  .t2{
    color: red;
  }
  .t3{
    color: blue;
  }
}

3.1.2、修改后

html

去掉了重复的类名使用 title

<template>
  <div class="wrapper">
    <h2 class="title">标题1h2>
    <p>Lorem ipsum dolor sit amet.p>

    <h2 class="t2">标题2h2>
    <p>Lorem ipsum dolor sit amet.p>

    <h2 class="t3">标题3h2>
    <p>Lorem ipsum dolor sit amet.p>
  div>
template>
<style lang="scss" scoped>
.wrapper{
  width: 100vw;
  height: 100vh;
}
@import '@/assets/css/test.scss'; /* 导入成功 */
style>

scss

在每个使用到title的样式里,使用@extend .title;继承.title的样式

.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    &::before{
      content: '';
      display: inline-block;
      width: 2px;
      height: 23px;
      background-color: darkcyan;
      margin-right: 10px;
    }
  }

  .t2{
    @extend .title;
    color: red;
  }
  .t3{
    @extend .title;
    color: blue;
  }
}

3.1.3、编译后

.wrapper {
  padding-left: 10px;
}
.wrapper .title, .wrapper .t3, .wrapper .t2 {
  font-size: 18px;
  display: flex;
  align-items: center;
}
.wrapper .title::before, .wrapper .t3::before, .wrapper .t2::before {
  content: "";
  display: inline-block;
  width: 2px;
  height: 23px;
  background-color: darkcyan;
  margin-right: 10px;
}
.wrapper .t2 {
  color: red;
}
.wrapper .t3 {
  color: blue;
}

3.1.4、注意

  • 其他使用到 .title 的样式也会同样继承给 .t2 .t3,例如,另一个样式 .title.border 使用了border属性
  • 那么,如果继承的标签上,也有类名border,则同样会应用样式

html



scss编译前

.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    &::before{
      content: '';
      display: inline-block;
      width: 2px;
      height: 23px;
      background-color: darkcyan;
      margin-right: 10px;
    }

    &.border{
      border: 3px solid darkkhaki
    }
  }

  // 等效于上面内联语法
  /* .title.border{
    border: 3px solid darkkhaki
  } */

  .t2{
    @extend .title;
    color: red;
  }
  .t3{
    @extend .title;
    color: blue;
  }
}

scss编译后

.wrapper {
  padding-left: 10px;
  /* .title.border{
    border: 3px solid darkkhaki
  } */
}
.wrapper .title, .wrapper .t3, .wrapper .t2 {
  font-size: 18px;
  display: flex;
  align-items: center;
}
.wrapper .title::before, .wrapper .t3::before, .wrapper .t2::before {
  content: "";
  display: inline-block;
  width: 2px;
  height: 23px;
  background-color: darkcyan;
  margin-right: 10px;
}
.wrapper .title.border, .wrapper .border.t3, .wrapper .border.t2 {
  border: 3px solid darkkhaki;
}
.wrapper .t2 {
  color: red;
}
.wrapper .t3 {
  color: blue;
}

效果

因为最后一个标题,类名中,没有border,所以样式没有匹配到,所以没有应用边框

CSS-预编译器-Sass_第8张图片

3.2、延伸复杂的选择器

  • Class 选择器并不是唯一可以被延伸 (extend) 的,Sass 允许延伸任何定义给单个元素的选择器,比如 .special.coola:hover
  • 1.62.1:版本不支持,编译报错(下面为官网案例)
.hoverlink {
  @extend a:hover;
}
a:hover {
  text-decoration: underline;
}

// 编译后
a:hover, .hoverlink {
  text-decoration: underline; 
}

3.3、多重延伸

  • 同一个选择器可以延伸给多个选择器,它所包含的属性将继承给所有被延伸的选择器
  • 虽然两个border都被编译出来了,但是由于第二个border是后继承的,后定义的样式享有优先权,所以值还是取2px solid red
// 编译前
.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    border: 1px solid green;
  }

  .tit{
    border: 2px solid red;
  }

  .t2{
    @extend .title;
    @extend .tit;
    color: red;
  }
}


// 编译后
.wrapper {
  padding-left: 10px;
}
.wrapper .title, .wrapper .t2 {
  font-size: 18px;
  display: flex;
  align-items: center;
  border: 1px solid green;
}

.wrapper .tit, .wrapper .t2 {
  border: 2px solid red;
}
.wrapper .t2 {
  color: red;
}

多重延伸可以使用逗号分隔选择器名,上面的sass代码,可以写为如下格式

.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    border: 1px solid green;
  }

  .tit{
    border: 2px solid red;
  }

  .t2{
    @extend .title,  .tit;
    color: red;
  }
}

3.4、继续延伸

当一个选择器延伸给第二个后,可以继续将第二个选择器延伸给第三个

3.4.1、编译前

// 编译前
.wrapper{
  padding-left: 10px;
  .title{
    font-size: 18px;
    display: flex;
    align-items: center;
    border: 1px solid green;
  }

  .t2{
    @extend .title;
    color: red;
  }

  .t3{
    @extend .t2;
  }
}

3.4.2、编译后

// 编译后
.wrapper {
  padding-left: 10px;
}
.wrapper .title, .wrapper .t2, .wrapper .t3 {
  font-size: 18px;
  display: flex;
  align-items: center;
  border: 1px solid green;
}
.wrapper .t2, .wrapper .t3 {
  color: red;
}

3.5、@extend-Only 选择器

  • 有时,需要定义一套样式并不是给某个元素用,而是只通过 @extend 指令使用,尤其是在制作 Sass 样式库的时候,希望 Sass 能够忽略用不到的样式。
  • 如果使用普通的 CSS 规则,最后会编译出很多用不到的样式,也容易与其他样式名冲突,所以,Sass 引入了“占位符选择器” (placeholder selectors)
  • 看起来很像普通的 idclass 选择器,只是 #. 被替换成了 %。可以像 class 或者 id 选择器那样使用,当它们单独使用时,不会被编译到 CSS 文件中

3.5.1、定义

.wrapper .a%extendName{
  background-color: aqua;
}

3.5.2、使用

.title{
  @extend %extendName;
  color: red;
}

3.5.3、编译后

.wrapper .a.title {
  background-color: aqua;
}

.title {
  color: red;
}

3.6、在指令中延伸

  • 在指令中使用 @extend 时(比如在 @media 中)有一些限制:Sass 不可以将 @media 层外的 CSS 规则延伸给指令层内的 CSS,这样会生成大量的无用代码
  • 也就是说,如果在 @media (或者其他 CSS 指令)中使用 @extend,必须延伸给相同指令层中的选择器

3.6.1、成功的例子

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

3.6.2、失败的例子

.error {
  border: 1px #f00;
  background-color: #fdd;
}

@media print {
  .seriousError {
    // 不可以继承指令@media 外的样式
    @extend .error;
    border-width: 3px;
  }
}

4、@at-root

  • @at-root指令导致一个或多个规则在文档的根处发出,而不是嵌套在其父选择器下
  • 它可以与单个内联选择器一起使用

4.1、编译前

.parent {
  ...
  @at-root {
    .child1 { ... }
    .child2 { ... }
  }
  .step-child { ... }
}

4.2、编译后

.parent { ... }
.child1 { ... }
.child2 { ... }
.parent .step-child { ... }
  • 默认@at-root只能排除选择器,但是,也可以使用@at-root在根目录下移动到嵌套指令(如@media)之外

4.3、编译前

@media print {
  .page {
    width: 8in;
    @at-root (without: media) {
      color: red;
    }
  }
}

4.4、编译后

@media print {
  .page {
    width: 8in;
  }
}
.page {
  color: red;
}

控制指令

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

1、@if

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

1.1、编译前

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

1.2、编译后

p {
  border: 1px solid;
}
  • @if 声明后面可以跟多个 @else if 声明,或者一个 @else 声明。
  • 如果 @if 声明失败,Sass 将逐条执行 @else if 声明,如果全部失败,最后执行 @else 声明

1.3、编译前

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

1.4、编译后

p {
  color: green; 
}

2、@for

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

2.1、编译前

@for $i from 1 through 5{
    .inner-#{$i}{
      background: rgba(random(255), random(255), random(255), 0.8);
    }
  }

2.2、编译后

.wrapper .inner-1 {
  background: rgba(112, 37, 127, 0.8);
}
.wrapper .inner-2 {
  background: rgba(76, 227, 87, 0.8);
}
.wrapper .inner-3 {
  background: rgba(248, 174, 69, 0.8);
}
.wrapper .inner-4 {
  background: rgba(216, 12, 153, 0.8);
}
.wrapper .inner-5 {
  background: rgba(161, 164, 210, 0.8);
}

3、@each

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

3.1、编译前

// 单属性列表 list
@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

// 多属性列表 list
@each $animal, $color, $cursor in (puma, black, default),
                                  (sea-slug, blue, pointer),
                                  (egret, white, move) {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
    border: 2px solid $color;
    cursor: $cursor;
  }
}

// map列表
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
  #{$header} {
    font-size: $size;
  }
}

3.2、编译后

/* 单属性列表 */
.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'); 
}

/* 多属性列表 */
.puma-icon {
  background-image: url('/images/puma.png');
  border: 2px solid black;
  cursor: default; 
}
.sea-slug-icon {
  background-image: url('/images/sea-slug.png');
  border: 2px solid blue;
  cursor: pointer; 
}
.egret-icon {
  background-image: url('/images/egret.png');
  border: 2px solid white;
  cursor: move; 
}

/* map列表 */
h1 {
  font-size: 2em; 
}
h2 {
  font-size: 1.5em; 
}
h3 {
  font-size: 1.2em; 
}

4、@while

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

4.1、编译前

$i: 6;
@while $i > 0 {
  .item-#{$i} { 
      width: 2em * $i; 
    }
  $i: $i - 2;
}

4.2、编译后

.item-6 {
  width: 12em; 
}

.item-4 {
  width: 8em; 
}

.item-2 {
  width: 4em; 
}

混合指令

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

1、定义混合指令@mixin

  • 混合指令的用法是在 @mixin 后添加名称与样式,比如名为 large-text 的混合通过下面的代码定义
  • 混合也需要包含选择器和属性,甚至可以用 & 引用父选择器:

语法

@mixin clearfix {
  display: inline-block;
  &:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
}

2、引用混合样式@include

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

2.1、语法

.wrapper{
  @include clearfix;
}

2.2、编译后

.wrapper {
  display: inline-block;
}
.wrapper:after {
  content: ".";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
}
* html .wrapper {
  height: 1px;
}

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

2.3、编译前

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

2.4、编译后

a {
  color: blue;
  background-color: red; 
}

混合样式中也可以包含其他混合样式

2.5、语法

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

3、带参

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

3.1、简单使用

3.1.1、编译前

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

3.1.2、编译后

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

3.2、赋默认值

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

3.2.1、编译前

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

3.2.2、编译后

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

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

3.3、关键词参数

混合指令也可以使用关键词参数,上面的例子也可以写成

  • 关键词参数可以打乱顺序使用,如果使用默认值也可以省缺
  • 参数名被视为变量名,下划线、短横线可以互换使用
p { 
    @include sexy-border($color: blue); 
}
h1 { 
    @include sexy-border($color: blue, $width: 2in); 
}

3.4、参数变量

  • 有时,不能确定混合指令需要使用多少个参数
  • 比如一个关于 box-shadow 的混合指令不能确定有多少个 ‘shadow’ 会被用到。
  • 这时,可以使用参数变量 声明(写在参数的最后方)告诉 Sass 将这些参数视为值列表处理

3.4.1、编译前

@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);
}

3.4.2、编译后

.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;
}

参数变量也可以用在引用混合指令的时候 (@include),与平时用法一样,将一串值列表中的值逐条作为参数引用

3.4.3、编译前

@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
  @include colors($values...);
}

3.4.4、编译后

.primary {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

4、向混合样式中导入内容

在引用混合样式的时候,可以先将一段代码导入到混合指令中,然后再输出混合样式,额外导入的部分将出现在 @content 标志的地方

4.1、编译前

@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

4.2、编译后

* html #logo {
  background-image: url(/logo.gif);
}

函数指令

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

1、定义函数

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

@function grid-width($n) {
    // 5 * 40 + (5-1) * 10 = 240
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

2、使用函数

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

3、编译后

#sidebar {
  width: 240px; 
}

内置函数

更多内置函数查看官网:Sass: sass:color (sass-lang.com)
注意:要先使用@use "sass:xxx"引入对应函数,然后才能使用

1、random

  • 当没有传参时(默认为null):返回一个介于0和1之间的随机十进制数。
  • random()忽略 l i m i t 中的单位。此行为已被弃用, r a n d o m ( limit中的单位。此行为已被弃用,random( limit中的单位。此行为已被弃用,randomlimit)将返回一个与$limit参数具有相同单位的随机整数

1.1、语法

// 引入样式
@use "sass:math"

math.random($limit: null)
random($limit: null) //=> number 

1.2、随机生成颜色

  • 只有每次重新编译才会生成
.wrapper{ 
  background-color: rgb(math.random(255), math.random(255), math.random(255));
}

CSS-预编译器-Sass_第9张图片

你可能感兴趣的:(前端,css,sass,前端)