Sass 快速入门 | SASS 中文网

文档链接:https://www.sasscss.com/getting-started/

前言

之前整理了一篇关于Less的,现在就来整理一下关于Sass的。

因为这两种都是CSS的主流预处理器,当然还有Stylus。

要解释一下什么是Sass吗?

Sass和Less一样都是CSS预处理器。

CSS预处理器通俗来讲就是用它们专有的语法来写CSS,然后再通过编译工具编译成.css文件。

想象一下,当CSS有了变量之后该会是多么神奇的一件事情。

Sass的特色是:

完全兼容CSS3;

在CSS语言的基础上增加变量、嵌套、混合等功能;

通过函数进行运算;

提供控制指令等功能;

自定义输出格式;

Sass和Less有什么区别?

Sass和Less在语法上没什么太大的区别。

就个人体验来说,Sass比Less略强大、Less比Sass略简单。

当然了,网上的网友们也总结了几点:

1.Sass比Less更成熟,有强大的团队在维护;

2.Sass的教程会比Less的丰富;

3.Sass有成熟的框架;

4.国内外的讨论也是Sass比Less好。

不过,选择Sass还是Less还是要基于你所在的团队。

两者其实都是不错的选择。

知识链

0 Sass文件后缀名

1 变量

1.1 变量声明

1.2 变量引用

1.3 变量名用中划线还是下划线分隔

2 嵌套CSS规则

2.1 父选择器的标识符&

2.2 群组选择器的嵌套

2.3 子组合选择器和同层组合选择器:>、+和~

2.4 嵌套属性

3 导入SASS文件

3.1 使用SASS部分文件

3.2 默认变量值

3.3 嵌套导入

3.4 原生的CSS导入

4 静默注释

5 混合器

5.1 何时使用混合器

5.2 混合器中的CSS规则

5.3 给混合器传参

5.4 默认参数值

6 使用选择器继承来精简CSS

6.1 何时使用继承

6.2 继承的高级用法

6.3 继承的工作细节

6.4 使用继承的最佳实践

0 Sass文件后缀名

sass 有两种后缀名文件:

一种后缀名为sass,不使用大括号和分号;

另一种就是我们这里使用的scss文件,这种和我们平时写的css文件格式差不多,使用大括号和分号。

本教程中所说的所有sass文件都指后缀名为scss的文件。

在此也建议使用后缀名为scss的文件,以避免sass后缀名的严格格式要求报错。

区别就是这样子:

 

1 变量

你可以把反复使用的css属性值 定义成变量,然后通过变量名来引用它们,而无需重复书写这一属性值。

或者,对于仅使用过一 次的属性值,你可以赋予其一个易懂的变量名,让人一眼就知道这个属性值的用途。

sass使用$符号来标识变量(老版本的sass使用!来标识变量)。

1.1 变量声明

  1. $highlight-color: #F90;

任何可以用作css属性值的赋值都 可以用作sass的变量值,

甚至是以空格分割的多个属性值,如$basic-border: 1px solid black;,

或以逗号分割的多个属性值,如$plain-font: "Myriad Pro"、Myriad、"Helvetica Neue"、Helvetica、"Liberation Sans"、Arial和sans-serif; sans-serif;。

这时变 量还没有生效,除非你引用这个变量。

与CSS属性不同,变量可以在css规则块定义之外存在。

当变量定义在css规则块内,那么该变量只能在此规则块内使用。

  1. $nav-color: #F90;
  2. nav {
  3. $width: 100px;
  4. width: $width;
  5. color: $nav-color;
  6. }
  7. //编译后
  8. nav {
  9. width: 100px;
  10. color: #F90;
  11. }

在这段代码中,

$nav-color这个变量定义在了规则块外边,所以在这个样式表中都可以像nav规则块那样引用它。

$width这个变量定义在了nav的{ }规则块内,所以它只能在nav规则块内使用。

这意味着是你可以在样式表的其他地方定义和使用$width变量,不会对这里造成影响。

1.2 变量引用

凡是css属性的标准值(比如说1px或者bold)可存在的地方,变量就可以使用。

css生成时,变量会被它们的值所替代。

