css预处理器

115 阅读15分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

写在前面

随着css的发展,诞生了很多css预处理器,用来处理css代码不能复用,不利于维护的特点。这篇文章我们主要来学习两种比较典型常用的css预处理器:less和scss

css预处理器

css预处理器是一种新的编程语言,为css增加一些编程特性,不需要考虑浏览器兼容问题。然后再编译生成css文件。

在css预处理器出来之前,css没有变量,样式复用,代码很难维护,而且没有不支持嵌套的写法,css预处理器正是为了解决这些痛点的。

css预处理器的特点

  1. 增强编程能力,可复用性,可维护性,使浏览器具有更好的兼容性,从而提高开发效率
  2. 是一种基于css的编程语言,通过中间件工具编译成css文件
  3. 增加了一些css不具备的新特性,提升css的文件组织

less

less 是一门css预处理语言,它扩展了css语言,增加了变量,mixin和函数等特性,使css更易维护和扩展。less可以运行在node环境和浏览器中。

1. 使用less

1.1 安装

npm install -g less

1.2 命令行用法

编译命令:

lessc styles.less

编译具体文件

lessc styles.less styles.css

1.3 node环境直接引用

var less = require('less');
less.render('.class{width: (1 + 1)}', 
{
  path: ['.', './lib'],
  filename: 'style.less',
  compress: true
},
function(e, output) {
  console.log(output.css);
}) 

1.4 浏览器端用法

<link rel="stylesheet/less" type="text/css" href="styles.less">

下载less.js。

<script src="less.js" type="text/javascript"></script>

也可以配置选项

<script>
  less = {
    env: "development",
    async: false,
    fileAsync: false,
    poll: 1000,
    functions: {},
    dumpLineNumbers: "comments",
    relativeUrls: false,
    rootpath: ":/a.com/"
  };
</script>
2. less语法介绍

2.1 变量

语法格式:定义变量是以@开头

2.1.1 定义属性值变量

@link-color: #428bca;
@link-color-hover: darken(@link-color, 10%);

a, .link {
  color: @link-color;
}
a:hover {
  color: @link-color-hover;
}
.widget {
  color: #ffff;
  background: @link-color;
}

2.1.2 定义选择器变量

@my-selector: banner;

