1 CSS 预编译器
Less
预译器:将类 CSS 语言(Less(.less)、Sass(.scss)、Stylus 等)编译处理成浏览器可解析的真正 CSS。增强了 CSS 代码的复用性,还有嵌套、变量、循环、函数、mixin 等,具有很方便的 UI 组件模块化开发能力。
在 Node.js 环境中使用 Less:
// 比如全局安装 less:
npm install -g less;
// 转换编写好的 less 文件为 CSS
lessc styles.less styles.css
在浏览器环境中使用 Less :
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="https://cdn.jsdelivr.net/npm/less@4"></script>
采用变量定义属性值让属性值更具语义化,@定义变量,@{}变量插值,其中选择器中、属性名中、部分片段中:必须使用变量插值。
/* @定义变量 */
@width: 10px;
@height: @width + 10px;
@color: blue;
.heading {
width: @width;
height: @height;
margin: 5px;
padding: $margin; // 属性可直接作为变量使用
a {
color: @color; // white 变量支持提升和作用域嵌套
}
@color: white;
}
// 编译后
.heading {
width: 10px;
height: 20px;
margin: 5px;
padding: 5px;
}
.heading a {
color: white;
}
/* 选择器中使用变量插值 */
@banner: banner;
.@{banner} {
font-weight: bold;
}
/* 属性名中使用 */
@color: color;
.widget {
@{color}: #ffffff;
}
/* 属性值中的部分片段中使用 */
@images: '../images';
.bg-img {
background: url('@{images}/bg.png');
}
// 编译后
@banner: banner;
.banner {
font-weight: bold;
}
.widget {
color: #ffffff;
}
.bg-img {
background: url('../images/bg.png');
}
混合 mixin,可理解为可复用的样式片段。编译后,mixin 本身是否在 CSS 中输出取决于定义是否带括号。
/* 定义 mixin */
/* 不带括号,该 mixin 定义会输出在编译结果中 */
.my-mixin {
color: black;
}
/* 带括号,该 mixin 定义不会输出在编译结果中 */
.my-other-mixin() {
background-color: white;
}
/* 带选择器的 mixin 定义 */
.my-hover-mixin() {
&:hover { /* & 符号表示父选择器 */
border: 1px solid red;
}
}
/* 命名空间 mixin, 允许堆叠多个 id 或 class 可以减少和其他库 mixin 或用户 mixin 的冲突 */
#bundle {
.button() {
display: block;
&:hover {
background-color: white;
}
}
/* 允许添加条件形成受保护的命名空间,条件为 true 时才会使用 */
.minxin() when (@mode=huge) { /* */ }
}
.heading a {
color: orange;
#bundle.button();
}
/* mixin 允许使用参数(类型 JavaScript 中的函数), 包括参数默认值、命名参数(引用名称即可,不必按任何特殊顺序)、剩余参数(@rest...)、参数集(@arguments) */
/* 也支持将逗号分隔的列表值传递给单个参数 */
/* mixin 也允许重载 */
/* 在 mixin 调用后使用 !important 关键字会将其 mixin 内定义的所有属性标记为 !important */
.mixin(@color) {
color: @color;
}
.mixin(@color, @padding: 2) {
color: @color;
padding: @padding;
}
.mixin(@color, @padding, @marin: 2, @rest...) {
color: @color;
padding: @padding;
margin: @margin @margin @margin @margin;
}
/* 调用 mixin */
.class {
/* 调用 mixin 时可选的括号已经被弃用,因此一定要加括号 */
.my-mixin();
.my-other-mixin();
}
.button {
.my-hover-mixin();
}
.class-other {
#my-library.my-mixin(); /* > 语法已弃用 */
}
.some .selctor div {
.mixin(#008000) !important;
}
/* 编译后 */
.my-mixin {
color: black;
}
.class {
color: black;
background-color: white;
}
.button:hover{
border: 1px solid red;
}
.heading a {
display: block;
color: orange;
}
.heading a:hover {
background-color: #ffffff;
}
.some .selctor div {
color: #008000 !important;
padding: 2 !important;
}
/* mixin 中递归调用自身即可形成循环 */
.loop(@counter) when (@conter > 0) {
/* 递归调用自身 */
.loop(@counter - 1);
widht: (10px * @counter);
}
.container {
.loop(5);
}
/* */
.container {
width: 10px;
width: 20px;
width: 30px;
width: 40px;
width: 50px;
}
@media 或 @supports 等 at 规则能以与选择器相同的方式嵌套。编译后,at 规则位于外层,并且与同一规则集中的其他元素的相对顺序保持不变,这称为冒泡。
/* 编译前, at-rule 规则定义在选择器内部,更加统一 */
.component {
widht: 300px;
@media (min-width: 768px) {
width: 600px;
@media (min-resolution: 192dpi) {
background-image: url(/img/retina2x.png);
}
}
@media (min-width: 1280px) {
width: 800px;
}
}
/* 编译后 */
.component {
width: 300px;
}
@media (min-width: 768px) {
.component {
width: 600px;
}
}
@media (min-width: 768px) and @media (min-resolution: 192dpi) {
.component {
background-image: url(/img/retina2x.png);
}
}
@media (min-width: 1280px) {
.component {
width: 800px;
}
}
函数(Function):包括多种转换颜色、字符串操作、数学运算、参数检测的函数。
@base: #f04615;
@width: 0.5
.class {
width: percentage(@width); /* return 50% */
color: saturate(@base, 5%); /* 增加 5% 的饱和度 */
background-color: spin(lighten(@base, 25%), 8); /* lighten 亮度增加 25% 并使用 spin 旋转颜色的色调 8 deg, spin 不能直接传入颜色值,需要确保以保留色调的方式调用 */
}
/* 检测参数类型 */
iscolor
isnumber
isstring
iskeyword
isurl
/* 检测参数单位 */
ispixel
ispercentage
isem
isunit
注释(comments):less 支持块注释(即 css 注释:/* */)和行注释(//),由于在编译 less 代码时,行注释不会出现在结果 css 文件中,因此更多推荐在 less 中使用行注释。
2 CSS 后处理器
PostCSS
Postcss 是一个用 JavaScript 工具和插件转换 CSS 代码的工具。通过完整的插件化,Postcss 可以具有以下能力:
- 增强代码的可读性:利用从 Can I Use 网站获取的数据为 CSS 规则添加特定厂商的前缀。Autoprefixer 自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀。
- 将未来的 CSS 特性带到今天:PostCSS Preset Env 帮你将最新的 CSS 语法转换成大多数浏览器都能理解的语法,并根据你的目标浏览器或运行时环境来确定你需要的 polyfills,此功能基于 cssdb 实现。
- 终结全局 CSS:CSS 模块使得永远不用担心命名太大众化而造成冲突,只要用最有意义的名字就行了。
- 避免 CSS 代码中的错误:通过使用 stylelint 强化一致性约束并避免样式表中的错误。
PostCSS,通常被视为在完成的样式表中根据 CSS 规范处理 CSS,让其更有效。它的初始功能只有源文件生成 AST 树,AST 树生成新文件,借助插件机制实现定制化的功能,目前最常做的是给CSS属性添加浏览器私有前缀,实现跨浏览器兼容性的问题。
比如,插件 Autoprefixer 支持自动从 Can I Use 网站获取浏览器的流行度和能够支持的属性,并根据这些数据自动为 CSS 规则添加特定厂商前缀。实现简易版 Autoprefixer:
import postcss from 'postcss';
// 假设这是从 Can I Use 网站获取的浏览器兼容数据
const mockPrefixerConfig = {
// 需要添加厂商前缀的属性名
key: ['transform', 'opacity'],
// 需要添加厂商前缀的属性值
values: [{
name: display,
preValue: 'flex',
newValue: ['-webkit-box', '-webkit-flex', '-moz-box', '-ms-flexbox']
}]
}
const myPrefixPlugin = postcss.plugin('myPrefixPlugin', (opt) => {
return (ast) => {
opt = opt || {};
ast.each((node) => {
// node 是每一个 selector 选择器节点
node.each((declaration => {
// declaration 是当前 selector 选择器节点内的每一条规则声明,即属性:值
const { prop, value, cloneBefore } = declaration;
if (mockPrefixerConfig.key.includes(prop)) {
// 克隆规则声明节点并将生成的节点插入到当前节点之前
cloneBefore({ prop: `-webkit-${prop}`;
}
const item = mockPrefixerConfig.values.find((value) => value.name === prop);
item && item.preValue === value && item.newValue.forEach((newVal) => {
// 克隆规则声明并将生成的克隆节点插入到当前节点之前
cloneBefore({ value: newVal });
});
}
}
}
});
export default myPrefixPlugin;