SASS(二)

样式规则(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库时有些样式规则只需要某些情况下起作用,这时候占位符就显得格外有用。但根据经验,如果你只是为自己的应用编写样式表的话,如果有可用的类选择器,扩展类选择器通常更好。

 

posted @ 2019-08-26 17:03  BeeAndFlower  阅读(263)  评论(0编辑  收藏  举报