.@{my-selector} {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

编译结果为:

.banner {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

从上面的例子中可以看出,如果将变量和别的属性或者字符串连在一起,使用@{变量名称}的方式。

2.1.3 使用变量定义变量

@primary: green;
@secondary: blue;

.section {
  @color: primary;

  .element {
    color: @@color;
  }
}

编译结果:

.selection .element {
  color: green;
}

2.1.4 变量也是有作用域的

@var: 0;
.class {
  @var: 1;
  .brass {
    @var: 2;
    three: @var;
    @var: 3;
  }
  one: @var
}

编译结果:

.class {
  one: 1;
}
.class .brass {
  three: 3;
}

2.2 父选择器

&操作符表示嵌套规则的父选择器,最常用于将修改类或伪类应用到现有选择器。

2.2.1 基本用法

a {
  color: blue;
  &:hover {
    color: green;
  }
}

编译结果:

a {
  color: blue;
}
a: hover {
  color: green;
}

2.2.2 &还可以多个嵌套

.link {
  & + & {
    color: red;
  }
  & & {
    color: green;
  }
}

2.3 extend继承

extend是一个less伪类,它将它所使用的选择器与它所引用的选择器相匹配。

2.3.1 基本用法

nav ul {
  &:extend(.inline);
  background: blue;
}
.inline {
  color: red;
}

编译结果:

nav ul {
  background: blue;
}
.inline, nav ul {
  color: red;
}

2.3.2 extend附加到选择器

extend可以附加到选择器,也可以放入规则集中。它看起来像一个伪类,选择器参数后面可选地跟着关键字all

.a:extend(.b) {};
// 相当于下面这种写法
.a {
  &:extend(.b);
}

.c:extend(.d all) {};
// 相当于下面这种写法
.c:extend(.d) {}

// extend也可以继承多个类
.e:extend(.f) {}
.e:extend(.g) {}
// 相当于下面这种写法
.e:extend(.f, .g) {}

上面的这种写法是依附于选择器的,下面介绍的这种写法是放入规则集中的。语法是&:extend(选择器), 是将其放置到该规则集的每一个选择器中的捷径。

2.3.3 extend运用到规则集

pre:hover,
.some-class {
  &:extend(div pre);
}

放入规则集的写法相当于是在每个选择器后面都添加了一个extend伪类。

pre:hover:extend(div pre),
.some-class:extend(div pre) {}

2.3.4 extend匹配嵌套选择器

extend能够匹配嵌套选择器,比如less

.bucket {
  tr {
    color: blue;
  }
}
.some-class:extend(.bucket tr) {}

编译结果:

.bucket tr, .some-class {
  color: blue;
}

nth表达式在继承中是匹配不了的,因此不支持

:nth-child(1n+3) {
  color: blue;
}
.child:extend(:nth-child(1n+3)) {}

编译结果:

:nth-child(1n+3) {
  color: blue;
}

同样地,类似于这种*.class这种匹配选择器的也不能在继承中匹配。

2.4 merge合并

merge合并就是将来自多个属性的值聚合到单个属性下的逗号或空格分隔的列表中。合并对于背景和转换等属性很有用。

2.4.1 合并基本用法

.mixin() {
  box-shadow+: inset 0 0 10px #555;
}
.myclass {
  .mixin();
  box-shadow+: 0 0 20px black;
}

编译结果:

.mixin() {
  box-shadow+: inset 0 0 10px #555;
}
.myclass {
  box-shadow+: inset 0 0 10px #555, 0 0 20px black;
}

2.5 mixins混入模式

2.5.1 混入选择器的方式引入mixin

.a, #b {
 color: red;
}
.mixin-class {
 .a();
}
.mixin-id {
 #b();
}

编译结果:

.a, #b {
 color: red;
}
.mixin-class {
 color: red;
}
.mixin-id {
 color: red;
}

2.5.2 想要创建混入样式,但是不想被编译

.my-mixin {
  color: black;
}
.my-other-mixin() {
  background: white;
}
.class {
  .my-mixin();
  .my-other-mixin();
}

编译结果:

.my-mixin {
  color: black;
}
.class {
  color: black;
  background: white;
}

2.5.3 混入不仅仅只是混入样式,更也可以包含选择器

.my-hover-mixin() {
  &:hover {
    border: 1px solid red;
  }
}
button {
  .my-hover-mixin();
}

编译结果:

.my-hover-mixin:hover {
  border: 1px solid red;
}
button:hover {
  border: 1px solid red;
}

2.5.4 命名空间

#outer() {
  .inner {
    color: red;
  }
}

.c {
  #outer.inner();
}

2.5.5 !important 关键字

.foo(@bg: #f5f5f5; @color: #900) {
  background: @bg;
  color: @color;
}
.unimportant {
  .foo();
}
important {
  .foo() !important;
}

编译结果:

.unimportant {
  background: #f5f5f5;
  color: #900;
}
.important {
  background: #f5f5f5 !important;
  color: #900 !important;
}

2.5.6. mixin混入传参

.border-radius(@radius) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}
#header {
  .border-radius(4px);
}
.button {
  .border-radius(6px);
}

编译结果:

#header {
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
}
.button {
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px;
}

2.5.7 按照函数的方式使用混入

.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  padding: .average(16px, 50px)[@result];
}

编译结果:

div {
  padding: 33px;
}

2.6 运算符

less具有运算的特性,也就是对数值型的value进行运算。

@base: 5%;
@filter: @base * 2;   // 10%
@other: @base + @filter; // 15%
@color: (#224488 / 2); // #112244
background-color: #112244 + #111; // #223355

2.7 计算calc()

@var: 50vh/2;
width: calc(50% + (@var - 20px));  // calc(50% + (25vh - 20px));

2.8 函数功能

@base: #f04615;
@width: 0.5;

percentage(@width) {
  @result: (@width * 100) + '%';
}
.class {
  width: percentage(@width); // 50%
}

2.9 嵌套

#header {
  color: black;
  .navigation {
    font-size: 12px;
  }
  .logo {
    width: 300px;
  }
}

