样式规则(Style Rules)
总览
和css一样,样式规则是Sass的基础,原理也差不多:用选择器选择你所要改变样式的元素,然后声明一些属性去决定它的样式。
Sass:
.button {
padding: 3px 10px;
font-size: 12px;
border-radius: 3px;
border: 1px solid #e1e4e8;
}
css:
.button {
padding: 3px 10px;
font-size: 12px;
border-radius: 3px;
border: 1px solid #e1e4e8;
}
1)嵌套(Nesting)
当然Sass致力于让码生幸福,不会让我们一遍又一遍地去写重复的选择器,所以你可以写嵌套样式,Sass会自动把外层选择器和内层样式规则结合起来。
Sass:
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
css:
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
注意:嵌套规则很好用,但是同时你也无法从视觉上去感受你到底产生了多少css,嵌套得越深加载所需带宽越高,浏览器渲染工作量也越大,所以尽量嵌套浅一些。
1.选择器列表(Selecor Lists)
嵌套规则在处理选择器列表(就是用逗号分隔的选择器)上还是比较智能的,每个复合选择器(逗号之间的)分别嵌套,再被结合为一个选择器列表。
Sass:
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
css:
.alert ul, .alert p, .warning ul, .warning p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
2.选择器连接符(Selector Combinators)
你也可以嵌套使用了连接符的选择器,连接符可以放在外部选择器的尾部,内部选择器的开头,或者是自身要连接的选择器之间。
Sass:
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
css:
ul > li {
list-style-type: none;
}
h2 + p {
border-top: 1px solid gray;
}
p ~ span {
opacity: 0.8;
}
3.高级嵌套(Advanced Nesting)
万一你不想让你的嵌套仅仅按顺序以派生连接符(就那空格)结合起来,Sass也是支持你的。详情见下节父选择器。
2)插值(Interpolation)
你可以使用插值来从表达式(比如变量、函数调用)中注入动态值到你的选择器中,这在你书写混合变量的时候格外有用,因为这样的话你就可以根据用户传入的变量来决定使用什么选择器。
Sass:
@mixin define-emoji($name, $glyph)
span.emoji-#{$name}
font-family: IconFont
font-variant: normal
font-weight: normal
content: $glyph
@include define-emoji("women-holding-hands", "👭")
css:
@charset "UTF-8";
span.emoji-women-holding-hands {
font-family: IconFont;
font-variant: normal;
font-weight: normal;
content: "👭";
}
PS:Sass只有在求得插值之后才会去解析选择器,所以你可以放心地在选择器的任何地方使用插值,不用担心它是不是还没有解析。
你可以在需要动态决定选择器的时候把插值和父选择器&、at-rules和选择器函数结合使用来达到效果。详情见下节父选择器。
属性声明(Property Declarations)
和css一样,Sass里的属性声明定义了和选择器匹配的元素的样式。但是Sass定义了额外的特性来增强易书写性和智能性。重要的是,声明的值可以是Sass表达式,它会被求值然后包含在结果中。
Sass:
.circle {
$size: 100px;
width: $size;
height: $size;
border-radius: $size / 2;
}
css:
.circle {
width: 100px;
height: 100px;
border-radius: 50px;
}
1)插值(Interpolation)
属性名可以包括插值,这样的话就可以按需决定使用哪个属性名了。甚至整个属性名都可以由插值决定。
Sass:
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.gray {
@include prefix(filter, grayscale(50%), moz webkit);
}
css:
.gray {
-moz-filter: grayscale(50%);
-webkit-filter: grayscale(50%);
filter: grayscale(50%);
}
2)嵌套(Nesting)
很多css属性以相同的前缀开头,这些前缀扮演着类似于命名空间的作用。举个例子,font-family、font-size、font-weight就都以font-开头。Sass通过允许属性声明嵌套来使写法更加简易。外层属性会加到内层属性上,通过连字符来连接。
Sass:
.enlarge {
font-size: 14px;
transition: {
property: font-size;
duration: 4s;
delay: 2s;
}
&:hover { font-size: 36px; }
}
css:
.enlarge {
font-size: 14px;
transition-property: font-size;
transition-duration: 4s;
transition-delay: 2s;
}
.enlarge:hover {
font-size: 36px;
}
PS:有些css属性使用命名空间名作为属性名的简略写法,这种情况你可以同时使用简略写法和复杂的嵌套写法。
Sass:
.info-page {
margin: auto {
bottom: 10px;
top: 2px;
}
}
css:
.info-page {
margin: auto;
margin-bottom: 10px;
margin-top: 2px;
}
3)隐式声明(Hidden Declarations)
有时候你想要一个属性声明只在特定时候出现,如果一个属性的值是null或者空的未加引号的字符串,Sass就不会把它编译到css中。
$rounded-corners: false;
.button {
border: 1px solid black;
border-radius: if($rounded-corners, 5px, null);
}
css:
.button {
border: 1px solid black;
}
4)自定义属性(Custom Properties)
css自定义属性,也被称为css变量,它们的声明语法比较特殊,允许变量名包含几乎任何文本,而且这些变量JavaScript也可以访问,所以任何变量对于书写者来说都可能有意义,包括被正常转为SassScript的变量。因此Sass解析自定义属性声明的时候跟正常属性声明不一样。所有类似于SassScript的字符会原样输出为css。唯一注入动态变量到自定义属性的方法是插值。
Sass:
$primary: #81899b;
$accent: #302e24;
$warn: #dfa612;
:root {
--primary: #{$primary};
--accent: #{$accent};
--warn: #{$warn};
// Even though this looks like a Sass variable, it's valid CSS so it's not
// evaluated.
--consumed-by-js: $primary;
}
css:
:root {
--primary: #81899b;
--accent: #302e24;
--warn: #dfa612;
--consumed-by-js: $primary;
}
注意:不幸的是插值会移除字符串的引号,所以将来自Sass变量的被引号包裹的字符串注入自定义属性就比较困难,但是你可以使用inspect()方法来保留引号。
Sass:
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;
:root {
--font-family-sans-serif: #{inspect($font-family-sans-serif)};
--font-family-monospace: #{inspect($font-family-monospace)};
}
css:
:root {
--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;
}
父选择器(Parent Selector)
父选择器&是Sass独创的一个选择器,用于在嵌套选择器中指向其外层选择器,利用父选择器可以实现外层选择器的多重复杂重用,比如增加一个伪类或者其他选择器。
和正常的嵌套机制不同,当父选择器在一个选择器内部使用时它指代的就是这个选择器。
Sass:
.alert {
// The parent selector can be used to add pseudo-classes to the outer
// selector.
&:hover {
font-weight: bold;
}
// It can also be used to style the outer selector in a certain context, such
// as a body set to use a right-to-left language.
[dir=rtl] & {
margin-left: 0;
margin-right: 10px;
}
// You can even use it as an argument to pseudo-class selectors.
:not(&) {
opacity: 0.8;
}
}
css:
.alert:hover {
font-weight: bold;
}
[dir=rtl] .alert {
margin-left: 0;
margin-right: 10px;
}
:not(.alert) {
opacity: 0.8;
}
注意:由于父选择器可以代表类选择器比如h1,它只能出现在类选择器能够出现的地方即复合选择器开头,例如span&就是不合法的写法。我们也在尝试放松这些限制,你想的话可以加入我们。
1)添加后缀(Adding Suffix)
你也可以使用父选择器来为外层选择器添加后缀,这在使用某些例如BEM这种使用高度结构化类名的命名原则时会格外有用,只要外层选择器以含有字母和数字的名称(比如class,id,元素选择器)结尾,你就可以使用父选择器添加额外文本。
Sass:
.accordion {
max-width: 600px;
margin: 4rem auto;
width: 90%;
font-family: "Raleway", sans-serif;
background: #f4f4f4;
&__copy {
display: none;
padding: 1rem 1.5rem 2rem 1.5rem;
color: gray;
line-height: 1.6;
font-size: 14px;
font-weight: 500;
&--open {
display: block;
}
}
}
css:
.accordion {
max-width: 600px;
margin: 4rem auto;
width: 90%;
font-family: "Raleway", sans-serif;
background: #f4f4f4;
}
.accordion__copy {
display: none;
padding: 1rem 1.5rem 2rem 1.5rem;
color: gray;
line-height: 1.6;
font-size: 14px;
font-weight: 500;
}
.accordion__copy--open {
display: block;
}
2)SassScript用法(In SassScript)
父选择器可以在SassScript中使用,属于特殊表达式,返回当前父选择器,和选择器函数使用的格式一样,包含以空格分隔的列表即复杂选择器(the complex selectors )的以逗号分隔的选择器列表(the selector list),复杂选择器又可能包含不带引号的字符串即复合选择器(the compound selectors)。
Sass:
SCSS SYNTAX
.main aside:hover,
.sidebar p {
parent-selector: &;
// => ((unquote(".main") unquote("aside:hover")),
// (unquote(".sidebar") unquote("p")))
}
css:
.main aside:hover,
.sidebar p {
parent-selector: .main aside:hover, .sidebar p;
}
如果父选择器在样式规则外层使用,它会返回null,而null属于falsey,因此你可以借此来决定在一个样式规则中要不要引用一个混合类型。
Sass:
@mixin app-background($color) {
#{if(&, '&.app-background', '.app-background')} {
background-color: $color;
color: rgba(#fff, 0.75);
}
}
@include app-background(#036);
.sidebar {
@include app-background(#c6538c);
}
css:
.app-background {
background-color: #036;
color: rgba(255, 255, 255, 0.75);
}
.sidebar.app-background {
background-color: #c6538c;
color: rgba(255, 255, 255, 0.75);
}
高级嵌套(Advanced Nesting)
你可以把父选择器作为正常表达式使用,也就是说你可以把它传入函数或者插值,即使是在别的选择器里。结合选择器函数和@at-root规则使用可以达到非常强大的嵌套效果。
举个例子,假设你要写一个选择器来匹配外层选择器和一个元素选择器,你可以像这样使用selector-unify()函数来结合父选择器和另一个自定义选择器:
Sass:
@mixin unify-parent($child) {
@at-root #{selector-unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
css:
.wrapper input.field {
/* ... */
}
.wrapper select.field {
/* ... */
}
注意:Sass在处理嵌套的时候,它也不知道这些选择器是由什么样的插值产生的,所以它会自动把外层选择器加到内层选择器前面,即使你使用了父选择器作为SassScript表达式。所以你要使用@at-root规则来明确告诉Sass不要去包含外层选择器。
占位符选择器(Placeholder Selectors)
Sass还有一种特殊的选择器‘占位符’。它的长相和行为都很像一个类选择器,不同的是它以%开头并且不输出到css中。事实上,任何含有了占位符选择器的复杂选择器(被逗号隔离的那些)及其对应样式规则都不会被输出到css中。
Sass:
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
css:
.alert:hover {
font-weight: bold;
}
一个选择器它都被全部忽略了那要它干嘛?诶,它还可以被扩展。不像类选择器,如果不进行扩展,并且不要求库的用户为其HTML使用特定的类名,则占位符不会出现使得css一团乱。
Sass:
%toolbelt {
box-sizing: border-box;
border-top: 1px rgba(#000, .12) solid;
padding: 16px 0;
width: 100%;
&:hover { border: 2px rgba(#000, .5) solid; }
}
.action-buttons {
@extend %toolbelt;
color: #4285f4;
}
.reset-buttons {
@extend %toolbelt;
color: #cddc39;
}
css:
.action-buttons, .reset-buttons {
box-sizing: border-box;
border-top: 1px rgba(0, 0, 0, 0.12) solid;
padding: 16px 0;
width: 100%;
}
.action-buttons:hover, .reset-buttons:hover {
border: 2px rgba(0, 0, 0, 0.5) solid;
}
.action-buttons {
color: #4285f4;
}
.reset-buttons {
color: #cddc39;
}
在编写一个Sass库时有些样式规则只需要某些情况下起作用,这时候占位符就显得格外有用。但根据经验,如果你只是为自己的应用编写样式表的话,如果有可用的类选择器,扩展类选择器通常更好。