Sass基础教程-4 基本语法 样式规则 重大改变

2021-06-06
css
约 3809 字 预计阅读 8 分钟

本篇主要内容是sass的语法基础,样式规则以及一些重大的改变

1. 语法

1.1. Overview

其实是css语法的一个扩展,所有任何css的语法都可以在sass里写

1.2. 样式表的基本结构

1.2.1. 语句Statements

1.2.1.1. 通用语句
  • 变量声明, $var1: value1
  • 流程控制, @if @each @for等等
  • 调试和错误警告信息, @debug @error @warn
1.2.1.2. CSS语句
  • 样式规则
  • css的at-rules, @media @font-face
  • mixin的使用, @include
  • @at-root
1.2.1.3. 顶级语句

和样式本身无关

  • 模块的加载@use @forward
  • 导入 @import
  • mixin的声明@mixin
  • 函数定义@function
1.2.1.4. 其它语句
  • 属性声明, 基本的属性语法width: 100%;
  • 继承@extend

1.2.2. 表达式Expressions

表达式位于属性声明的右侧,或者变量声明的右侧,表达式可以产生值

1.2.2.1. 字面量

一些静态的值类型

  • Numbers, 有单位和无单位的数值, 12 or 100px.
  • Strings, 有引号和无引号的字符串 "Helvetica Neue" or bold.
  • Colors, 颜色值或者枚举值 #c6538c or blue.
  • boolean true or false.
  • 单一的空值 null.
  • Lists of values, 列表类型数值 1.5em 1em 0 2em, Helvetica, Arial, sans-serif, or [col1-start].
  • Maps 键值对类型数值 ("background": red, "foreground": pink).
1.2.2.2. 操作符
1.2.2.3. 其它表达式
  • Variables, 一个变量值引用 $var.
  • Function calls, 函数调用 比如 nth($list, 1) or var(--main-bg-color)
  • Special functions, 特殊函数,比如 calc(1px + 100%) or url(http://myapp.com/assets/logo.png), that have their own unique parsing rules.
  • The parent selector, 父选择器&.
  • The value !important, which is parsed as an unquoted string.

1.3. 注释

1.3.1. SCSS里的注释

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// This comment won't be included in the CSS.

/* But this comment will, except in compressed mode. */

/* It can also contain interpolation:
 * 1 + 1 = #{1 + 1} */

/*! This comment will be included even in compressed mode. */

p /* Multi-line comments can be written anywhere
   * whitespace is allowed. */ .sans {
  font: Helvetica, // So can single-line commments.
        sans-serif;
}

1.3.2. SASS里注释

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// This comment won't be included in the CSS.
   This is also commented out.

/* But this comment will, except in compressed mode.

/* It can also contain interpolation:
   1 + 1 = #{1 + 1}

/*! This comment will be included even in compressed mode.

p .sans
  font: Helvetica, /* Inline comments must be closed. */ sans-serif

1.3.3. 文档型注释

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/// Computes an exponent.
///
/// @param {number} $base
///   The number to multiply by itself.
/// @param {integer (unitless)} $exponent
///   The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent) {
  $result: 1;
  @for $_ from 1 through $exponent {
    $result: $result * $base;
  }
  @return $result;
}

参考:Sass: Comments (sass-lang.com)

1.4. 特殊方法

大部分css里的函数在sass脚本里都能正常工作,以下的几个函数比较特殊,在sass里有不同的意义

说白了下面这些函数在使用的过程中可以利用sass的表达式或者插值之类特性

1.4.1. url()

不带引号的,在sass里会被理解为表达式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$roboto-font-path: "../fonts/roboto";

@font-face {
    // This is parsed as a normal function call that takes a quoted string.
    src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");

    font-family: "Roboto";
    font-weight: 100;
}

@font-face {
    // This is parsed as a normal function call that takes an arithmetic
    // expression.
    src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");

    font-family: "Roboto";
    font-weight: 300;
}

@font-face {
    // This is parsed as an interpolated special function.
    src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");

    font-family: "Roboto";
    font-weight: 400;
}

1.4.2. calc(), clamp(), element(), progid:...(), and expression()

这些函数里可以使用插值,除了这种情况,sass不解析他们

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@use "sass:math";