编译结果:

#header {
  color: black;
}
#header .navigation {
  font-size: 12px;
}
#header .logo {
  width: 300px;
}

2.10 @import插值

在less中使用插值的语法是@{变量名}

@device: 'mobile';
@import 'style.@{device}.css'

2.11 @import

语法格式如下:

@import (keyword) 'filename';

其中keyword可以是如下几种选项(可以联合使用):

  1. **reference:**使用一个外部文件参与编译,但不输出其内容。
  2. **inline:**直接将引入的文件放入输出文件中,但不处理这个引入的文件。
  3. **less:**不管文件扩展名是什么都将该文件作为一个LESS文件处理。
  4. **css:**不管文件扩展名是什么都将该文件作为一个CSS文件处理。
  5. **once:**只引入文件一次(去重),这是默认方式。
  6. **multiple:**可以引入文件多次。
// foo.less
.a {
  color: green;
}
// main.less
@import (multiple) 'foo.less';

编译结果:

.a {
  color: green;
}
.a {
  color: green;
}

2.12 逻辑控制

2.12.1 判断

在less中通过guarded mixins代替if/else, 利用关键字'when'来实现简单的条件判断。

.mixin (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin (@a) {
  color: @a;
}

2.12.2 循环

使用when来模拟for循环的特性

.loopingClass (@index) when (@index > 0) {
  .myStyle {
    z-index: @index;
  }
  // 递归
  .loopingClass(@index - 1);
}
// 停止循环
.loopingClass(0){};
// 输出
.loopingClass(3);

scss

scss是sass的一种语法格式,这种格式仅在css3语法的基础上进行拓展,加入sass的特色功能,支持大多数CSS hacks写法以及浏览器前缀写法,文件名以.scss结尾。

SASS还有一种语法格式,也是之前很早的sass语法格式。这种文件格式以.sass结尾。对于现在的我们来说,我们采用的一般都是scss的语法格式,下面介绍的也是scss语法格式。

1. 使用scss

Sass 可以通过以下三种方式使用:作为命令行工具;作为独立的 Ruby 模块 (Ruby module);或者作为 Rack-enabled 框架的插件(例如 Ruby on Rails 与 Merb)。无论哪种方式都需要先安装 Sass gem (Windows 系统需要先安装 Ruby)

1.1 安装

gem install sass

1.2 作为命令行工具使用

  1. 编写你的.scss文件index.scss,里面写好你的scss语法
  2. 编译index.scss文件
    sass index.scss output.css
    

对于其他的两种方式感兴趣的可以参考官网: www.sass.hk/docs/

2. scss的语法

2.1 变量

2.1.1 变量的基本用法

变量以$符号开头,赋值方法和css属性一样。

$width: 200px;

直接使用变量

#main {
  width: $width;
}

2.1.2 变量的块级作用域

变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量可在任何地方使用(全局变量),将布局变量转成全局变量的方法就是添加!global声明

#main {
  $width: 200px !global;
  width: $width;
}
#sidebar {
  width: $width;
}

编译结果:

#main {
  width: 200px;
}
#sidebar {
  width: 200px;
}

2.1.3 变量使用!default

在变量的结尾添加!default给一个未通过!default声明赋值的变量赋值,此时,如果变量已经被赋值,将不能被再次赋值。如果变量还没被赋值,则可以被赋其他的值。

$content: 'First content';
$content: 'Second content?' !default;
$new_content: 'First time reference' !default;

#main {
  content: $content;
  new-content: $new_content;
}

编译结果:

#main {
  content: 'First content';
  new-content: 'First time reference';
}

变量是null空值时将视为未被!default赋值.

$content: null;
$content: 'Non-null content' !default;

#main {
  content: $content;
}

编译结果:

#main {
  content: 'Non-null content';
}

2.2 数据类型

