随着网页开发越发复杂,CSS 的可维护性也越显重要,但在 CSS 语法仍然受限的状况下,发展出了 CSS Preprocessor(CSS 预处理器)来扩展更多的写法。
本篇文章将介绍关于 CSS 预处理器的几个要点:
在过去,CSS 的基本语法与核心机制一直没有太多变化,大家普遍认为 CSS 的功能就是定义样式属性与排版,是一个入门简单的工具。
随着网页开发复杂度逐渐地提高,在开发大型项目时,许多网页开发者开始发现传统 CSS 有一些问题:
因为这些重复、可维护性差等缺点,于是开发者就开始思考若是能让 CSS 像一般程序语言一样,有变量、函数、循环等功能该有多好。
于是,CSS 预处理器就应运而生了!
CSS 预处理器可以说是 CSS 语法的扩充,为了弥补 CSS 在大型项目维护性的不足,CSS 预处理器中新增了变量、混入、继承、嵌套等写法,让开发者可以更有结构地撰写简洁、清晰且好维护的 CSS 代码。
现今较为主流的 CSS 预处理器有三种,分别是 Sass/SCSS、Less、Stylus,其中的 Sass/SCSS 是目前最多人使用也相对较成熟的选择。
而这些 CSS 预处理器相对于 CSS 算是较高阶的语法,需要另外编译成 CSS,浏览器才看得懂。
其实上面已经讲得差不多了,就像上面说的,CSS 预处理器比较适合用在开发大型项目、多人协作的场景,更能发挥它在可维护性上的效果。
举例像是通过 CSS 预处理器中变量(variables)的特性,可以在项目创建时统一定义全站的颜色对应表,在后期的开发只要通过类似 $primary-color
、 $warning-color
、 $danger-color
这样的写法,就能分别轻松配上主色、警告色、错误色的样式,甚至有个最大的优点是未来若是全站的颜色对应表要更换,只需要针对这些变量调整就好,不需要痛苦地一个一个 CSS 调整。
但若只开发是一般小型的个人 side project 或者单纯的活动案,或许使用传统的 CSS 就很足够了,也可以省去要创建编译 CSS 预处理器相关环境的麻烦。
讲了这么多 CSS 预处理器的好处,那到底实际上要怎么用呢?前面提到了三种较主流的 CSS 预处理器,这里以最常见的 Sass/SCSS 为例来做介绍。
或许你会很疑惑,为什么 Sass 都跟 SCSS 摆在一起讲,他们两者又有什么关系?这跟 Sass 的发展史有关,2007 年诞生的 Sass,是最早的 CSS 预处理器。旧版的 Sass 采用 Ruby 语言编写,最初为了配合 HAML(一种缩排式的 HTML 模版语法)的写法,也设计成缩排式的写法,所以在 Sass 的语法中不写大括号及分号,像是以下这一段 Sass 语法:
$font-stack: Helvetica, sans-serif
$primary-color: #333
body
font: 100% $font-stack
color: $primary-color
编译后会产生如下的 CSS:
body {
font: 100% Helvetica, sans-serif;
color: #333;
}
虽然这种缩排的风格可以减少一些代码,但却因为无法兼容旧有的 CSS 语法,所以一开始没有后来出现的 Less 那么普及。后来受到 Less 影响,Sass 发展出兼容 CSS 的新语法就称为 SCSS,也就是说在 SCSS 中直接撰写 CSS 也是完全没有问题的,因为在 SCSS 的语法中有大括号及分号,以前面的例子像是这样:
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
这样的写法其实跟原本的 CSS 没有太大的差异,又多了许多变量、mixins、nested rules 等更丰富的语法,这也是为什么 Sass/SCSS 越来越受欢迎的原因之一。
关于 Sass 的详细语法教程有许多文章中都有介绍了,这边就简单用几个示例示范 CSS 预处理器的几个常用的特性:变量(Variables)、函数(Functions)、嵌套(Nesting)、混入(Mixins)、共用(Extends)。
在开始前首先还是要了解怎么将 Sass 编译成 CSS,根据 官方安装方法 选择最基本的在 CLI 安装 Sass 编译器,在终端机输入以下这行:
npm install -g sass
安装好后在某个数据夹底下建立一个 input.scss
的文件,并且在该文件的位置下终端机执行这行:
sass --watch input.scss output.css
这是将 input.scss
编译成 output.css
的指令,而其中的 --watch
可以 hot-reload 接下来后面要测试的语法,直接针对 input.scss
文件每次的变化来编译成 CSS 文件。
前面有提到,若是要定义全站的颜色对应表(color-map)、字型相关样式等等,任何你认为未来会一直重复使用到,并且需要定义统一的 CSS 属性,就可以使用变量,概念与写 JavaScript 时定义变量是一样的。如下面例子分别是使用变量的 SCSS 及编译后的 CSS:
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
body {
font: 100% Helvetica, sans-serif;
color: #333;
}
除了变量之外,让开发 Sass 更像在写程序的特性就是 function 了,可以将重复使用的长度、大小计算等逻辑,抽象化成 function 的形式,如下面例子分别是使用 function 的 SCSS 及编译后的 CSS:
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
.sidebar {
float: left;
margin-left: pow(4, 3) * 1px;
}
.sidebar {
float: left;
margin-left: 64px;
}
这边实作一个指数函数 pow( ),可以看到语法是以 @function 为开头加上函数名称及参数,概念与一般写程序一样,甚至也可以用 for 循环、if/else 判断式,最后将结果值 return 给调用这个函数的地方。
当我们在撰写 HTML 时,可以轻易的写出 DOM 之间嵌套的阶层结构,但在传统的 CSS 做不到,需要重复写许多父元素选择器。
这问题可以使用 Sass 中嵌套的特性来解决,以下是 SCSS 及编译后的 CSS:
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
从这个例子可以看到编译后的 CSS 就像原本提到的问题,需要写许多 nav 这个父元素,但在 Sass 中可以直接像在写程序一样将父子元素这样一层一层包起来。
当有一段 CSS 设置经常性地被重复使用,甚至可以根据不同“参数”对应出相似的样式,就可以将这段设置独立写成一个 mixin 方便取用,参考下面的例子:
@mixin square($size, $radius: 0) {
width: $size;
height: $size;
@if $radius != 0 {
border-radius: $radius;
}
}
.avatar {
@include square(100px, $radius: 4px);
}
.card {
@include square(300px, $radius: 2px);
}
.avatar {
width: 100px;
height: 100px;
border-radius: 4px;
}
.card {
width: 300px;
height: 300px;
border-radius: 2px;
}
语法是用 @mixin 开头,并可以带入参数及默认值,其中也可以写 if/else 判断式等写法。设置好之后就可以在需要这一段 mixin 的选择器中使用 @include 引入。
mixin 可以说是 Sass 中一个强而有力的写法,甚至它还可以搭配 @content 的写法传入整段 CSS,想要看更多 mixin 的例子的话可以参考 Bootstrap 中 mixin 的代码 ,里面有更多深入的语法及应用。
有一种状况是当有一个选择器需要包含另一个选择器中的所有样式,或是许多选择器具有相同样式时,为了避免要一直重写同一组相同的 CSS 样式,在 Sass 中我们可以使用 Extends 的写法。
上面这段话稍微有点抽象,换句话说就是 Extends 可以将所有相同样式的内容合并,直接举个例子:
%message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
%equal-heights {
display: flex;
flex-wrap: wrap;
}
.message {
@extend %message-shared;
}
.success {
@extend %message-shared;
border-color: green;
}
.error {
@extend %message-shared;
border-color: red;
}
.warning {
@extend %message-shared;
border-color: yellow;
}
.warning, .error, .success, .message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
.warning {
border-color: yellow;
}
从上面的例子中可以看到,将要共用的样式用 %message-shared 包起来,并在其他要共用这一段样式的地方使用 @extend %message-shared ,这边可以注意到使用 Extends 的 Sass 语法编译成 CSS 后,在 CSS 中会将共用的部分统一集中管理。
另外也可以注意到在上面的 SCSS 中有另一段共用属性 %equal-heights 没有被其他人共用,在编译成 CSS 后并不会产生,所以这个写法又被称为“占位选择器(placeholder selector)”。
Mixins 与 Extends 两者的概念蛮相近的,由于两者都可以拿来做相同样式的包装,所以两者的使用时机很容易让人搞混。
举个例子将上面 Extends 的例子若用 Mixins 改写:
@mixin message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.message {
@include message-shared;
}
.success {
@include message-shared;
border-color: green;
}
.error {
@include message-shared;
border-color: red;
}
.warning {
@include message-shared;
border-color: yellow;
}
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: green;
}
.error {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: red;
}
.warning {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: yellow;
}
其中可以看出一个明显的差别就是,编译后的 CSS 会在每一个选择器都插入 mixin 中重复的部分,在这种完全相同的样式时,使用 Extends 处理会更好,而 Mixins 就拿来处理可以动态使用“参数”的类型。
在官方文档中也有对这个 疑问 作出解释,另外也举了一个 Extends 在 BEM 设计方法中的应用,有兴趣深入了解的读者可以研究研究,这边就不赘述。
Sass 中还有许多特性像是可以将单个文件切成多个 modules 引入、使用各种数据类型(Strings、Lists、Maps 等)、内置 functions 等,而上面介绍的几种语法也都有相对应深入且复杂的应用,这边只浅浅的点出最入门的部分。
其他更深入的语法建议仍可以参考 官方文档 ,应用的部分也可以参考一些知名大型项目怎么使用,像是 Bootstrap 的代码 中就有用到许多 SCSS 的写法。
随着网页开发越发复杂,CSS 的可维护性也越显重要,但在 CSS 语法仍然受限的状况下,发展出了 CSS 预处理器来扩展更多有弹性的写法。
本篇文章从介绍 CSS 预处理器的内容与使用时机,到实际利用 Sass/SCSS 介绍几个基本语法来展示其特性,希望能让读者对 CSS 预处理器相关的入门知识有更多了解。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。