《大前端技术》 -- CSS 预处理器

1 什么预处理器

  • CSS 是什么;
  • CSS 的缺陷;
  • CSS 预处理器 是为了解决什么问题?
  • 常见的几款 CSS 预处理器:Sass, less, Stylus, Scss

CSS(层叠样式表)是一门历史悠久的标记性语言,同 HTML 一道,被广泛应用于万维网(World Wide Web)中。

HTML 主要负责文档结构的定义,CSS 负责文档表现形式或样式的定义。作为一门标记性语言,CSS 的语法相对简单,对使用者的要求较低,但同时也带来一些问题:CSS 需要书写大量看似没有逻辑的代码,不方便维护及扩展,不利于复用,尤其对于非前端开发工程师来讲,往往会因为缺少 CSS 编写经验而很难写出组织良好且易于维护的 CSS 代码,造成这些困难的很大原因源于 CSS 是一门非程序式语言,没有变量、函数、SCOPE(作用域)等概念。

为了加入一些编程元素,让 CSS 能像其他程序语言一样可以做一些预定的处理,CSS 预处理器 应运而生。 CSS 预处理器用一种专门的编程语言,进行样式设计,然后再编译成正常的 CSS 文件,以供项目使用。CSS 预处理器为 CSS 增加一些编程的特性,使用变量、简单的逻辑程序、函数等在编程语言中的一些基本特性,让 CSS 更加简洁、适应性更强、可读性更佳,更易于代码的维护。

使用最为普遍的几款 CSS 预处理器框架分别是 SASS、LESS 和 Stylus、Scss:
1.SASS:最早、最成熟的 CSS 预处理器,拥有 Ruby 社区的支持和 compass 这一最强大的 CSS 框架,目前受 LESS 影响,已经进化到了全面兼容 CSS 的 SCSS。SASS 使用.sass 扩展名
2.LESS:受 SASS 的影响较大,但又使用 CSS 的语法,更容易上手,在 Ruby 社区之外支持者远超过 SASS,其缺点是比起 SASS 来,可编程功能不够,优点是简单和兼容 CSS。LESS 影响了 SASS 演变到 SCSS,著名的 Twitter Bootstrap 就是采用 LESS 做底层语言的。LESS 使用.less 扩展名
3.Stylus:来自 Node.js 社区,主要用来给 Node 项目进行 CSS 预处理,在 node.js 社区内有一定支持者,但在广泛意义上人气还完全不如 SASS 和 LESS。Stylus 使用.styl 扩展名。Stylus 功能上更为强壮,和 JavaScript 联系更加紧密。
4.SCSS: Sass 和 SCSS 其实是同一种东西,我们平时都称之为 Sass,SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能。不同点:(1)文件扩展名不同,Sass 是以 “.sass” 后缀为扩展名,而 SCSS 是以 “.scss” 后缀为扩展名.(2)语法书写方式不同,Sass 是以严格的缩进式语法规则来书写,不带大括号 ({}) 和分号 (;),而 SCSS 的语法书写和我们的 CSS 语法书写方式非常类似(SCSS 和 CSS 写法无差别)。简单点说,把你现有的 “.css” 文件直接修改成 “.scss” 即可使用。

2 Less & Scss 简介

当前使用较多的预处理器为 Less & Scss,如上介绍,他们的语法其实都挺像的,所以可以放在一起介绍;

2.1 导入

lessscss 都可以通过 @import " "; 来实现文件的引入,从而实现模块化

新建一个 reset.less 文件,其内容如下

reset.less 全局样式文件
1
2
3
4
* {
margin: 0;
padding: 0;
}

在 style.less 文件中引入

style.less 中导入 reset
1
@import "reset.less";

2.2 注释

两者注释都是单行注释编译后不显示,多行注释显示。所以平时业务上代码尽量使用单行注释。

2.3 变量

2.3.1 普通变量

less 采用 @

less 普通变量
1
2
3
4
5
6
@number : 123px; // 定义变量

