Skip to main content

几种CSS预处理器比较选型

css的预处理器主流的大概有: SASS, LESS, Stylus;

https://tympanus.net/codrops/ 灵感

https://github.com/chokcoco/iCSS

https://zh.learnlayout.com/display css tips

css 模块化

css tips

css 预处理器介绍

why css preprocessor

CSS仅仅是一个标记语言,不是编程语言,因此不可以自定义变量,不可以引用

会带来的新问题

CSS的好处在于简便、随时随地被使用和调试。

预编译CSS步骤的加入,让我们开发工作流中多了一个环节,调试也变得更麻烦了。

更大的问题在于,预编译很容易造成后代选择器的滥用。

选型和对比

语法区别: https://zhuanlan.zhihu.com/p/38715068, https://efe.baidu.com/blog/revisiting-css-preprocessors/

============ sass 优点

sass 比 less 更像完整的编程语言, 有 变量 (全局, 局部区分), 函数, 作用域, 流程控制, 数据结构...,

有成熟的框架, 如 Compass, Foundation

社区热度比 less 更发达

还有Scss对sass语法进行了改良, 完全兼容 css 语法 (和 less 打平了)

bootstrap最新版就抛弃 less, 转向 sass了

丰富的 ruby api 支持, 适合开发 css 框架

=============== sass 缺点

但是 sass 安装需要 ruby 环境支持, less 只需要 引入 'less.js' 即可

开发工具也没有相应的sass编码提示

=================Stylus

来自node.js社区

人气不及sass, less

语法更简洁, 比如用缩进代替大括号

PostCSS

简单介绍 postcss

https://github.com/postcss/postcss git 仓库

不是 css preprocessor, 是一个使用JS插件来转换样式的工具 (检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片)

作为一个平台, 可以编写各种插件实现对 css 的处理, Autoprefixer 是最火的插件 (底层原理实际是 PostCSS 提供了一个解析器,它能够将 CSS 解析成抽象语法树(AST)。)

TailwindCSS 可以作为 postcss 的一个插件来使用

可以搜索插件 在这里 https://www.postcss.parts/ , 所有插件同时列在这里了 https://github.com/postcss/postcss/blob/main/docs/plugins.md

怎么使用 tailwindcss

tailwindcss 简介

css 原生写法 -> 零件化 (tailwindcss) -> 组件化 (bootstrap)

组件化封装度最高, 调整样式不方便, 自由度不高, 原生写法太麻烦

实际就是封装了大量的类, 直接使用就行了

这不就是内联样式吗, 为什么不用内联样式?

- tailwindcss 有约束, 数值都被封装为类了, 内联样式没有约束
- tailwindcss 可以使用伪类 (:hover ....)
- tailwinccss 可以通过 class 实现响应式

自定义postcss插件

https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md

SASS

https://www.bilibili.com/video/BV1Wb411Y7Ms?p=1 开发简历页面

//过时
// 解决 node-sass 无法下载问题
npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass

//推荐
//使用 dart-sass 替代 node-sass, 后者过时了
yarn add sass -D


LESS

Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。 Less 可以运行在 Node 或浏览器端。 LESS 做为 CSS 的一种形式的扩展,它并没有阉割 CSS 的功能,而是在现有的 CSS 语法上,添加了很多额外的功能

环境配置

npm install -g less

命令行使用:

  • 不压缩 lessc myStyle.less myStyle.css
  • 压缩后输出 lessc --clean-css styles.less styles.min.css

代码用法:

var less = require('less');

less.render('.class { width: (1 + 1) }', function (e, output) {// e: 异常, output: 输出
console.log(output.css);
// console.log(output.toCSS());
});

输出

.class {
width: 2;
}

render方法有更多配置项:

less.render('.class { width: (1 + 1) }',
{
paths: ['.', './lib'], // // Specify search paths for @import directives
filename: 'style.less', // // Specify a filename, for better error messages
compress: true // Minify CSS output
},
function (e, output) {
console.log(output.css);
});

浏览器端用法

需要在server下打开, 直接打开无效

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<!-- do not change the order -->
<link rel="stylesheet/less" type="text/css" href="css/index.less" />
<!-- download less.js, and import -->
<script src="lib/less.js" type="text/javascript"></script>
</head>
<body>
<div id="header">div-header</div>
<h2>h2 h2 h2</h2>
</body>
</html>

编写index.less即可

监视模式: 自动刷新

监视模式是客户端的一个功能,这个功能允许你当你改变样式的时候,客户端将自动刷新。

要使用它,只要在URL后面加上'#!watch',然后刷新页面就可以了。另外,你也可以通过在终端运行less.watch()来启动监视模式。

语法

变量

@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;

#header { color: @light-blue; }

输出

#header { color: #6c94be; }

混合

不带参数

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

#menu a {
color: #111;
.bordered;
}
.post a {
color: red;
.bordered;
}

输出

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

#menu a {
color: #111;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
.post a {
color: red;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}

带参数

.border-radius (@radius) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
}

#header {
.border-radius(4px);
}
.button {
.border-radius(6px);
}

参数有默认值

.border-radius (@radius: 5px) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
}

#header {
.border-radius; // radius值为默认: 5px
}

暂时隐藏css属性

.wrap () { // 里面的属性不会暴露到css, 只能被内部调用
text-wrap: wrap;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
word-wrap: break-word;
}

pre { .wrap }

@arguments变量

@arguments包含了所有传递进来的参数. 如果你不想单独处理每一个参数的话就可以像这样写

.box-shadow (@x: 0, @y: 0, @blur: 1px, @color: #000) {
box-shadow: @arguments;
-moz-box-shadow: @arguments;
-webkit-box-shadow: @arguments;
}
.box-shadow(2px, 5px);

