《Sass与Compass实战》读书笔记

虽然最初使用Less写了两个项目,后来又转为Scss开发,经过短暂的语法学习就直接在生产环境中使用(没有人管...)。不过使用的只是诸如变量,嵌套这一些比较基础的语法,时间久了就有一种"暴殄天物"的感觉,所幸有网友推荐了这本《Sass与Compass实战》,带着“真正学会Scss,提高工作效率”的目的,以及那个困扰我许久许久的“选择器命名”问题,开始学习本书。PS:书很薄,二百来页。

<!--more-->

1. Sass基础语法

写Sass和读Sass和读写CSS十分相似,Scss是Sass的一个超集。我们关注的焦点应当放在如何使用Sass特性来优化书写CSS的过程。Sass的主要特性有:

  • 变量——最简单、最基本的重用形式;
  • 选择器嵌套——保持样式表的简洁和易读性;
  • 引入样式——将大片的样式拆分到不同文件,通过组织文件保持可维护性;
  • 混合器和继承——重用大段样式。

由于在初识SCSS这篇博中已经简单了解了Scss的基础语法,这里只是简单记录一下,作为复习。

1.1. 变量

使用 $ 符号来标识一个变量,因为$符号在CSS中没有任何用途,不会导致与现存或未来的CSS语法冲突。 任何作为CSS属性值的赋值都可以作为Sass的变量值,甚至是以空格分割的多个属性值。 变量可以定义在CSS规则块之外;当变量定义在CSS规则块之内的时候,该变量具有块级作用域,即其值只能在该规则块及其子规则块下使用。 此外变量名不区分下划线和中横线,也就是说$test-color和$test_color指向同一个变量,然而,统一使用同一种风格是很有必要的。

1.2. 嵌套规则

选择器嵌套使用的十分频繁,需要注意的就是父选择器的标识符 &,可以用来处理伪类选择器 ;此外关于子组合选择器>和同层组合选择器+,~等,都能被Scss正确解释。 此外还有属性值嵌套,由于CSS原生语法就支持部分组合属性,因此属性值嵌套用的并不是很多,主要用来解决border-right,border-left等这样的属性。 关于选择器嵌套需要明白,嵌套只是让样式表看起来很小,实际上生成的CSS文件可能很大(浏览器只认CSS文件),在群组选择器中这种情形发生的可能性更大,因此,使用嵌套要慎重,不要使用毫无意义的多重嵌套。

1.3. 引入样式

在Scss中,可以将样式分散到多个文件,这样整个项目可具备非常良好的维护性,且独立的样式甚至可以在其他项目中重用。 不同于原生的CSS@import,Scss会将多个文件下的代码编译成一个文件,这样完全不用担心造成多次服务器请求的问题。 为了避免在每个Scss文件都被编译成css文件,可以在这些局部文件(即只为了@import命令而书写的文件)名字前加上下划线_,这样就可以将多个Scss样式组件编译成一个css文件。 前面提到了变量的块级作用域:

  • 在多个引入的Scss文件之间,前面文件中的全局变量可以在后面文件中使用(当然反过来就会报错:未定义的变量);
  • 而后定义的变量会覆盖前面文件中的同名变量(注意短横线和下划线表示相同的变量)。

然而在某些时候,我们可能担心自定定义的变量会与前面文件中的变量发生冲突而无法使用前面的变量(比如在使用第三方样式库的时候,我们更希望优先使用样式库中的变量值),这种情况下可以使用默认变量,即在定义变量值之后加上default即可,这样,只有当前面的文件没有定义该变量时才会使用我们自定义的变量值。

$basecolor : #ff00cc !default;

1.4. 混合器

混合器类似于函数,可以用来定义将会重用的大段样式:

  • 使用@mixin来定义混合器
  • 使用@include来调用混合器 可以向混合器传递参数来修改最终的样式数值,甚至可以为混合器的参数设置默认值。
    /*border-radius*/
    @mixin bd-r($size:5px){
      -webkit-border-radius: $size;
      -moz-border-radius: $size;
      border-radius: $size;
    }
    .test {
      @include bd-r(10px);
    }
    利用混合器可以尽可能的重用样式(当然这只是减少在书写CSS代码时的复制粘贴,实际生成的CSS文件可能非常大)。 重新翻阅到混合器这里,突然想到之前的“面向属性的CSS选择器命名”,当时由于考虑到由于“不要对任何任何网站通用的样式进行分离”,那么,将基本的样式定义成混合器怎么样呢?这样,如果有需要修改的地方,只需修改对应的参数或者是移除对应的混合器即可。将混合器当作是css的属性缩写,这样可以极大的减轻代码量。为了避免编译的CSS样式表过大,需要注意使用混合器的场合:即反复重用的视觉样式。记得有位前辈说,现在在压缩的情况下,CSS文件大小根本不是影响页面加载速度的因素,如何增加工作效率,身心愉悦的工作才是最应当考虑的问题...汗。 书中关于正确使用混合器的建议是:如果能为混合器找到一个恰当的语义化名字(即对应的视觉样式描述),那么这段样式就可以使一个优秀的混合器;反之,可能就不那么合适了。 另外,混合器可以包含CSS规则,包含选择器和选择器中的属性————因为,混合器本质上就是一段复用的CSS代码而已。 最后,需要注意的是,尽管混合器跟函数相似,但是只能在CSS规则调用前面定义的混合器,而函数而可以出现在同级作用域之间的任何位置。