在SassScript中支持6种主要的数据类型:

  1. 数字:1, 2, 13, 10px
  2. 字符串: 有引号字符串和无引号字符串,'foo', 'bar', baz
  3. 颜色: blue, #04a3f9, rgba(255, 0, 0, 0.5)
  4. 布尔型: true,false
  5. 空值: null
  6. 数组: 用空格或逗号作分隔符,1.5em, 1em, 0, 2em Helvetica Arial sans-serif
  7. maps: 相当于JavaScript的object,(key1: value1, key2: value2)

2.3 嵌套

嵌套在scss中非常常见,主要有下面几种嵌套情况

2.3.1 内层样式将它外层的选择器作为父选择器嵌套

 $width: 200px;
 .test_box {
   width: $width;
   height: 500px;
   .child_box {
     width: 100px;
     height: 100px;
   }
 }

编译结果:

 .test_box {
   width: 200px;
   height: 500px;
 }
 .test_box .child_box {
   width: 100px;
   height: 100px;
 }

2.3.2 &嵌套

这种嵌套和上面那种嵌套方式最大的区别就是上面那种只是按照文档结构将选择器按照嵌套的方式编写,节省代码,而&是从选择器的名称就开始嵌套了。&嵌套的是最外层的父选择器

a {
  font-weight: bold;
  text-decoration: none;
  &:hover {
    text-decoration: underline;
  }
  test_box & {
    font-weight: normal;
  }
}

编译结果:

a {
  font-weight: bold;
  text-decoration: none;
  a:hover {
    text-decoration: underline;
  }
  test_box a {
    font-weight: normal;
  }
}

&作为选择器的第一个字符,其后可以跟随后缀生成复合的选择器,例如:

#main {
  color: black;
  $-sidebar {
    border: 1px solid;
  }
}

编译结果:

#main {
  color: black;
  #main-sidebar {
    border: 1px solid;
  }
}

2.3.3 属性嵌套

有些CSS属性遵循相同的命令空间(namespace),比如font-family, font-size, font-weight都以font作为属性的命名空间。为了便于管理这样的属性,同时也为了避免重复输入,Sass允许将属性嵌套在命名空间中。

.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}

编译结果:

.funky {
  font-family: fantasy;
  font-size: 30em;
  font-weight: bold;
}

命名空间也可以包含自己的属性值

.funky {
  font: 20px/40px {
    family: fantasy;
    weight: bold;
  }
}

编译结果:

.funky {
  font: 20px/40px;
  font-family: fantasy;
  font-weight: bold;
}
2.4 运算

2.4.1 数字运算

.child_box {
  width: 100px;
  height: 100px + 300px;
}

编译结果:

.child_box {
  width: 100px;
  height: 400px;
}

2.4.2 颜色值运算

p {
  color: #010203 + #040506;
}

编译结果:

p {
  color: #050709;
}

2.4.3 字符串运算

+可用于连接字符串

p {
  cursor: e + -resize;
}

编译结果:

p {
  cursor: e-resize;
}

注意:如果有引号字符串(位于+左侧)连接无引号字符串,运算结果是有引号的,相反,无引号字符串(位于+左侧)连接有引号字符串,运算结果无引号。

p:before {
  content: 'Foo' + Bar;
  font-family: sans- + 'serif';
}

编译结果:

p:before {
  content: 'Foo Bar';
  font-family: sans-serif;
}

运算表达式与其他值连用时,用空格做连接符:

p {
  margin: 3px + 4px auto;

编译结果:

p {
  margin: 7px auto;
}

在有引号的文本字符串中使用#{}插值语句可以添加动态的值

p:before {
  content: 'I ate #{5 + 10} pies!';
}

编译结果:

p:before {
  content: 'I ate 15 pies!';
}

空的值被视作插入了空字符串

$value: null;
p:before {
  content: 'I ate #{value} pies!';
}

编译结果:

p:before {
  content: 'I ate pies!';
}

2.4.4 布尔运算

SassScript支持布尔型的and or 以及not运算。

2.4.5 数组运算

数组不支持任何运算方式,只能使用list functions控制。

2.4.6 圆括号

圆括号可以用来影响运算的顺序

p {
  width: 1em + (2em * 3);
}

编译结果:

p {
  width: 7em;
}

2.5 函数

这里的函数指的是在css属性值可以使用函数。

p {
  color: hsl(0, 100%, 50%);
}

编译结果:

p {
  color: #ff0000;
}

函数也可以使用关键字参数

p{
  color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}

2.6 插值语句

前面我们在运算中使用到了插值语句,其实插值语句还可以在选择器或属性名中使用变量。

$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}