.box {
width: @number;
height: @number;
}

scss 采用 $

scss 普通变量
1
2
3
4
5
6
$number : 123px;

.box2 {
width: $number;
height: $number;
}

2.3.2 插值变量 @{xx}

less - 插值变量
1
2
3
4
5
6
7
8
@number : 123px;
@i : 2;
@wd : width;

.box@{i} {
@{wd} : @number;
height: @number;
}
scss - 插值变量
1
2
3
4
5
6
7
8
$number : 123px;
$i : 2;
$wd : width;

.box#{$i} {
#{$wd}: $number;
height: $number;
}

相当于:

1
2
3
4
.box2 {
width: 123px;
height: 123px;
}

2.4 封装性

2.4.1 作用域

less 作用域示例
1
2
3
4
5
6
7
8
@var: red;

#page {
@var: white;
#header {
color: @var; // white
}
}

这里要注意下,与 css 自定义属性一样,混合和变量的定义不必在引用之前事先定义,像下面这样定义与上面是一样的结果!

作用域优先级
1
2
3
4
5
6
7
8
@var: red;

#page {
#header {
color: @var; // white
}
@var: white;
}

2.4.2 嵌套

嵌套语法 在 less 与 sass 中是一样的。

2.4.2.1 选择器嵌套

选择器嵌套
1
2
3
4
5
6
7
8
9
.box2 {
width: 100px;
.box3 {
height: 100px;
li {
list-style: none;
}
}
}

2.4.2.2 伪类嵌套

伪类嵌套
1
2
3
4
5
6
.box2 {
width: 100px;
&:hover { // 在:hover 前加一个 & 用来连接
width: 200px;
}
}

2.4.2.3 属性嵌套

属性嵌套
1
2
3
4
5
6
7
8
.box {
margin: {
top: 10px;
bottom: 20px;
left: 10px;
right: 20px;
};
}

2.4.3 混合(Mixins)

混合(Mixin)是一种将一组属性从一个规则集包含(或混入)到另一个规则集的方法。说白了就是将两个样式类合并;

比如现在有一个 class

1
2
3
4
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}

如果想将上面这个规则复用其中的属性,则可使用混合

1
2
3
4
#menu a {
color: #111;
.bordered();
}

2.4.4 传参混合

混合可以使用传参:

less 混合可以使用传参
1
2
3
4
5
6
7
8
.hide(@color) {
display: none;
color: @color;
}
.box4{
width: 100px;
.hide(blue);
}

2.4.5 命名空间

有时,出于组织结构或仅仅是为了提供一些封装的目的,你希望对混合(mixins)进行分组。你可以用 更直观地实现这一需求。

命名空间使得样式集合有点面向对象的意思。less 中使用 # 号定义一个命名空间集合

less
1
2
3
4
5
6
7
8
9
10
11
12
13
#mm() {
.hide{
display: none;
}
.color{
color: red;
}
}

.box {
#mm.hide;
#mm.color;
}

相当于:

1
2
3
4
.box {
display: none;
color: red;
}

2.4.6 继承

less 继承
1
2
3
4
5
6
7
8
9
10
11
.show {
display: block;
color: red;
}

.box {
&:extend (.show); // &:extend () 语法
}
.box2 {
&:extend(.show);
}
scss 继承
1
2
3
4
5
6
7
8
9
10
11
%show {
display: block;
color: red;
}

.box {
@extend %show;
}
.box2 {
@extend %show;
}

相当于:

1
2
3
4
5
6
.show,
.box,
.box2 {
display: block;
color: red;
}

2.4.7 合并

less: + 会用 , 相互隔开,+_ 会用 空格 隔开。

less 合并
1
2
3
4
5
6
.box {
background+: url(a.png);
background+: url(b.png);
transform+_: scale(2);
transform+_: rotate(30deg);
}

scss 是使用 map-values () 函数表示 ,,使用 zip () 表示 空格