输出

.box-shadow {
box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;
}

模式匹配(混合中的参数匹配)

只有被匹配的混合才会被使用。变量可以匹配任意的传入值,而变量以外的固定值就仅仅匹配与其相等的传入值。

.mixin (dark, @color) { // 第一个混合定义并未被匹配,因为它只接受dark做为首参
color: darken(@color, 10%);
}
.mixin (light, @color) { // 第二个混合定义被成功匹配,因为它只接受light
color: lighten(@color, 10%);
}
.mixin (@_, @color) {// 第三个混合定义被成功匹配,因为它接受任意值
display: block;
}
.mixin (@param) {...} // 不会匹配, 因为参数个数不对

@switch: light;

.class {
.mixin(@switch, #888);
}

输出

.class {
color: #a2a2a2;
display: block;
}

导引表达式(类似@media query)

单表达式

当我们想根据表达式进行匹配,而非根据值和参数匹配时,导引就显得非常有用

// 导引中表达式符号:  >, >=, =, =<, <, true; 
// 除了true之外的的值都被视为假
// 大于等于, 小于等于, 符号可以位置交换
.mixin (@a) when (lightness(@a) >= 50%) {// lightness是less内置函数
background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin (@a) {
color: @a;
}

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

输出

.class1 {
background-color: black;
color: #ddd;
}
.class2 {
background-color: white;
color: #555;
}

多表达式

[,] 表示 "或" [and] 表示"与"条件 [not] 表示 "非"

.mixin (@a) when (@a > 10), (@a < -10) { ... }

.mixin (@a) when not (@a < 50%) and not (@a < 5px){
font-size: 20px;
}

参数值类型判断(isXXX内置函数)

常见的检测函数:

iscolor:是否为颜色值。 isnumber:是否为数值。 isstring:是否为字符串。 iskeyword:是否为关键字。 isurl:是否为URL字符串。

以下是常见的单位检查函数:

ispixel:是否为像素单位。 ispercentage:是否为百分比。 isem:是否为em单位。 isunit:是否为单位。

.mixin (@a, @b: 0) when (isnumber(@b)) { ... }
.mixin (@a, @b: black) when (iscolor(@b)) { ... }

嵌套

#header {
h1 {
font-size: 26px;
font-weight: bold;
}
p { font-size: 12px;
a { text-decoration: none;
&:hover { border-width: 1px }// & 表示串联, 即[a]和[:hover]间没有空格
}
}
}

输出

#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p a:hover {
border-width: 1px;
}

运算

任何数字、颜色或者变量都可以参与运算.

@base: 5%;
@filler: @base * 2;
width: (@var + 5) * 2;
@other: @base + @filler;
@var: 1px + 5;// 输出6px

color: #888 / 4;
background-color: @base-color + #111;
height: 100% / 2 + @filler;
border: (@width * 2) solid black;

color函数

lighten(@color, 10%);     // return a color which is 10% *lighter* than @color
darken(@color, 10%); // return a color which is 10% *darker* than @color

saturate(@color, 10%); // return a color 10% *more* saturated than @color
desaturate(@color, 10%); // return a color 10% *less* saturated than @color

fadein(@color, 10%); // return a color 10% *less* transparent than @color
fadeout(@color, 10%); // return a color 10% *more* transparent than @color
fade(@color, 50%); // return @color with 50% transparency

spin(@color, 10); // return a color with a 10 degree larger in hue than @color
spin(@color, -10); // return a color with a 10 degree smaller hue than @color

mix(@color1, @color2); // return a mix of @color1 and @color2

hue(@color); // returns the `hue` channel of @color
saturation(@color); // returns the `saturation` channel of @color
lightness(@color); // returns the 'lightness' channel of @color

@new: hsl(hue(@old), 45%, 90%);// @new 将会保持 @old的 色调, 但是具有不同的饱和度和亮度.

Math函数

round(1.67); // returns `2`
ceil(2.4); // returns `3`
floor(2.6); // returns `2`
percentage(0.5); // returns `50%`

命名空间

// 先定义好
#bundle {
.button () {
display: block;
border: 1px solid black;
background-color: grey;
&:hover { background-color: white }
}
.tab { ... }
.citation { ... }
}

// 使用
#header a {
color: orange;
#bundle > .button;
}

作用域

@var: red;

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

#footer {
color: @var; // red
}

importing引入

// 你可以在main文件中通过下面的形势引入 .less 文件, .less 后缀可带可不带:
@import "lib.less";
@import "lib";
// 如果你想导入一个CSS文件而且不想LESS对它进行处理,只需要使用.css后缀就可以:
@import "lib.css";

字符串插值

// 变量可以用类似ruby和php的方式嵌入到字符串中,像@{name}这样的结构:
@base-url: "http://assets.fnord.com";
background-image: url("@{base-url}/images/bg.png");

避免编译

.class {
filter: ~"ms:alwaysHasItsOwnSyntax.For.Stuff()";
}

// 输出
.class {
filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}

JavaScript 表达式

// JavaScript 表达式也可以在.less 文件中使用. 可以通过反引号的方式使用
@var: `"hello".toUpperCase() + '!'`;
@height: `document.body.clientHeight`;// 访问JavaScript环境

// 输出
@var: "HELLO!";

css 模块化

css 框架

https://github.com/nostalgic-css/NES.css 像素风

https://github.com/papercss/papercss 手写风格

bootstrap 响应式布局框架 (bootstrap-react 库)

https://github.com/jgthms/bulma 响应式, 基于 Flexbox, 类似 Bootstrap

https://github.com/tailwindlabs/tailwindcss 高度自定义

https://github.com/palantir/blueprint react 组件库, 类似 antd

响应式页面