编译结果:

p.foo {
  border-color: blue;
}

#{}插值语句也可以在属性值中插入SassScript, 大多数情况下,这样写还不如变量方便,但是这样可以避免Sass运行运算表达式,直接编译CSS。

p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}

编译结果:

p {
  font: 12px/30px;
}

2.7 混合指令

混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语义的class, 比如.float-left。混合指令可以包含所有的CSS规则,绝大部分Sass规则,甚至通过参数功能引入变量,输出多样化的样式。

2.7.1 定义混合指令@mixin

混合指令的用法是在@mixin后添加名称与样式,比如名为large-text的混合通过下面的代码定义:

@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}

混合也需要包含选择器和属性,甚至可以用&引用父选择器:

@mixin clearfix {
  display: inline-block;
  &:after {
    content: '.';
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
  * html & {
    height: 1px;
  }
}

2.7.2 引用混合样式@include

使用@include指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选)

.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

编译结果为

.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px;
}

2.7.3 参数

参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:

@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p {
  @include sexy-border(blue, 1px);
}

编译结果:

p {
  border-color: blue;
  border-width: 1px;
  border-style: dashed;
}

混合指令也可以使用给变量赋值的方法给参数设定默认值,然后,当这个指令被引用的时候,如果没有给参数赋值,则直接使用默认值。

@mixin sexy-border($color, $width: 1px) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p {
  @include sexy-border(blue);
}
h1 {
  @include sexy-border(blue, 2px);
}

编译结果:

p {
  border-color: blue;
  border-width: 1px;
  border-style: dashed;
}
h1 {
  border-color: blue;
  border-width: 2px;
  border-style: dashed;
}

混合指令也可以使用关键词参数,上面的例子可以改写成

p {
  @include sexy-border($color: blue);
}
h1 {
  @include sexy-border($color: blue, $width: 2px);
}

如果不能确定混合指令需要使用多少个参数,可以将参数视为值列表处理:

@mixin box-shadow($shadows...) {
  -moz-box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
  box-shadow: $shadows;
}
.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

编译结果:

.shadows {
  -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

参数变量在可以用在引用混合指令的时候,将一串值列表中的值逐条作为参数引用:

@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
  @include colors($values...);
}

编译结果:

.primary {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

2.7.4 向混合样式中导入内容

在引用混合样式的时候,可以先将一段代码导入到混合指令中,然后再输出混合样式,额外导入的部分将出现@content标志的地方:

@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

编译结果为:

* html #logo {
  background-image: url(/logo.gif);
}

这种情况下,为了方便书写,@mixin可以用=表示,而@include可以用+表示,这样上面的例子可以写成:

=apply-to-ie6-only {
  * html {
    @content;
  }
}
+apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

2.8 函数指令

Sass支持自定义函数,并能在任何属性值或Sass script中使用:

$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar {
  width: grid-width(5);
}

编译结果:

#sidebar {
  width: 240px;
}

与mixin相同,也可以传递若干全局变量给函数作为参数。一个函数可以含有多条语句,需要调用@return输出结果。 自定义的函数也可以使用关键词参数,上面的例子还可以这样写:

#sidebar {
  width: grid-width($n: 5);
}

2.9 @-Rules与指令

Sass支持所有的CSS3@-Rules,以及Sass特有的'指令'。

2.9.1 @import

只有文件名是.scss或.sass的才会导入,下列情况不会导入文件,而是会将该语句视作普通css语句。

  • 文件拓展名是.css
  • 文件名以http://开头
  • 文件名是url()
  • @import包含media queries
@import 'foo.scss'

这种用法文件中的scss代码会被编译成css,如果不想被编译成css,可以使用以下用法: 将文件名命名为_foo.scss, 导入的时候使用下面的指令

