Sass | Less
CSS 预处理器
CSS 预处理器是独有的语法来生成 CSS 的程序,如 Sass、Less、PostCSS。预处理器是一种脚本语言,在扩展 CSS 的同时,使其具有易于维护且可读性高的特点,并最终将其编译回常规 CSS 输出。
Sass|Scss
Sass 最初在 2006 年用 Ruby 编写的,使用缩进式语法来表示代码块和层级的关系,与 YML (YAML) 文件的语法非常相似。需要注意的是,目前 Sass 的官方推荐版本是用 Dart 语言重新实现的 Dart Sass,具有更快的编译速度和更好的兼容性。
尽管如此,后来的版本中引入了 SCSS(Sassy CSS)语法,该语法和普通的 CSS 语法几乎完全相同,只是添加了一些额外的功能,例如条件语句、循环和函数等。
Regular use of Sass
运行命令来安装 Sass 和 sass-loader,并在配置文件中使用相应的 loader 来处理 SCSS 文件。
npm install -D sass sass-loader
{
test: /\.scss$/,
use: [
'style-loader', // 将编译后的样式注入到 DOM 中
'css-loader', // 将 CSS 转换为 CommonJS 模块
'sass-loader' // 将 Sass 编译为 CSS
]
}
在完成上述的步骤后,就可以在项目中创建以 .scss
后缀结尾的文件,并使用 CSS 语法来编写样式。
变量插入
将变量视为一种存储信息的方式,在整个样式表中重复使用这些信息。存储诸如颜色、字体堆栈或任何 CSS 值之类的内容。Sass 使用 $ 符号来使某些数据成为变量。
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack; // font: 100% Helvetica, sans-serif;
color: $primary-color; // color: #333;
}
层次嵌套
Sass 可以嵌套 CSS 选择器,以遵循 HTML 的相同视觉层次结构。不过注意,使用过度的嵌套规则将导致高度耦合的 CSS,这会导致代码难以维护。
// sass代码
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
// 等价于css
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
Partials模块
创建模块化的 Sass 文件,其可以作为包含在其他 Sass 文件中的 CSS 片段,易于维护。Partial 是一个以下划线开头的 Sass 文件,其命名为 _partial.scss. 下划线让 Sass 知道该文件只是部分文件,不应将其生成为CSS文件。Sass 部分与@use 规则一起使用。
可以根据需要将 Sass 其拆分为 @use 规则。此规则将另一个 Sass 文件加载为 module,这意味可以使用基于文件名的命名空间在 Sass 文件中引用其变量、mixin和函数。使用文件还将在编译输出中包含它生成的 CSS。
// _base.scss
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
// styles.scss
@use 'base';
.inverse {
background-color: base.$primary-color;
color: white;
}
// 输出 css
body {
font: 100% Helvetica, sans-serif;
color: #333;
}
.inverse {
background-color: #333;
color: white;
}
Mixins
mixin 可以创建全局作用域中可复用的 scss 块,同时可以指定参数传入给 mixin。@mixin 作为复用代码块前缀常伴随 @include 调用并指定传参。
// scss
@mixin theme($theme: DarkGray) {
background: $theme;
box-shadow: 0 0 1px rgba($theme, .25);
color: #fff;
}
.info {
@include theme;
}
.alert {
@include theme($theme: DarkRed);
}
.success {
@include theme($theme: DarkGreen);
}
// css
.info {
background: DarkGray;
box-shadow: 0 0 1px rgba(169, 169, 169, 0.25);
color: #fff;
}
.alert {
background: DarkRed;
box-shadow: 0 0 1px rgba(139, 0, 0, 0.25);
color: #fff;
}
.success {
background: DarkGreen;
box-shadow: 0 0 1px rgba(0, 100, 0, 0.25);
color: #fff;
}
扩展与继承
@extend 允许将一组CSS属性从一个选择器共享到另一个选择器。它有助于保持你的 Sass 非常干燥。在我们的示例中,我们将使用另一个与扩展、占位符类齐头并进的功能,为错误、警告和成功创建一系列简单的消息传递。占位符类是一种特殊类型的类,仅在扩展时才打印,有助于保持编译后的CSS整洁干净。
// scss
// %message-shared 与 %equal-heights 不会被打印
%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;
}
// css
.message, .success, .error, .warning {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
.warning {
border-color: yellow;
}
算数操作Operate
在 SCSS 中可以进行数学运算,在 CSS 中可能需要借助 calc()。SCSS 拥有标准的数学运算符,+、-、*、/ 和 %。
.container {
width: 100%;
}
article[role="main"] {
float: left;
width: 600px / 960px * 100%;
}
aside[role="complementary"] {
float: right;
width: 300px / 960px * 100%;
}
// css
.container {
width: 100%;
}
article[role="main"] {
float: left;
width: 62.5%;
}
aside[role="complementary"] {
float: right;
width: 31.25%;
}
Less
操作函数
支持算术运算符、逻辑运算符等,以对任何数字、颜色或变量进行运算,甚至编码操作(scape)。
// if(condition, value1, value2)
@some: foo;
div {
margin: if((2 > 1), 0, 3px); // margin: 0;
color: if((iscolor(@some)), @some, black); // color: black;
}
// boolean
@bg: black;
@bg-light: boolean(luma(@bg) > 50%);
div {
background: @bg; // background: black;
color: if(@bg-light, black, white); // color: white;
}
变量插入
// Selectors
@my-selector: banner;
.@{my-selector} {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
// URLs
@images: "../img";
@themes: "../../src/themes";
body {
color: #444;
background: url("@{images}/white-sand.png");
}
@import "@{themes}/tidal-wave.less";
// Properties
@property: color;
.widget {
@{property}: #0ee;
background-@{property}: #999;
}
// Variable Variables
@primary: green;
@secondary: blue;
.section {
@color: primary;
.element {
color: @@color;
}
}
// Lazy Evaluation
.lazy-eval {
width: @var;
}
@var: @a;
@a: 9%;
// Properties as Variables
.block {
color: red;
.inner {
background-color: $color; // blue --> choose the last property within the current
}
color: blue;
}
// Default Variables --> 没大看懂,码个坑
父选择器
// Referencing parent selectors with &
a {
color: blue;
&:hover {
color: green;
}
} // a { color: blue;} a:hover { color: green; }
// Changing Selector Order
.header {
.menu {
border-radius: 5px;
.no-borderradius & {
background-image: url('images/button-background.png');
}
}
} // .no-borderradius .header .menu {...}
// Combinatorial Explosion -- 排列组合
p, a, ul, li {
border-top: 2px dotted #366;
& + & { // p + p, p + a, p + ul, p + li, a + p, a + a...li + li
border-top: 0;
}
}
拓展语法
// 扩展嵌套选择器
.bucket {
tr { // nested ruleset with target selector
color: blue;
}
}
.some-class:extend(.bucket tr) {} // nested ruleset is recognized
// 输出
.bucket tr,
.some-class {
color: blue;
}
组合属性
// 允许将多个属性的值聚合
.mixin() {
box-shadow+: inset 0 0 10px #555;
}
.myclass {
.mixin();
box-shadow+: 0 0 20px black;
}
// .myclass { box-shadow: inset 0 0 10px #555, 0 0 20px black; }
混合属性
// mix-in class selectors and id selectors
.a, #b {
color: red;
}
.mixin-class {
.a(); // color: red;
}
.mixin-id {
#b(); // color: red;
}
// Mixins With Parentheses
// 创建一个 mixin,但又不希望该 mixin 出现在 CSS 输出中
.my-mixin {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin();
.my-other-mixin();
} // .my-mixin { color: black; } .class { color: black; background: white; }
// Selectors in Mixins
.my-hover-mixin() {
&:hover {
border: 1px solid red;
}
}
button {
.my-hover-mixin();
} // button:hover { border: 1px solid red; }
// Guarded Namespaces -- 则仅当保护条件返回 true 时才使用由它定义的 mixin
#namespace when (@mode = huge) {
.mixin() { /* */ }
}
@import 规则
在标准 CSS 中,@importat 规则必须在所有其他类型的规则之前。但是 Less 并不关心你把 @import 语句放在哪里。@import 根据不同文件扩展名会以不同的方式处理语句:.css 扩展名将被视为 CSS 并且 @import 语句保持原样、有任何其他扩展名将被视为 Less 并导入、没有扩展名将作为导入的 Less 文件且 .less 将被附加包含在内。
@import "foo"; // foo.less is imported
@import "foo.less"; // foo.less is imported
@import "foo.php"; // foo.php imported as a Less file
@import "foo.css"; // foo.css is imported as a css file
Sass and Less selection
Sass 和 Less 都具有强大的功能特性,如变量、嵌套、混合、继承等,然而 Sass 在功能上会更加丰富一些,例如条件语句、循环和函数等。一般来说,Sass 的编译速度比较快,而 Less 的编译速度稍慢一些。但是,在实际应用中,这些差异可能并不明显,并不是决定性因素。通常来说,Sass 和 Less 都有庞大的社区支持,但 Sass 的生态系统更为成熟和广泛。
效果增强
阴影动画
// 鼠标经过上移阴影动画
.hoverShadow () {
transition: all .5s;
&:hover {
transform: translate3d(0,-3px,0);
box-shadow: 0 3px 8px rgba(0,0,0,0.2);
}
}
Bugs 处理
- sass 版本兼容问题
Node Sass version 6.0.0 is incompatible with^4.0.0
卸载之前版本,安装 node-sass@4.14.1,其他版本可能导致 bugs 仍然存在。
yarn add node-sass@4.14.1
- 关于 node-sass 里面 vendor 缺失
Syntax Error: Error: ENOENT: no such file or directory, scandir '...node_modules/node-sass/vendor'
可以找到缺失的文件直接从 node-sass 官网下载;或者删除 node_modules 重新下载;或者重新构建 node-sass。
npm rebuild node-sass
结束
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处!