一、Sass和SCSS
当我们说起 Sass ,我们经常指的是两种事物:一种 css 预处理器和一种语言,Sass (预处理器)有两种不同的语法:
- Sass,一种缩进语法
- SCSS,一种 CSS-like 语法
注意SCSS是Sass处理器的一种语法
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。
二、sass的变量
1. sass使用$符号来标识变量(老版本的sass使用!来标识变量。),比如$highlight-color和$sidebar-width。
2. sass变量的声明和css属性的声明很像:
$highlight-color: #F90;
3. 任何可以用作css属性值的赋值都 可以用作sass的变量值,甚至是以空格分割的多个属性值,如$basic-border: 1px solid black;
4. 变量可以在css规则块定义之外存在。当变量定义在css规则块内,那么该变量只能在此规则块内使用。
5. 通常我们在vue中的assets目录下面单独创建一个放scss变量名的文件,引入到App.vue
<style lang="scss">
@import "src/assets/style/reset.scss";
@import "src/assets/style/helper.scss";
#app {
line-height: 1.5;
font-family: $font-hei;
color: #333333;
font-size: 16px;
}
</style>三、嵌套规则
#content {
article {
h1 { color: #333 }
p { margin-bottom: 1.4em }
}
aside { background-color: #EEE }
}
/* 编译后 */
#content article h1 { color: #333 }
#content article p { margin-bottom: 1.4em }
#content aside { background-color: #EEE }大多数情况下这种简单的嵌套都没问题,但是有些场景下不行,比如你想要在嵌套的选择器 里边立刻应用一个类似于:hover的伪类。为了解决这种以及其他情况,sass提供了一个特殊结 构&。一个简单的&符号,且可以放在任何一个选择器可出现的地方,比如h1放在哪,它就可以放在哪。
article a {
color: blue;
&:hover { color: red }
}当包含父选择器标识符的嵌套规则被打开时,它不会像后代选择器那样进行拼接,而是&被父选择器直接替换:
article a { color: blue }
article a:hover { color: red }同时父选择器标识符还有另外一种用法,你可以在父选择器之前添加选择器。举例来说,当用户在使用IE浏览器时,你会通过JavaScript在<body>标签上添加一个ie的类名,为这种情况编写特殊的样式如下:(可以加active类)
#content aside {
color: red;
body.ie & { color: green }
}
/*编译后*/
#content aside {color: red};
body.ie #content aside { color: green }article > section { border: 1px solid #ccc }你可以用子组合选择器>选择一个元素的直接子元素。
你可以用同层相邻组合选择器+选择header元素后紧跟的p元素:
header + p { font-size: 1.1em }你也可以用同层全体组合选择器~,选择所有跟在article后的同层article元素,不管它们之间隔了多少其他元素:
article ~ article { border-top: 1px dashed #ccc }四、导入SASS文件
css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件。然而,后果是只有执行到@import时,浏览器才会去下载其他css文件,这导致页面加载起来特别慢。
sass也有一个@import规则,但不同的是,sass的@import规则在生成css文件时就把相关文件导入进来。这意味着所有相关的样式被归纳到了同一个css文件中,而无需发起额外的下载请求。
当通过@import把sass样式分散到多个文件时,你通常只想生成少数几个css文件。那些专门为@import命令而编写的sass文件,并不需要生成对应的独立css文件,这样的sass文件称为局部文件。对此,sass有一个特殊的约定来命名这些文件。
此约定即,sass局部文件的文件名以下划线开头。这样,sass就不会在编译时单独编译这个文件输出css,而只把这个文件用作导入。当你@import一个局部文件时,还可以不写文件的全名,即省略文件名开头的下划线。举例来说,你想导入themes/_night-sky.scss这个局部文件里的变量,你只需在样式表中写@import "themes/night-sky";。
五、原生的CSS导入
由于sass兼容原生的css,所以它也支持原生的CSS@import。尽管通常在sass中使用@import时,sass会尝试找到对应的sass文件并导入进来,但在下列三种情况下会生成原生的CSS@import,尽管这会造成浏览器解析css时的额外下载:
- 被导入文件的名字以
.css结尾; - 被导入文件的名字是一个URL地址(比如http://www.sass.hk/css/css.css),由此可用谷歌字体API提供的相应服务;
- 被导入文件的名字是
CSS的url()值。
这就是说,你不能用sass的@import直接导入一个原始的css文件,因为sass会认为你想用css原生的@import。但是,因为sass的语法完全兼容css,所以你可以把原始的css文件改名为.scss后缀,即可直接导入了。
六、混合器
@mixin link-colors($normal, $hover, $visited) {
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}当混合器被@include时,你可以把它当作一个css函数来传参。如果你像下边这样写:
a {
@include link-colors(blue, red, green);
}
//Sass最终生成的是:
a { color: blue; }
a:hover { color: red; }
a:visited { color: green; }七、继承
混合器主要用于展示性样式的重用,而类名用于语义化样式的重用。
.error {
border: 1px solid red;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}在上边的代码中,.seriousError将会继承样式表中任何位置处为.error定义的所有样式。
继承应该是建立在语义化的关系上。当一个元素拥有的类(比如说.seriousError)表明它属于另一个类(比如说.error),这时使用继承再合适不过了。想象一下你正在编写一个页面,给html元素添加类名,你发现你的某个类(比如说.seriousError)另一个类(比如说.error)的细化。你会怎么做?
@extend背后最基本的想法是,如果.seriousError @extend .error, 那么样式表中的任何一处.error都用.error.seriousError这一选择器组进行替换。
八、占位符选择器 %foo
必须通过 @extend 指令调用
时,需要定义一套样式并不是给某个元素用,而是只通过 @extend 指令使用,尤其是在制作 Sass 样式库的时候,希望 Sass 能够忽略用不到的样式。
#context a%extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
占位符选择器需要通过延伸指令使用,用法与 class 或者 id 选择器一样,被延伸后,占位符选择器本身不会被编译。
.notice {
@extend %extreme;
}编译为
#context a.notice {
color: blue;
font-weight: bold;
font-size: 2em; }九、总结-混合器用于减少样式重复,继承用于减少类重复
- 跟混合器相比,继承生成的
css代码相对更少。因为继承仅仅是重复选择器,而不会重复属性,所以使用继承往往比混合器生成的css体积更小。如果你非常关心你站点的速度,请牢记这一点。 - 继承遵从
css层叠的规则。当两个不同的css规则应用到同一个html元素上时,并且这两个不同的css规则对同一属性的修饰存在不同的值,css层叠规则会决定应用哪个样式。相当直观:通常权重更高的选择器胜出,如果权重相同,定义在后边的规则胜出。
十、实战
我们写css时,讲究一个思路
1. reset
2. 全局(全局背景,字体等等)
全局的样式有两种选择,写在#app上或者写在body上,区别在于你负责所有页面,还是你只负责一个页面,你写在你的挂靠点上即可
#app {
line-height: 1.5;
font-family: $font-hei;
color: #333333;
font-size: 16px;
}3. 变量
4. 局部
十一、循环和插值
通过 #{} 插值语句可以在选择器或属性名中使用变量:
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
}
编译为
p.foo {
border-color: blue; }@for 指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包含两种格式:@for $var from <start> through <end>,或者 @for $var from <start> to <end>,区别在于 through 与 to 的含义:
through 时,条件范围包含 <start> 与 <end> 的值,而使用 to 时条件范围只包含 <start> 的值不包含 <end> 的值。另外,$var 可以是任何变量,比如 $i;<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; }$class-prefix: col-;
@for $n from 1 through 24 {
&.#{$class-prefix}#{$n}{
width: ($n/24)*100%;
}