@import 'foo';

@import还有另外一种经常被用到的用法就是嵌套@import。在大多数情况下,一般在文件的最外层(不在嵌套规则里)使用@import, 其实也可以将文件的css嵌入到css样式中。 比如在example.scss文件中有以下样式:

.example {
  color: red;
}

现在要将这个样式导入到#main样式内。

#main {
  @import "example";
}

编译结果为:

#main .example {
  color: red;
}

2.9.2 @media

@media和css中的用法类似,如果@media用在了嵌套规则里面,编译的时候也会被编译到文件的最外层, 包含嵌套的父选择器。

.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}

编译结果为

.sidebar {
  width: 300px;
}
@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px;
  }
}

@media screen { .sidebar { @media (orientation: landscape) { width: 500px; } } } 编译结果为

@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px;
  }
}

2.9.3 @extend

如果一个元素的样式与另一个元素的样式完全相同,但是有有特定的自己的样式,这种情况下就很适合使用@extend,这个指令可以继承样式,同时又可以添加自己的样式。

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

这时候其他使用到.error的样式同样也会继承给.seriousError。比如下面这种情况:

// .error在别的地方也使用到
.error.intrusion {
  background-image: url('/image/hacked.png');
}

编译结果为

.error, .seriousError {
  border: 1px #foo;
  background-color: #fdd;
}
.error.intrusion, .seriousError.intrusion {
  background-image: url('/image/hacked.png');
}

除了继承选择器之外,@extend还可以继承任何定义给单个元素的选择器

.hoverlink {
  @extend a:hover;
}
a:hover {
  text-decoration: underline;
}

编译结果:

a:hover .hoverlink {
  text-decoration: underline;
}

除此之外,一个选择器还可以继承多个选择器的样式,别的选择器也可以继承这个选择器,实现继续继承

2.9.4 @at-root

@at-root指令在平时的使用比较少,会导致一个或多个规则在文档的根位置发出,而不是嵌套在它们的父选择器下面。它可以与单个内联选择器一起使用:

.parent {
  ...
  @at-root {
    .child1 { ... }
    .child2 { ... }
  }
  .step-child { ... }
}

编译结果为:

.parent { ... }
.child1 { ... }
.child2 { ... }
.parent .step-child { ... }

2.9.5 @debug

@debug指令将SassScript表达式的值打印到标准错误输出流。它对于调试带有复杂SassScript的Sass文件非常有用。平时用到的也比较少

@debug 10em + 12em;

编译结果:

Line 1 DEBUG: 22em

2.9.6 @warn

@warn指令将SassScript表达式的值打印到标准错误输出流。它对于那些需要警告用户弃用或从mixin使用错误中恢复的库非常有用。这个指令在平时开发中用的也比较少。@warn和@debug有两个主要区别:

  • 您可以使用——quiet命令行选项或:quiet Sass选项关闭警告。
  • 样式表跟踪将与消息一起打印出来,以便被警告的用户可以看到他们的样式在哪里引起警告。
@mixin adjust-location($x, $y) {
  @if unitless($x) {
    @warn "Assuming #{$x} to be in pixels";
    $x: 1px * $x;
  }
  @if unitless($y) {
    @warn "Assuming #{$y} to be in pixels";
    $y: 1px * $y;
  }
  position: relative; left: $x; top: $y;
}

2.9.7 @error

@error指令将SassScript表达式的值作为致命错误抛出,包括一个漂亮的堆栈跟踪。它对于验证mixin和函数的参数很有用。这个指令在平时开发中用的也比较少。例如:

@mixin adjust-location($x, $y) {
  @if unitless($x) {
    @error "$x may not be unitless, was #{$x}.";
  }
  @if unitless($y) {
    @error "$y may not be unitless, was #{$y}.";
  }
  position: relative; left: $x; top: $y;
}

2.10 控制指令

控制指令主要是和mixin配合使用。

2.10.1 @if

@if和js中的js语句差不多, 当@if的表达式返回值不是false或null等,条件成立,就会执行{}里面的语句。