1.5. 选择器继承

选择器继承是“面向对象的CSS”里面的概念,在Scss中主要通过@extend来实现选择器继承。当时在sass中国的网站上学习Scss的时候,关于选择器继承一直没有弄明白,经过本书的讲解,豁然开朗。 选择器继承,实际上是通过分组选择器来实现的,比如一个.seriousError的类,想让他继承.error类的全部样式,就需要使用@extend(注意是全部样式,而不是部分样式,如果想要继承部分样式,应当将公用样式拆分成单独的类然后再继承,或者使用混合器)。

.error {
    color: red;
    font-weight: bold;
}
.seriousError {
    @extend .error;
    border: 1px solid #000;
}

编译生成的CSS文件:

.error, .seriousError {
  color: red;
  font-weight: bold; }

.seriousError {
  border: 1px solid #000; }

实际上,选择器继承的原理,是将样式表中父类出现的任何地方(包括出现在子类后面的位置)都转变成(父类,子类)形式的分组选择器,这样,子类就拥有了父类的全部样式,然后独自拥有自定义的样式。 与混合器相比,使用继承会生成更少的样式代码(因为混合器会完全复制重用的代码,而选择器继承是通过分组选择器实现的) 关于继承,有几个需要理清的地方:

  • 只有全部命中子类选择器的元素才会继承父类的样式,即#main .seriousError @extend .error 中,只有#main下的.seriousError选择器对应的元素才有.error的全部样式,因为出现在分组选择器的是#main .seriousError而不是单独的.seriousError
  • 选择器继承也遵从CSS层叠的规则,即浏览器最后采用的是样式权重值更高的样式,虽然分组选择器并不会增加或者减少选择器的权重值,但是“知道这点总没有什么坏处”——书本原话。
  • 最后也是最最重要的一点,不要滥用选择器继承。如果父类是一个后代选择器,为了使子类完全继承父类的全部样式,Scss必须考虑全部情况:比如
.wrap .box {
    @extends .father
}
.foo .father {
    color: red;
}

在这种情况下,为了使.wrap下的.box选择器对应的元素继承.foo下.father元素的样式:红色字体,必须限制.box选择器为.foo选择器的后代选择器,因此Scss生成的CSS样式必须考虑下面三种情形:

// 情形1
<div class="wrap">
    <div class="foo">
        <div class="box"></div>
    </div>
</div>

// 情形2
<div class="foo">
    <div class="wrap">
        <div class="box"></div>
    </div>
</div>

// 情形3
<div class="wrap foo">
    <div class="box"></div>
</div>

因此生成的CSS代码为

.foo .father, .foo .wrap .box, .wrap .foo .box {
  color: red; }

我使用的是Koala编译,可以看到结果中并没有出现.wrap.foo .box的情形(实际上Scss并不总是生成所有的选择器组合)。因此,得到的结论便是: 不要让子类继承作为后代选择器的父类样式。(我们可以放心地继承包含后代选择器的选择器)

2. 高性能样式表

书中关于样式表的性能有如下建议:

  • 减少传输时间
    • 开启服务器的gzip压缩可以极大的降低样式表的大小(甚至可以压缩到原来的10%~15%,有这么夸张?)
    • 压缩图片(这里的图片指的是样式表中所使用的背景图片,并尽可能使用精灵图片来减少服务器的请求次数);
  • 利用资源托管来提高页面加载速度
  • 选择器性能,一直以来对于选择器性能耿耿于怀,书中的一句话让我走出了死胡同,“选择器的结构和数量会对页面产生微小却可以度量的影响,然而根据20-80的理论,首先应当考虑页面的载入次序,服务器响应时间,以及网络传输消耗,之后才应当考虑选择器方面的优化”!!!

3. 总结

仔细看完了Scss部分的介绍,关于Compass只是随手翻过,关于网格系统,精灵图等也大致了解过一点,这本书更主要的部分放在了Compass这个框架,而关于框架的掌握,更明智的选择应当是练习而不是看书,因此草草结束了这篇笔记。关于编写高效的CSS代码,还有很长的路要走。

2018年五月面试发现的一些问题 BFC及其应用