.logo {
  $width: 800px;
  width: $width;
  position: absolute;
  left: calc(50% - #{math.div($width, 2)});
  top: 0;
}

// 输出
@use "sass:math";

.logo {
  width: 800px;
  position: absolute;
  left: calc(50% - 400px);
  top: 0;
}

1.4.3. min()max()

这两个函数,如果里面有插值, 则为css语法,如果有表达式则被解释为sass语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$padding: 12px;

.post {
  // Since these max() calls don't use any Sass features other than
  // interpolation, they're compiled to CSS max() calls.
  padding-left: max(#{$padding}, env(safe-area-inset-left));
  padding-right: max(#{$padding}, env(safe-area-inset-right));
}

.sidebar {
  // Since these refer to a Sass variable without interpolation, they call
  // Sass's built-in max() function.
  padding-left: max($padding, 20px);
  padding-right: max($padding, 20px);
}

1.4.4. 参考

2. 样式规则

2.1. Overview

样式规则是css中基础中的基础,通过在选择器上的属性定义来达到外观布局等等效果

2.1.1. 嵌套

嵌套使得我们的样式文件结构更清晰,并且避免了无意的对其它外层元素的影响

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

// 输出

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav li {
  display: inline-block;
}
nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none;
}

2.1.1.1. 选择器列表

sass能够很智能的进行组合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

.alert, .warning {
  ul, p {
    margin-right: 0;
    margin-left: 0;
    padding-bottom: 0;
  }
}
// 输出

.alert ul, .alert p, .warning ul, .warning p {
  margin-right: 0;
  margin-left: 0;
  padding-bottom: 0;
}
2.1.1.2. 组合选择器

您也可以嵌套使用组合器的选择器。 您可以将组合器放在外部选择器的末尾,内部选择器的开头,甚至可以单独放在两者之间。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ul > {
  li {
    list-style-type: none;
  }
}

h2 {
  + p {
    border-top: 1px solid gray;
  }
}

p {
  ~ {
    span {
      opacity: 0.8;
    }
  }
}

//输出
ul > li {
  list-style-type: none;
}

h2 + p {
  border-top: 1px solid gray;
}

p ~ span {
  opacity: 0.8;
}

2.1.1.3. 更高级的嵌套

参考下面的父选择器章节

注意: 后代选择器,空格分开的选择器组合,如果使用&父选择器, 编译结果父选择器是最后一个,看下面的示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.cls1 .cls2 {
    &.cls3 {
        font-size: 18px;
    }
}

// 输出
.cls1 .cls2.cls3 {
  font-size: 18px;
}

2.1.2. 插值

选择器在sass里也是可以用插值的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@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", "👭");

// 输出
@charset "UTF-8";
span.emoji-women-holding-hands {
  font-family: IconFont;
  font-variant: normal;
  font-weight: normal;
  content: "👭";
}

sass是先解析插值再解析选择器,所以可以放心的在选择器上使用差值

2.2. 属性声明

2.2.1. 插值

属性的声明也是可以自由的使用插值的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@mixin prefix($property, $value, $prefixes) {
  @each $prefix in $prefixes {
    -#{$prefix}-#{$property}: $value;
  }
  #{$property}: $value;
}

.gray {
  @include prefix(filter, grayscale(50%), moz webkit);
}

// 输出

.gray {
  -moz-filter: grayscale(50%);
  -webkit-filter: grayscale(50%);
  filter: grayscale(50%);
}

2.2.2. 嵌套(声明)

属性的声明也是可以嵌套的,因为如 font-, border-, padding-等等很多都是前缀相同的,利用sass可以少打好多字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.enlarge {
  font-size: 14px;
  transition: {
    property: font-size;
    duration: 4s;
    delay: 2s;
  }

  &:hover { font-size: 36px; }
}

// 输出

.enlarge {
  font-size: 14px;
  transition-property: font-size;
  transition-duration: 4s;
  transition-delay: 2s;
}
.enlarge:hover {
  font-size: 36px;
}

甚至有些,前缀本身可以有值的,可以这样写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.info-page {
  margin: auto {
    bottom: 10px;
    top: 2px;
  }
}

// 输出

.info-page {
  margin: auto;
  margin-bottom: 10px;
  margin-top: 2px;
}

2.2.3. 隐藏声明

如果sass发现有的表达式的值为null或者为没有引号的空字符串, 那sass解析时会忽略这个属性的定义

1
2
3
4
5
6
$rounded-corners: false;

.button {
  border: 1px solid black;
  border-radius: if($rounded-corners, 5px, null); // 这个会被忽略
}

2.2.4. 自定义属性

css允许自定义属性,一般是指变量声明, 并且这些属性的主要意义是提供给js访问, 所有标记都会原封不动的解释为css语言,除非里面使用了插值

自定义属性除非有插值,否则都被认为是css语法,sass不做任何处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
$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;
}

// 输出
:root {
  --primary: #81899b;
  --accent: #302e24;
  --warn: #dfa612;
  --consumed-by-js: $primary;
}

注意:

插值会删除字符串的引号,如果需要使用meta.inspect()来保留引号

1
2
3
4
5
6
7
8
9
@use "sass:meta";

$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;

:root {
  --font-family-sans-serif: #{meta.inspect($font-family-sans-serif)};
  --font-family-monospace: #{meta.inspect($font-family-monospace)};
}

2.3. 父选择器

在sass里&是一个特殊的占位符,表示父选择器,在内嵌样式中非常常见和重要,它和别的组合起来可以实现父选择器的伪类,组合等等

简单的使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.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;
  }
}