p {
  @if 1 + 1 == 2 { border: 1px solid; }
  @if 5 < 3 { border: 2px dotted; }
  @if null { border: 3px double; }
}

编译结果:

p { border: 1px solid; }

@if和if类似,它也有@else if和@else声明,比如下面这种用法:

$type: monster;
p {
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else if $type == monster {
    color: green;
  } @else {
    color: black;
  }
 }

编译结果:

p { color: green; }

2.10.2 @for

@for指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包括两种格式:@for varfrom<start>through<end>或者@forvar from <start> through <end> 或者 @for var from to 。through格式中包含start和end,而在to中,只包含start,不包含end.

@for $i from 1 through 3 {
  .item-#{$i} {
    width: 2em * $i;
  }
}

编译结果:

.item-1 {
  width: 2em;
}
.item-2 {
  width: 4em;
}
.item-3 {
  width: 6em;
}

2.10.3 @each

@each指令的格式是@var in

@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

编译结果为:

.puma-icon {
  background-image: url('/images/puma.png');
}
.sea-slug-icon {
  background-image: url('/images/sea-slug.png');
}
.egret-icon {
  background-image: url('/images/egret.png');
}
.salamander-icon {
  background-image: url('/images/salamander.png');
}

2.10.4 @while

@while指令重复输出格式直到表达式返回结果为false。这样可以实现比@for更复杂的循环,只是会很少会用到。

$i: 6;
@while $i > 0 {
  .item-#{$i} {
    width: 2em * $i;
    $i: $i - 2;
  }
}

编译结果:

.item-6 {
  width: 12em;
}
.item-4 {
  width: 8em;
}
.item-2 {
  width: 4em;
}
less和scss的比较

less和scss的大致特性类似,只是在语法上可能写法会有所不同,下面我们就针对几个常用的属性进行对比

特性lessscss
变量@变量名$变量名
插值@{变量名}#{$变量名}
mixin直接定义 myMixin {};引用:myMixin()定义:@mixin myMixin {}; 引用:@include myMixin;
函数直接定义 myFun() {};引用:myFun()定义:@function myFun() {}; 引用:myFun();
webpack中使用css预处理器

我们在实际开发项目中用的更多的可能就是vue, react这种框架,里面集成了webpack打包,因此我们很多时候并不是独立使用命令行去编译成css文件,而且更多的使用webpack去编译,下面我们就来介绍一下如何在webpack中使用css预处理器。 webpack不能直接处理css文件,需要借助相关loader才能编译成功,同样地,webpack也不能直接处理less,scss这种css预处理文件,需要借助相关的插件进行处理。

1. webpack处理css文件

1.1 安装两个依赖:css-loader和style-loader

npm install css-loader style-loader -D

1.2 配置相关loader

在webpack的rules中添加以下代码

rules: [
  {
  test: /\.css$/,
    use: [
      'style-loader',
      'css-loader'
    ]
  }
]

1.3. 打包运行

npm run build

2. webpack处理less文件

webpack处理less文件,首先要把less文件转成css文件,因此它需要多安装一个loader.

2.1 安装四个依赖:css-loader,style-loader,sass和sass-loader

npm install css-loader style-loader less less-loader -D

2.2 配置相关loader

rules: [
  {
  test: /\.css$/,
    use: [
      'style-loader',
      'css-loader'
    ]
  },
  {
  test: /\.less$/,
    use: [
      'style-loader',
      'css-loader',
      'less-loader'
    ]
  }
]

2.3 打包运行

npm run build

3. webpack处理scss文件

webpack处理less文件,首先要把scss文件转成css文件,因此它需要多安装一个loader.

3.1 安装四个依赖:css-loader,style-loader,sass和sass-loader

npm install css-loader style-loader sass sass-loader -D

3.2 配置相关loader

rules: [
  {
  test: /\.css$/,
    use: [
      'style-loader',
      'css-loader'
    ]
  },
  {
  test: /\.s[ca]ss$/,
    use: [
      'style-loader',
      'css-loader',
      'sass-loader'
    ]
  }
]

3.3 打包运行

npm run build