这算是 element 源码学习的番外篇,由于 element 中使用了大量 sass 来写样式。而 UI 框架的核心其实就是样式。因此,抽空把 sass 学了一遍,写了些小 demo 实践,总结成此文。
简单说下 sass 如何安装和编译调试。
参照官网,须要使用 gem 来安装 sass。若是是windows用户没有 gem 须要先安装 Rubycss
$ gem install sass
若是有权限问题,须要加上 sudo
。html
$ sudo gem install sass
最后,经过查询 sass 版本号验证是否安装成功。web
$ sass -v
编译命令很简单,在项目目录下编译选中 .scss
、.sass
文件便可。shell
$ sass hello.scss hello.css
若是是学习 sass 这一个命令足矣,其余命令可参考sass 编译编程
下面我用本身对 sass 语法的理解,配合上 demo 快速过一遍 sass 基础语法。windows
二者其实都是 sass 能够识别的文件,惟一不一样点是 .sass
文件不使用大括号和分号。以下~浏览器
// .scss $default-color: #FFAACC; .selected { color: $default-color; } // .sass $default-color: #FFAACC .selected color: $default-color // .css .selected { color: #FFAACC; }
官方文档推荐使用 .scs
s 文件类型写法,避免 .sass
文件的严格格式要求报错。sass
经过 $
符号来定义 sass 变量,变量在样式内外均可定义,用于各个样式中。定义的变量不会在编译后的 CSS 文件中显示。ruby
$default-color: #FFAACC; $border-color: #AAFFCC; $default-border: 1px solid $border-color; $extra-color: #BBDD00; .selected { $scoped-width: 60px; width: $scoped-width; color: $default-color; border: $default-border; }
编译结果:框架
.selected { width: 60px; color: #FFAACC; border: 1px solid #AAFFCC; }
另外注意的一个点是在定义变量时使用的 -
和 _
的效果是同样的。即 $border-color
和 $border_color
指向的是同一个变量。
为了不一些代码的重复,引入了代码的嵌套。看一个例子:
.selected { color: #FFAA22; h1 { color: #FFDD77 } div { width: 50px; height: 20px; span { color: #012DD6; } } &:hover { color: #FAFAFA; } }
获得的结果以下:
.selected { color: #FFAA22; } .selected h1 { color: #FFDD77; } .selected div { width: 50px; height: 20px; } .selected div span { color: #012DD6; } .selected:hover { color: #FAFAFA; }
从中能够看到,嵌套能够将须要重复写选择器的过程嵌套到一个表达式中了。
从上面的例子中看到有这么一段 &:hover
而在编译结果中获得的结果是 .selected:hover
,其实 &
标识符就表明了父级选择器。就这么简单,不理解的时候把父级选择题替换 &
理解下就简单了。
sass 中的嵌套是能够多个样式同时嵌套的。 用法见demo。
.container .content { h1, h2, h3 {margin-bottom: .8em} }
编译结果
.container .content h1, .container .content h2, .container .content h3 { margin-bottom: .8em; }
关于 >
、+
和 ~
这三个选择器,是 CSS3 中就有的。在 SASS 中一样适用。
简单说下三个选择器用途(参考 CSS 选择器):
div>p
选取父元素是 <div> 元素的每一个 <p> 元素div+p
选择 <div> 元素以后紧跟的每一个 <p> 元素p~ul
选择前面有 <p> 元素的每一个 <ul> 元素。看个官网的例子:
article { ~ article { border-top: 1px dashed #ccc } > section { background: #eee } dl > { dt { color: #333 } dd { color: #555 } } nav + & { margin-top: 0 } }
动手编译出的结果以下:
article ~ article { border-top: 1px dashed #ccc; } article > section { background: #eee; } article dl > dt { color: #333; } article dl > dd { color: #555; } nav + article { margin-top: 0; }
属性嵌套说白了就是把 margin-bottom
这类有 -
符号隔开的属性拆分开来便于查看和编写。
nav { border: { style: solid; width: 1px; color: #ccc; } }
这里把 border-style
等属性进行了拆分,结果以下:
nav { border-style: solid; border-width: 1px; border-color: #ccc; }
sass 提供了 sass 文件导入功能。能够作一些基础样式的复用。用法很简单:
// var.scss $default-color: #AABBCC; .focused { color: red; margin: 5px; } // h1.scss h1 { color: #BBDDFF; margin: 10px; } // demo.scss @import "var01"; $default-color: #FFAADD !default; .selected { color: $default-color; @import "h1"; }
以上代码中将 var.scss
和 h1.scss
两个文件导入到了 demo.scss
中,最终生成结果以下:
.focused { color: red; margin: 5px; } .selected { color: #AABBCC; } .selected h1 { color: #BBDDFF; margin: 10px; }
从结果来讲说导入的几个注意点:
@import
表达式来导入,导入能够是外部导入也但是嵌套导入。上面例子中 var
是外部导入,而 h1
是嵌套导入的。$default-color: #FFAADD !default;
中的 !default
是定义变量默认值的方式,若是导入文件中有一样的值优先使用导入的值,若是导入文件中没有这个值,使用默认值。@import
与 css 中的 @import
不一样,sass 中是编译的时候就直接导入生成 css 文件了,而 css 中,只有执行到 @import
时,浏览器才会去下载 css 文件,会致使页面加载变慢。就是在 sass 是否保留注释内容的语法。保留注释的方式为:在CSS语法容许的地方,以 /*...*/
的方式写注释就能在生成的 css 文件中看到。再来看一个例子:
// 不显示 /* 显示 */ .selected { //不显示 /* 显示 */ color: #FFAADD; // 不显示 margin:/* 不显示 */ 10px; /* 显示 */ /* 显示 */border: 1px dashed /* 不显示 */ #ccc; } // 不显示 /* 显示 */
编译结果正如注释所预测的。
混合器在 element 的样式表中用的很是多,是个很强大的功能。混合器以 @mixin
来导出混合内容,使用 @include
来导入混合内容。
个人理解是:@mixin
相似定义变量同样定义个混合器(编译的时候不显示 @mixin
的内容),@include
获取混合器来替换 @include xxxx
的这行内容。
// mixin.scss @mixin rounded-corners { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; div { width: 50px; height: 20px; } } .name { span { color: #FFAADD; } } // include.scss @import "mixin"; .notice { background-color: green; border: 2px solid #00aa00; @include rounded-corners; }
这里在官方 demo 上加了点代码验证问题。获得结果以下:
.name span { color: #FFAADD; } .notice { background-color: green; border: 2px solid #00aa00; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } .notice div { width: 50px; height: 20px; }
这个demo验证了:1. @mixin
是一个相似变量的内容。在 @import
导入的内容中只显示了 .name
样式。 2. @include
会替换 @include xxx
这段代码。就算 @mixin
中有各类写法都会应用到 @include
中,如嵌套 CSS。
混合器能够接收 @include
表达式传递的参数。并且,参数能够设置默认值。
// mixin.scss @mixin link-colors($normal: white, $hover: white, $visited: white) { color: $normal; &:hover { color: $hover; } &:visited { color: $visited; } } // include.scss @import "mixin"; // 写法一,按照默认顺序传递参数 a { @include link-colors(blue, red, green); } // 写法二,按照参数名传递参数 b { @include link-colors( $normal: blue, $visited: green, $hover: red ); }
编译结果为:
a { color: blue; } a:hover { color: red; } a:visited { color: green; } b { color: blue; } b:hover { color: red; } b:visited { color: green; }
若是说 @include
中不传递参数 @include link-colors();
,那么生成结果的 color 都为默认值 white。
在 element 源码中用了很多混合,有一种写法 sass 的快速入门中没有提到。就找一个简单的 el-card 样式来学习下来:
@import "mixins/mixins"; @import "common/var"; @include b(card) { border-radius: $--card-border-radius; border: 1px solid $--card-border-color; background-color: $--color-white; overflow: hidden; box-shadow: $--box-shadow-light; color: $--color-text-primary; @include e(header) { padding: #{$--card-padding - 2 $--card-padding}; border-bottom: 1px solid $--card-border-color; box-sizing: border-box; } @include e(body) { padding: $--card-padding; } }
从中能够看到全部的属性都是使用了 @include
方式进行混合的。最终生成的 CSS 文件以下:
.el-card { border-radius: 4px; border: 1px solid #ebeef5; background-color: #fff; overflow: hidden; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); color: #303133; } .el-card__header { padding: 18px 20px; border-bottom: 1px solid #ebeef5; box-sizing: border-box; } .el-card__body { padding: 20px; }
先看下导入,其中 var
文件是项目样式变量统一保存的地方;mixin
文件用于混合;再加上几个 @include
表达式,答案必定是在 mixin
中的。咱们就直接找到 @mixin b
和 @mixin e
两个混合项。
@mixin b($block) { $B: $namespace+'-'+$block !global; // 定义 B 变量:变量名 el-card .#{$B} { @content; } } @mixin e($element) { $E: $element !global; $selector: &; $currentSelector: ""; @each $unit in $element { $currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","}; } @if hitAllSpecialNestRule($selector) { @at-root { #{$selector} { #{$currentSelector} { @content; } } } } @else { @at-root { #{$currentSelector} { @content; } } } }
发现有许多 sass 快速入门中没有提到过的语法: @if
,@else
等等,这里查阅具体文档列出其功能:
#{...}
是插值语法,用于在选择器和属性名中使用 SassScript 变量,因此 .#{$B}
表达式,若是 $B
的值为 hello-world,那么表达式结果等于 .hello-world
其实看完这些用法,上面的代码就很好理解了。具体关于 element 样式学习的细节将在下篇博客中详细学习。
我的感受继承就是几个样式类写在一块儿。并且,继承是能够嵌套的。
.error { border: 1px red; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; } .error02 { @extend .seriousError; margin: 5px; }
编译结果为:
.error, .seriousError, .error02 { border: 1px red; background-color: #fdd; } .seriousError, .error02 { border-width: 3px; } .error02 { margin: 5px; }
下面引用下继承的注意事项:
- 跟混合器相比,继承生成的 css 代码相对更少。由于继承仅仅是重复选择器,而不会重复属性,因此使用继承每每比混合器生成的 css 体积更小。若是你很是关心你站点的速度,请牢记这一点。
- 继承听从 css 层叠的规则。当两个不一样的 css 规则应用到同一个 html 元素上时,而且这两个不一样的 css 规则对同一属性的修饰存在不一样的值,css 层叠规则会决定应用哪一个样式。至关直观:一般权重更高的选择器胜出,若是权重相同,定义在后边的规则胜出。
因此,其实继承相比混合更简单。继承只是选择器的重复,而混合是用一段代码替换标签 @include
标签。
因为 element 项目中使用了大量的 sass 样式,因此想了解 element 必须对 sass 有必定了解。本文简单解决了 sass 是什么?基础用法怎么用?两个问题。更加深刻的 sass 语法涉及的很少,算是快速入门博客啦。在了解了 sass,可以看懂 element 中的样式表后,就能够愉快的去学习 element 源码啦~