之后,如果你需要一个不同的值,只需要改变这个变量的值,则所有引用此变量的地方生成的值都会随之改变。

  1. $highlight-color: #F90;
  2. .selected {
  3. border: 1px solid $highlight-color;
  4. }
  5. //编译后
  6. .selected {
  7. border: 1px solid #F90;
  8. }

在声明变量时,变量值也可以引用其他变量。

当你通过粒度区分,为不同的值取不同名字时,这相当有用。

下例在独立的颜色值粒度上定义了一个变量,且在另一个更复杂的边框值粒度上也定义了一个变量:

  1. $highlight-color: #F90;
  2. $highlight-border: 1px solid $highlight-color;
  3. .selected {
  4. border: $highlight-border;
  5. }
  6. //编译后
  7. .selected {
  8. border: 1px solid #F90;
  9. }

1.3 变量名用中划线还是下划线分隔

sass的变量名可以与css中的属性名和选择器名称相同,包括中划线和下划线。

这完全取决于个人的喜好,有些人喜欢使用中划线来分隔变量中的多个词。

使用中划线的方式更为普遍,这也是compass和本文都用的方式。

不过,sass并不想强迫任何人一定使用中划线或下划线,所以这两种用法相互兼容。

用中划线声明的变量可以使用下划线的方式引用,反之亦然。

这意味着即使compass选择用中划线的命名方式,这并不影响你在使用compass的样式中用下划线的命名方式进行引用:

  1. $link-color: blue;
  2. a {
  3. color: $link_color;
  4. }
  5. // 编译后
  6. a {
  7. color: blue;
  8. }

在上例中,$link-color和$link_color其实指向的是同一个变量。

实际上,在sass的大 多数地方,中划线命名的内容和下划线命名的内容是互通的,除了变量,也包括对混合器和Sass函数的命名。

但是在sass中纯css部分不互通,比如类名、ID或属性名。

2 嵌套CSS规则

css中重复写选择器是非常恼人的。

如果要写一大串指向页面中同一块的样式时,往往需要 一遍又一遍地写同一个ID:

  1. #content article h1 { color: #333 }
  2. #content article p { margin-bottom: 1.4em }
  3. #content aside { background-color: #EEE }

像这种情况,sass可以让你只写一遍,且使样式可读性更高。

在Sass中,你可以像俄罗斯套娃那样在规则块中嵌套规则块。