// 输出

.alert:hover {
  font-weight: bold;
}
[dir=rtl] .alert {
  margin-left: 0;
  margin-right: 10px;
}
:not(.alert) {
  opacity: 0.8;
}

父选择器暂时只能出现在开头

父选择器作为表达式用来得到父选择器的字面值,无论是组合关系列表等等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.main aside:hover,
.sidebar p {
  parent-selector: &;
  // => ((unquote(".main") unquote("aside:hover")),
  //     (unquote(".sidebar") unquote("p")))
}

// 输出

.main aside:hover,
.sidebar p {
  parent-selector: .main aside:hover, .sidebar p;
}

父选择器在出现在逻辑判断中

比如下面,使得mixin可以有选择的混合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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);
}

// 输出
.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);
}

更高级的内嵌用法

利用函数selector.unify组合父与子选择器,在用@at-root样式提取到外层

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@use "sass:selector";

@mixin unify-parent($child) {
  @at-root #{selector.unify(&, $child)} {
    @content;
  }
}

.wrapper .field {
  @include unify-parent("input") {
    /* ... */
  }
  @include unify-parent("select") {
    /* ... */
  }
}

// 输出
.wrapper input.field {
  /* ... */
}

.wrapper select.field {
  /* ... */
}

可以看到,这样做解决了一个问题, 将父选择器放到了组合选后面, 因为目前&只能用在表达式或者属性字面的开头,这样变相实现了父选择器的位置变换

这里@at-root的作用是明确,不要放到父选择器的下面了

如果去掉@at-root,结果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@use "sass:selector";

@mixin unify-parent($child) {
  #{selector.unify(&, $child)} {
    @content;
  }
}

.wrapper .field {
  @include unify-parent("input") {
    /* ... */
  }
  @include unify-parent("select") {
    /* ... */
  }
}
// 输出
.wrapper .field .wrapper input.field {
  /* ... */
}

.wrapper .field .wrapper select.field {
  /* ... */
}

2.4. 占位符选择器

占位符定义的样式,在sass编译会被删除,哪怕是组合选择器里有占位符选择器,编译后也不存在, 下面例子,两种都被删除掉了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.alert:hover, %strong-alert {
  font-weight: bold;
}

%strong-alert:hover {
  color: red;
}

// 编译后

.alert:hover {
  font-weight: bold;
}

一般结合@extend来使用占位符选择器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
%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;
}

// 输出
.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;
}

3. 重大改变(未完)

3.1. Overview

3.2. Slash和Division

3.3. 颜色单位

3.4. 扩展复合选择器

3.5. CSS变量语法

CSS本身支持--开头的变量定义,通过var()方法进行调用, 但是在SASS中注意尽量使用差值来给属性赋值,由于历史原因,如果不使用差值会被解析成CSS语法,

值没有被替换.

1
2
3
4
5
6
7
8
9
$accent-color: #fbbc04;

:root {
  // WRONG, will not work in recent Sass versions.
  --accent-color-wrong: $accent-color;

  // RIGHT, will work in all Sass versions.
  --accent-color-right: #{$accent-color};
}

生成如下

1
2
3
4
:root {
  --accent-color-wrong: $accent-color;
  --accent-color-right: #fbbc04;
}
TAG: sass scss css web
文章作者 : Cocding