scss 合并
1
2
3
4
5
6
7
8
9
10
11
12
13
$background : (
a : url(a.png),
b : url(b.png)
);

$transform : (
a : scale(2),
b : rotate(30deg)
);
.box9 {
background: map-values($background);
transform: zip(map-values($transform)...);
}

上面结果:

1
2
3
4
.box {
background: url(a.png), url(b.png);
transform: scale(2) rotate(30deg);
}

2.5 运算

less 中的运算

less 中的运算
1
2
3
4
5
6
7
8
9
@sum : 10px;
.box {
width: @sum + 10px;
height: 10em + @sum;
border: @sum - 2px;
margin-top: 10px * 2;
padding: 20px / 10px;
margin: ~"20px / 10px";
}

在 less 中加法运算的时候如果两个单位不同则取第一个数的单位.

scss 中的运算

scss 中的运算
1
2
3
4
5
6
7
8
$sum : 10px;
.box {
width: $sum + 10px;
border: $sum - 2px;
margin-top: 10px * 2;
padding: 20px / 10px;
margin: (20px / 10px);
}

scss 中两个数进行运算必须单位相同

2.6 函数

scss 和 less 拥有内置函数,同时 scss 可自定义函数

两者的内置函数具体查官方文档:

less: http://lesscss.cn/functions/

scss: https://sass-lang.com/documentation/modules

scss 自定义函数
1
2
3
4
5
6
7
@function sum($a,$b) {
@return $a + $b;
}

.box {
width: sum(100px,200px);
}

2.7 判断与循环

2.7.1 条件语句

less 条件语句
1
2
3
4
5
6
7
8
9
10
@count : 3;
.get(@count) when (@count > 4) {
width: 100px + @count;
}
.get(@count) when (@count < 4) {
width: 10px + @count;
}
.box{
.get(@count);
}

when 就相当于 if,对括号里面的内容进行判断,上面语句的结果:

结果
1
2
3
.box {
width: 13px;
}

scss 的条件语句相比 less 简单一些,直接在 if,else 前加一个 @, 也可以写 else if

scss 条件语句
1
2
3
4
5
6
7
8
9
$count : 5;
.box11 {
@if ($count > 4) {
width: 100px + $count;
}
@else{
width: 10px + $count;
}
}

2.7.2 循环语句

less 的循环采用的是递归的思想,通过调用自己来完成循环

less 循环语句
1
2
3
4
5
6
7
8
9
10
@number1 : 0;

.get(@cn) when (@cn < 3) {
.box-@{cn}{
width: 100px + @cn;
}
.get(@cn + 1);
}

.get(@number1);

生成 css 如下:

1
2
3
4
5
6
7
8
9
.box-0 {
width: 100px;
}
.box-1 {
width: 101px;
}
.box-2 {
width: 102px;
}

scss 的循环支持 for 循环,while 循环等,用法也很简单

scss 循环语句
1
2
3
4
5
@for $i from 0 through 2 {
.box#{$i}{
width: 100px + $i;
}
}

结果输出与 less 示例相同。

2.7.3 媒体查询

less 和 scss 媒体查询基本相同,@ 规则(例如 @media 或 @supports)可以与选择器以相同的方式进行嵌套。@ 规则会被放在前面,同一规则集中的其它元素的相对顺序保持不变。这叫做 冒泡(bubbling)

less 媒体查询
1
2
3
4
5
6
7
8
9
10
11
12
.component {
width: 300px;
@media (min-width: 768px) {
width: 600px;
@media (min-resolution: 192dpi) {
background-image: url(/img/retina2x.png);
}
}
@media (min-width: 1280px) {
width: 800px;
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.component {
width: 300px;
}
@media (min-width: 768px) {
.component {
width: 600px;
}
}
@media (min-width: 768px) and (min-resolution: 192dpi) {
.component {
background-image: url(/img/retina2x.png);
}
}
@media (min-width: 1280px) {
.component {
width: 800px;
}
}

3 引用

  1. 《Scss&Less初探,学会基本的使用方式》- 止水