sass在输出css时会帮你把这些嵌套规则处理好,避免你的重复书写。

  1. #content {
  2. article {
  3. h1 { color: #333 }
  4. p { margin-bottom: 1.4em }
  5. }
  6. aside { background-color: #EEE }
  7. }
  8. // 编译后
  9. #content article h1 { color: #333 }
  10. #content article p { margin-bottom: 1.4em }
  11. #content aside { background-color: #EEE }

一个给定的规则块,既可以像普通的CSS那样包含属性,又可以嵌套其他规则块。

当你同时要为一个容器元素及其子元素编写特定样式时,这种能力就非常有用了。

  1. #content {
  2. background-color: #f5f5f5;
  3. aside { background-color: #eee }
  4. }

大多数情况下这种简单的嵌套都没问题,但是有些场景下不行,比如你想要在嵌套的选择器里边立刻应用一个类似于:hover的伪类。

为了解决这种以及其他情况,sass提供了一个特殊结构&。

2.1 父选择器的标识符&

一般情况下,sass在解开一个嵌套规则时就会把父选择器(#content)通过一个空格连接到子选择器的前边(article和aside)形成(#content article和#content aside)。

这种在CSS里边被称为后代选择器,因为它选择ID为content的元素内所有命中选择器article和aside的元素。

但在有些情况下你却不会希望sass使用这种后代选择器的方式生成这种连接。

最常见的一种情况是当你为链接之类的元素写:hover这种伪类时,你并不希望以后代选择器的方式连接。

比如说,下面这种情况sass就无法正常工作:

  1. article a {
  2. color: blue;
  3. :hover { color: red }
  4. }

解决之道为使用一个特殊的sass选择器,即父选择器。

在使用嵌套规则时,父选择器能对于嵌套规则如何解开提供更好的控制。

它就是一个简单的&符号,且可以放在任何一个选择器可出现的地方,比如h1放在哪,它就可以放在哪。

  1. article a {
  2. color: blue;
  3. &:hover { color: red }
  4. }

当包含父选择器标识符的嵌套规则被打开时,它不会像后代选择器那样进行拼接,而是&被父选择器直接替换:

  1. article a { color: blue }
  2. article a:hover { color: red }

在为父级选择器添加:hover等伪类时,这种方式非常有用。

同时父选择器标识符还有另外一种用法,你可以在父选择器之前添加选择器。

举例来说,当用户在使用IE浏览器时,你会通过JavaScript在<body>标签上添加一个ie的类名,为这种情况编写特殊的样式如下:

  1. #content aside {
  2. color: red;
  3. body.ie & { color: green }
  4. }
  5. // 编译后
  6. #content aside {color: red};
  7. body.ie #content aside { color: green }

2.2 群组选择器的嵌套

  1. nav, aside {
  2. a {color: blue}
  3. }
  4. // 编译后
  5. nav a, aside a {color: blue}

2.3 子组合选择器和同层组合选择器:>、+和~

  1. article section { margin: 5px }
  2. article > section { border: 1px solid #ccc }

第一个选择器会选择article下的所有命中section选择器的元素。

第二个选择器只会选择article下紧跟着的子元素中命中section选择器的元素。

选择header元素后紧跟的p元素:

  1. header + p { font-size: 1.1em }

选择所有跟在article后的同层article元素,不管它们之间隔了多少其他元素:

  1. article ~ article { border-top: 1px dashed #ccc }
  1. article {
  2. ~ article { border-top: 1px dashed #ccc }
  3. > section { background: #eee }
  4. dl > {
  5. dt { color: #333 }
  6. dd { color: #555 }
  7. }
  8. nav + & { margin-top: 0 }
  9. }
  10. // 编译后
  11. article ~ article { border-top: 1px dashed #ccc }
  12. article > footer { background: #eee }
  13. article dl > dt { color: #333 }
  14. article dl > dd { color: #555 }
  15. nav + article { margin-top: 0 }

2.4 嵌套属性

在sass中,除了CSS选择器,属性也可以进行嵌套。

尽管编写属性涉及的重复不像编写选择器那么糟糕,但是要反复写border-style、border-width、border-color以及border-*等也是非常烦人的。

在sass中,你只需敲写一遍border:

  1. nav {
  2. border: {
  3. style: solid;
  4. width: 1px;
  5. color: #ccc;
  6. }
  7. }
  8. // 编译后
  9. nav {
  10. border-style: solid;
  11. border-width: 1px;
  12. border-color: #ccc;
  13. }
  1. nav {
  2. border: 1px solid #ccc {
  3.   left: 0px;
  4.   right: 0px;
  5. }
  6. }
  7. // 编译后
  8. nav {
  9. border: 1px solid #ccc;
  10. border-left: 0px;
  11. border-right: 0px;
  12. }

3 导入SASS文件

css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件。

然而,后果是只有执行到@import时,浏览器才会去下载其他css文件,这导致页面加载起来特别慢。

sass也有一个@import规则,但不同的是,sass的@import规则在生成css文件时就把相关文件导入进来。

这意味着所有相关的样式被归纳到了同一个css文件中,而无需发起额外的下载请求。

另外,所有在被导入文件中定义的变量和混合器均可在导入文件中使用。

使用sass的@import规则并不需要指明被导入文件的全名。

你可以省略.sass或.scss文件后缀。

这样,在不修改样式表的前提下,你完全可以随意修改你或别人写的被导入的sass样式文件语法,在sass和scss语法之间随意切换。

举例来说,@import"sidebar";这条命令将把sidebar.scss文件中所有样式添加到当前样式表中。

3.1 使用SASS部分文件

当通过@import把sass样式分散到多个文件时,你通常只想生成少数几个css文件。

那些专门为@import命令而编写的sass文件,并不需要生成对应的独立css文件,这样的sass文件称为局部文件。

对此,sass有一个特殊的约定来命名这些文件。

此约定即,sass局部文件的文件名以下划线开头。

这样,sass就不会在编译时单独编译这个文件输出css,而只把这个文件用作导入。

当你@import一个局部文件时,还可以不写文件的全名,即省略文件名开头的下划线。

举例来说,你想导入themes/_night-sky.scss这个局部文件里的变量,你只需在样式表中写@import "themes/night-sky";。

局部文件可以被多个不同的文件引用。

当一些样式需要在多个页面甚至多个项目中使用时,这非常有用。

在这种情况下,有时需要在你的样式表中对导入的样式稍作修改,sass有一个功能刚好可以解决这个问题,即默认变量值。

3.2 默认变量值

一般情况下,你反复声明一个变量,只有最后一处声明有效且它会覆盖前边的值。举例说明:

  1. $link-color: blue;
  2. $link-color: red;
  3. a {
  4. color: $link-color;
  5. }

在上边的例子中,超链接的color会被设置为red。

这可能并不是你想要的结果,假如你写了一个可被他人通过@import导入的sass库文件,你可能希望导入者可以定制修改sass库文件中的某些值。

使用sass的!default标签可以实现这个目的。

它很像css属性中!important标签的对立面,不同的是!default用于变量,含义是:如果这个变量被声明赋值了,那就用它声明的值,否则就用这个默认值。

  1. $fancybox-width: 400px !default;
  2. .fancybox {
  3. width: $fancybox-width;
  4. }

在上例中,如果用户在导入你的sass局部文件之前声明了一个$fancybox-width变量,那么你的局部文件中对$fancybox-width赋值400px的操作就无效。

如果用户没有做这样的声明,则$fancybox-width将默认为400px。

3.3 嵌套导入

跟原生的css不同,sass允许@import命令写在css规则内。

这种导入方式下,生成对应的css文件时,局部文件会被直接插入到css规则内导入它的地方。

举例说明,有一个名为_blue-theme.scss的局部文件,内容如下:

  1. aside {
  2. background: blue;
  3. color: white;
  4. }

然后把它导入到一个CSS规则内,如下所示:

  1. .blue-theme {@import "blue-theme"}

生成的结果跟你直接在.blue-theme选择器内写_blue-theme.scss文件的内容完全一样。

  1. .blue-theme {
  2. aside {
  3. background: blue;
  4. color: #fff;
  5. }
  6. }

被导入的局部文件中定义的所有变量和混合器,也会在这个规则范围内生效。

这些变量和混合器不会全局有效,这样我们就可以通过嵌套导入只对站点中某一特定区域运用某种颜色主题或其他通过变量配置的样式。

3.4 原生的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后缀,即可直接导入了。

文件导入是保证sass的代码可维护性和可读性的重要一环。

次之但亦非常重要的就是注释了。

注释可以帮助样式作者记录写sass的过程中的想法。

在原生的css中,注释对于其他人是直接可见的,但sass提供了一种方式可在生成的css文件中按需抹掉相应的注释。

4 静默注释

css中注释的作用包括帮助你组织样式、以后你看自己的代码时明白为什么这样写,以及简单的样式说明。

但是,你并不希望每个浏览网站源码的人都能看到所有注释。

sass另外提供了一种不同于css标准注释格式/* ... */的注释语法,即静默注释,其内容不会出现在生成的css文件中。

静默注释的语法跟JavaScript`Java等类C的语言中单行注释的语法相同,它们以//开头,注释内容直到行末。

  1. body {
  2. color: #333; // 这种注释内容不会出现在生成的css文件中
  3. padding:; /* 这种注释内容会出现在生成的css文件中 */
  4. }

实际上,css的标准注释格式/* ... */内的注释内容亦可在生成的css文件中抹去。

当注释出现在原生css不允许的地方,如在css属性或选择器中,sass将不知如何将其生成到对应css文件中的相应位置,于是这些注释被抹掉。

  1. body {
  2. color /* 这块注释内容不会出现在生成的css中 */: #333;
  3. padding:; /* 这块注释内容也不会出现在生成的css中 */ 0;
  4. }

5 混合器

如果你的整个网站中有几处小小的样式类似(例如一致的颜色和字体),那么使用变量来统一处理这种情况是非常不错的选择。

但是当你的样式变得越来越复杂,你需要大段大段的重用样式的代码,独立的变量就没办法应付这种情况了。

你可以通过sass的混合器实现大段样式的重用。

混合器使用@mixin标识符定义。

看上去很像其他的CSS@标识符,比如说@media或者@font-face。

这个标识符给一大段样式赋予一个名字,这样你就可以轻易地通过引用这个名字重用这段样式。

下边的这段sass代码,定义了一个非常简单的混合器,目的是添加跨浏览器的圆角边框。

  1. @mixin rounded-corners {
  2. -moz-border-radius: 5px;
  3. -webkit-border-radius: 5px;
  4. border-radius: 5px;
  5. }

然后就可以在你的样式表中通过@include来使用这个混合器,放在你希望的任何地方。

@include调用会把混合器中的所有样式提取出来放在@include被调用的地方。

如果像下边这样写:

  1. .notice {
  2. background-color: green;
  3. border: 2px solid #00aa00;
  4. @include rounded-corners;
  5. }
  6. // 编译后
  7. .notice {
  8. background-color: green;
  9. border: 2px solid #00aa00;
  10. -moz-border-radius: 5px;
  11. -webkit-border-radius: 5px;
  12. border-radius: 5px;
  13. }

5.1 何时使用混合器

利用混合器,可以很容易地在样式表的不同地方共享样式。

如果你发现自己在不停地重复一段样式,那就应该把这段样式构造成优良的混合器,尤其是这段样式本身就是一个逻辑单元,比如说是一组放在一起有意义的属性。

判断一组属性是否应该组合成一个混合器,一条经验法则就是你能否为这个混合器想出一个好的名字。

如果你能找到一个很好的短名字来描述这些属性修饰的样式,比如rounded-corners、fancy-font或者no-bullets,那么往往能够构造一个合适的混合器。

如果你找不到,这时候构造一个混合器可能并不合适。

混合器在某些方面跟css类很像。

都是让你给一大段样式命名,所以在选择使用哪个的时候可能会产生疑惑。

最重要的区别就是类名是在html文件中应用的,而混合器是在样式表中应用的。

这就意味着类名具有语义化含义,而不仅仅是一种展示性的描述:用来描述html元素的含义而不是html元素的外观。

而另一方面,混合器是展示性的描述,用来描述一条css规则应用之后会产生怎样的效果。

在之前的例子中,.notice是一个有语义的类名。

如果一个html元素有一个notice的类名,就表明了这个html元素的用途:向用户展示提醒信息。

rounded-corners混合器是展示性的,它描述了包含它的css规则最终的视觉样式,尤其是边框角的视觉样式。

混合器和类配合使用写出整洁的html和css,因为使用语义化的类名亦可以帮你避免重复使用混合器。

为了保持你的html和css的易读性和可维护性,在写样式的过程中一定要铭记二者的区别。

5.2 混合器中的CSS规则

混合器中不仅可以包含属性,也可以包含css规则,包含选择器和选择器中的属性,如下代码:

  1. @mixin no-bullets {
  2. list-style: none;
  3. li {
  4. list-style-image: none;
  5. list-style-type: none;
  6. margin-left: 0px;
  7. }
  8. }

当一个包含css规则的混合器通过@include包含在一个父规则中时,在混合器中的规则最终会生成父规则中的嵌套规则。

举个例子,看看下边的sass代码,这个例子中使用了no-bullets这个混合器:

  1. ul.plain {
  2. color: #444;
  3. @include no-bullets;
  4. }

sass的@include指令会将引入混合器的那行代码替换成混合器里边的内容。

最终,上边的例子如下代码:

  1. ul.plain {
  2. color: #444;
  3. list-style: none;
  4. }
  5. ul.plain li {
  6. list-style-image: none;
  7. list-style-type: none;
  8. margin-left: 0px;
  9. }

混合器中的规则甚至可以使用sass的父选择器标识符&。

使用起来跟不用混合器时一样,sass解开嵌套规则时,用父规则中的选择器替代&。

5.3 给混合器传参

混合器并不一定总得生成相同的样式。

可以通过在@include混合器时给混合器传参,来定制混合器生成的精确样式。

当@include混合器时,参数其实就是可以赋值给css属性值的变量。

如果你写过JavaScript,这种方式跟JavaScript的function很像:

  1. @mixin link-colors($normal, $hover, $visited) {
  2. color: $normal;
  3. &:hover { color: $hover; }
  4. &:visited { color: $visited; }
  5. }

当混合器被@include时,你可以把它当作一个css函数来传参。

如果你像下边这样写:

  1. a {
  2. @include link-colors(blue, red, green);
  3. }
  4. // 编译后
  5. a { color: blue; }
  6. a:hover { color: red; }
  7. a:visited { color: green; }

当你@include混合器时,有时候可能会很难区分每个参数是什么意思,参数之间是一个什么样的顺序。

为了解决这个问题,sass允许通过语法$name: value的形式指定每个参数的值。

这种形式的传参,参数顺序就不必再在乎了,只需要保证没有漏掉参数即可:

  1. a {
  2. @include link-colors(
  3. $normal: blue,
  4. $visited: green,
  5. $hover: red
  6. );
  7. }

5.4 默认参数值

  1. @mixin link-colors($normal, $hover:$normal, $visited:$normal) {
  2. color: $normal;
  3. &:hover { color: $hover; }
  4. &:visited { color: $visited; }
  5. }

如果像下边这样调用:@include link-colors(red) $hover和$visited也会被自动赋值为red。

混合器只是sass样式重用特性中的一个。

我们已经了解到混合器主要用于样式展示层的重用,如果你想重用语义化的类呢?

这就涉及sass的另一个重要的重用特性:选择器继承。

6 使用选择器继承来精简CSS

使用sass的时候,最后一个减少重复的主要特性就是选择器继承。

基于Nicole Sullivan面向对象的css的理念,选择器继承是说一个选择器可以继承为另一个选择器定义的所有样式。

这个通过@extend语法实现,如下代码:

  1. // 通过选择器继承继承样式
  2. .error {
  3. border: 1px red;
  4. background-color: #fdd;
  5. }
  6. .seriousError {
  7. @extend .error;
  8. border-width: 3px;
  9. }

在上边的代码中,.seriousError将会继承样式表中任何位置处为.error定义的所有样式。

以class="seriousError" 修饰的html元素最终的展示效果就好像是class="seriousError error"。

相关元素不仅会拥有一个3px宽的边框,而且这个边框将变成红色的,这个元素同时还会有一个浅红色的背景,因为这些都是在.error里边定义的样式。

.seriousError不仅会继承.error自身的所有样式,任何跟.error有关的组合选择器样式也会被.seriousError以组合选择器的形式继承,如下代码:

  1. //.seriousError从.error继承样式
  2. .error a{ //应用到.seriousError a
  3. color: red;
  4. font-weight:;
  5. }
  6. h1.error { //应用到hl.seriousError
  7. font-size: 1.2rem;
  8. }

6.1 何时使用继承

因为继承是基于类的(有时是基于其他类型的选择器),所以继承应该是建立在语义化的关系上。

当一个元素拥有的类(比如说.seriousError)表明它属于另一个类(比如说.error),这时使用继承再合适不过了。

这有点抽象,所以我们从几个方面来阐释一下。

想象一下你正在编写一个页面,给html元素添加类名,你发现你的某个类(比如说.seriousError)另一个类(比如说.error)的细化。

你会怎么做?

你可以为这两个类分别写相同的样式,但是如果有大量的重复怎么办?

使用sass时,我们提倡的就是不要做重复的工作。

你可以使用一个选择器组(比如说.error、.seriousError)给这两个选择器写相同的样式。

如果.error的所有样式都在同一个地方,这种做法很好,但是如果是分散在样式表的不同地方呢?

再这样做就困难多了。

你可以使用一个混合器为这两个类提供相同的样式,但当.error的样式修饰遍布样式表中各处时,这种做法面临着跟使用选择器组一样的问题。

这两个类也不是恰好有相同的样式。

你应该更清晰地表达这种关系。

综上所述你应该使用@extend。

让.seriousError从.error继承样式,使两者之间的关系非常清晰。

更重要的是无论你在样式表的哪里使用.error、.seriousError都会继承其中的样式。

6.2 继承的高级用法

任何css规则都可以继承其他规则,几乎任何css规则也都可以被继承。

大多数情况你可能只想对类使用继承,但是有些场合你可能想做得更多。

最常用的一种高级用法是继承一个html元素的样式。

尽管默认的浏览器样式不会被继承,因为它们不属于样式表中的样式,但是你对html元素添加的所有样式都会被继承。

接下来的这段代码定义了一个名为disabled的类,样式修饰使它看上去像一个灰掉的超链接。

通过继承a这一超链接元素来实现:

  1. .disabled {
  2. color: gray;
  3. @extend a;
  4. }

假如一条样式规则继承了一个复杂的选择器,那么它只会继承这个复杂选择器命中的元素所应用的样式。

举例来说,如果.seriousError@extend.important.error,那么.important.error和h1.important.error的样式都会被.seriousError继承,但是.important或者.error下的样式则不会被继承。

这种情况下你很可能希望.seriousError能够分别继承.important或者.error`下的样式。

如果一个选择器序列(#main .seriousError)@extend另一个选择器(.error),那么只有完全命中#main .seriousError这个选择器的元素才会继承.error的样式,就像单个类名继承那样。

拥有class="seriousError"的.main元素之外的元素不会受到影响。

像#main .error这种选择器序列是不能被继承的。

这是因为从#main .error中继承的样式一般情况下会跟直接从.error中继承的样式基本一致,细微的区别往往使人迷惑。

6.3 继承的工作细节

跟变量和混合器不同,继承不是仅仅用css样式替换@extend处的代码那么简单。

为了不让你对生成的css感觉奇怪,对这背后的工作原理有一定了解是非常重要的。

@extend背后最基本的想法是,如果.seriousError @extend .error,那么样式表中的任何一处.error都用.error .seriousError这一选择器组进行替换。

这就意味着相关样式会如预期那样应用到.error和.seriousError。

当.error出现在复杂的选择器中,比如说h1.error.error a或者#main .sidebar input.error[type="text"],那情况就变得复杂多了,但是不用担心,sass`已经为你考虑到了这些。

关于@extend有两个要点你应该知道。

跟混合器相比,继承生成的css代码相对更少。

因为继承仅仅是重复选择器,而不会重复属性,所以使用继承往往比混合器生成的css体积更小。

如果你非常关心你站点的速度,请牢记这一点。

继承遵从css层叠的规则。

当两个不同的css规则应用到同一个html元素上时,并且这两个不同的css规则对同一属性的修饰存在不同的值,css层叠规则会决定应用哪个样式。

相当直观:通常权重更高的选择器胜出,如果权重相同,定义在后边的规则胜出。

混合器本身不会引起css层叠的问题,因为混合器把样式直接放到了css规则中,而继承存在样式层叠的问题。

被继承的样式会保持原有定义位置和选择器权重不变。

通常来说这并不会引起什么问题,但是知道这点总没有坏处。

6.4 使用继承的最佳实践

通常使用继承会让你的css美观、整洁。

因为继承只会在生成css时复制选择器,而不会复制大段的css属性。

但是如果你不小心,可能会让生成的css中包含大量的选择器复制。

避免这种情况出现的最好方法就是不要在css规则中使用后代选择器(比如.foo .bar)去继承css规则。

如果你这么做,同时被继承的css规则有通过后代选择器修饰的样式,生成css中的选择器的数量很快就会失控:

  1. .foo .bar { @extend .baz; }
  2. .bip .baz { a: b; }

在上边的例子中,sass必须保证应用到.baz的样式同时也要应用到.foo .bar(位于class="foo"的元素内的class="bar"的元素)。

例子中有一条应用到.bip .baz(位于class="bip"的元素内的class="baz"的元素)的css规则。

当这条规则应用到.foo .bar时,可能存在三种情况,如下代码:

  1. <!-- 继承可能迅速变复杂 -->
  2. <!-- Case 1 -->
  3. <div class="foo">
  4. <div class="bip">
  5. <div class="bar">...</div>
  6. </div>
  7. </div>
  8. <!-- Case 2 -->
  9. <div class="bip">
  10. <div class="foo">
  11. <div class="bar">...</div>
  12. </div>
  13. </div>
  14. <!-- Case 3 -->
  15. <div class="foo bip">
  16. <div class="bar">...</div>
  17. </div>

为了应付这些情况,sass必须生成三种选择器组合(仅仅是.bip .foo .bar不能覆盖所有情况)。

如果任何一条规则里边的后代选择器再长一点,sass需要考虑的情况就会更多。

实际上sass并不总是会生成所有可能的选择器组合,即使是这样,选择器的个数依然可能会变得相当大,所以如果允许,尽可能避免这种用法。

值得一提的是,只要你想,你完全可以放心地继承有后代选择器修饰规则的选择器,不管后代选择器多长,但有一个前提就是,不要用后代选择器去继承。

Sass入门及知识点整理的更多相关文章

  1. Less入门及知识点整理

    LESS « 一种动态样式语言 文档链接:http://www.bootcss.com/p/lesscss/ 百科 Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合( ...

  2. Java 入门学习知识点整理

    [JAVA一个文件写多个类 ( 同级类 ) 规则和注意点] 在一个.java文件中可以有多个同级类,  其修饰符只可以public/abstract/final/和无修饰符 public修饰的只能有一 ...

  3. css入门知识点整理

    css入门知识点整理 不要嘲笑我这个蒟蒻..例子来源:w3school css其实就分为两个东西,一个是选择器,另外一个是声明.声明定义了某个对象的属性的值,这都是html的内容.重点要关注的是选择器 ...

  4. 【Android 面试基础知识点整理】

    针对Android面试中常见的一些知识点整理,Max 仅仅是个搬运工.感谢本文中引用文章的各位作者,给大家分享了这么多优秀文章.对于当中的解析,是原作者个人见解,有错误和不准确的地方,也请大家积极指正 ...

  5. Java入门学习知识点汇总

    Java入门重要知识点在这里总结一下,以方便日后复习,这部分内容主要有:变量和常量,常用的运算符,流程控制语句,数组,方法这些内容 一.变量和常量 1.Java关键字 先贴张图: 所有关键字区分大小写 ...

  6. ACM个人零散知识点整理

    ACM个人零散知识点整理 杂项: 1.输入输出外挂 //读入优化 int 整数 inline int read(){ int x=0,f=1; char ch=getchar(); while(ch& ...

  7. Android 零散知识点整理

    Android 零散知识点整理 为什么Android的更新试图操作必须在主线程中进行? 这是因为Android系统中的视图组件并不是线程安全的.通常应该让主线程负责创建.显示和更新UI,启动子线程,停 ...

  8. vue前端面试题知识点整理

    vue前端面试题知识点整理 1. 说一下Vue的双向绑定数据的原理 vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫 ...

  9. React 入门学习笔记整理目录

    React 入门学习笔记整理(一)--搭建环境 React 入门学习笔记整理(二)-- JSX简介与语法 React 入门学习笔记整理(三)-- 组件 React 入门学习笔记整理(四)-- 事件 R ...

随机推荐

  1. Java面向对象 第2节 Scanner 类和格式化输出printf

    §Scanner 类 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入. 1.创建 Scanner 对象的基本语法:Scanner s = ...

  2. Spring Cloud(Dalston.SR5)--Config 集群配置中心

    Spring Cloud Config 是一个全新的项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,他分为服务端和客户端两个部分.服务端也称为分布式配置中心,是一个独立的微服务 ...

  3. mysql 远程备份

    #远程备份./innobackupex --defaults-file=/etc/my.cnf --no-timestamp --user xxx --host 192.168.1.123 \--pa ...

  4. Lock和synchronized的区别和使用

    Java并发编程:Lock 今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问 ...

  5. Inheritance setUp() and tearDown() methods from Classsetup() and Classteardown

      I have a general test class in my nosetests suit and some sub-classes, inheriting from it. The con ...

  6. Kubernetes Service Account如何生成Token

    Service Account是运行pods用到的帐号,默认是default.如果apiserver启动配置--admission-control=ServiceAccount,Service Acc ...

  7. 学习笔记之机器学习(Machine Learning)

    机器学习 - 维基百科,自由的百科全书 https://zh.wikipedia.org/wiki/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0 机器学习是人工智能的一个分 ...

  8. python:函数初始

    一.函数 1.函数初始:函数就是封装一个功能 2.函数名,函数体,关键字,函数的返回值 def 关键字,定义一个函数 my_len 函数名书写规则和变量一样 def 与函数名中间一个空格 函数名(): ...

  9. Zookeeper集群节点数量为什么要是奇数个?

    无论是公司的生产环境,还是自己搭建的测试环境,Zookeeper集群的节点个数都是奇数个.至于为什么要是奇数个,以前只是模糊的知道是为了满足选举需要,并不知道详细的原因.最近重点学习zookeeper ...

  10. 第27课 可变参数模板(8)_TupleHelper

    1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...