Sass | Less

Syntactically Awesome Style Sheets

Sass&LESS
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 协议,转载请注明出处!