Scss 初识 @extend 与 @mixin

前言

前面我们已经学习了 Scss 的基础。其实,能够运用之前的技巧已经足够了,在日常开发中,对 CSS 的熟练使用比对 Scss 的熟练使用更重要。但本文集既然是讲学习 Scss,自然是希望能够对 Scss 有更深的研究。当然,不实用、复杂且不易懂的内容是被剔除的,毕竟学习工具的首要目的还是实用。

@extend实现样式复用

想必大家在日常的开发中常常为这种情况苦恼:例如我在写一个页面,页面里好几个地方是相同的样式,又或者这个地方的样式有一部分与另一个地方的样式完全重合,这里只是有一点不同而已,但是使用 CSS 并不能实现代码的复用,只能用 CV 大法搬运代码。为了解决这样的需求和场景,Scss 便实现了该功能,使用@extend便可以实现对重复代码的复用。

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

这里将.error的样式在seriousError里进行复用,代码看起来简洁美观。当然,@extend不仅仅支持类选择器,也支持伪类选择器。

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

上一篇文章我们提到,Scss 无论再怎么书写,最终都会被编译为 CSS。@extend方法的本质其实就是将.hoverlink添加到a:hover中。不是代码中表现的那样,将其他类名下的样式“拷贝”到当前类名下面,而是将当前类名添加到其他被 extend 的类名里,成为“组选择器”。上述代码编译为:

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

但不论如何,这样的书写让动辄几百、几千行的 CSS 代码清晰了很多。既然是写得更少,@extend自然是不止使用一次,在一个样式里,可以@extend多个其他类名下的样式。

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

仅仅如此吗?如果只是如此,那@extend的能力依然不算强大。既然是复用,那就贯彻到底。我们可以在一个类名下@extend另一个类名的样式,那这个类名可以在其他类名下被@extend吗?答案是肯定的:

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}
.criticalError {
  @extend .seriousError;
  position: fixed;
  top: 10%;
  bottom: 10%;
  left: 10%;
  right: 10%;
}

怎么样?是不是非常强大?这可以让平时反复出现的样式代码变得简洁多了。但代码量大的情况下依然是需要写注释的,类名庞杂的时候,需要注释@extend的样式在第几行,这对于你返回修改样式时非常有用。

@mixin实现更强大的复用

@mixin其实可以理解为函数(Scss有函数,但本文集不打算涉及,且Scss的函数并没有多易用)。@mixin可以理解为声明语句,例如,声明一个混入:

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

large-text 并不是一个类名,仅仅是一个“混入”名而已,也可以说是“代码块变量”。让我们回顾下前面讲到的知识,是时候串联起来了。& 符在@mixin里也是可用的:

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

“变量”声明了,哪里使用呢?如何使用呢?其实,在标题里我们就说了,@mixin只是更强大的复用而已,后面我们会讲到其与@extend的区别。前面讲到,@mixin可以理解为函数,函数声明了,是不是需要调用呢?要想使用@mixin,可以在需要复用样式的类名下使用@include进行引用。不在一个选择器下使用这些样式,光使用@include是会无效的!

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

@extend一样,@mixin内部也可以@include其他@mixin的样式:

@mixin compound {
  @include highlighted-background;
  @include header-text;
}

讲到这里,@mixin依然与@extend一样,并没有突显什么强大的功能。仅仅是样式的复用而已,而且比@extend还麻烦。接下来,来看看@mixin与众不同的地方:参数。

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

如同函数一样,@mixin可以携带参数,在@include使用时动态传入,依据不同的需求做出不同的选择。因为是参数,其实就是变量,所以必须使用$开头。与 ES6 中的函数一样,@mixin的参数也支持默认值:

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

不仅如此,@mixin还支持类似于 Vue 插槽一般的功能:

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

上述代码中,@content起到一个占位符的作用,与 Vue 中 slot 作为预留空间的作用一样,在@include时可以添加各种样式,这些样式会被添加到@content的位置,最终编译为 CSS 时会被统一编译到一起。但这里最重要的在于,替换@content的代码的作用域在原来的位置,@content相当于一个指向该位置的指针而已。也就是说,被传进去代替@content的代码片段不能使用在@mixin里定义的变量!

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

为了使@mixin@include更加方便,Scss 增加了这两者的语法糖,@mixin可以简写为 =@include可以简写为+,并且{}可以省略:

=apply-to-ie6-only
  * html
    @content

+apply-to-ie6-only
  #logo
    background-image: url(/logo.gif)

@mixin 与 @extend 的区别与选择

之前我们讲过,@extend的本质其实是将一个样式的类名组合在一起形成组选择器,共用一段样式代码,而@mixin则恰恰相反。

@extend

.button {  
    background: green;  
}
.button-1 {  
    @extend .button;  
}
.button-2 {  
    @extend .button;  
}

// 编译后
.button, 
.button-1, 
.button-2 {  
    background: green;  
}

@mixin

@mixin button {  
    background-color: green;  
}
.button-1 {  
    @include button;  
} 
.button-2 {  
    @include button;  
}

// 编译后
.button {  
    background-color: green;  
}
.button-1 {  
    background-color: green;  
}
.button-2 {  
    background-color: green;  
}

所以,二者的区别显而易见,使用@extend可以减少编译后代码量,不过这不重要,编译后的 CSS 谁会在乎呢?在一些静态的复用上,@extend更加简单方便,但@mixin的优势在于可以传参,使用上更加灵活。

但从实际来看,@extend更适合局部的复用,在复用父级样式或者兄弟样式时很有用,方便易得。使用@mixin可以像 JS 模块化一样在代码头部就初始化一些样式“混入”,在样式书写过程中如果遇到可以复用的样式(特别是需要灵活传参的样式),便可以在样式表头部声明,在任意位置复用。

你可能感兴趣的:(Scss 初识 @extend 与 @mixin)