关于Sass实践尝试

关于Sass实践尝试

最近项目引入Sass,并且对部分css进行了改进优化。Sass的语法学习使用是相对容易,但是结合实战,不同用法要适用于不同的场景,达到提高效率的目的才是关键。这篇文章对Sass使用技巧做一份小结,但不会一一列举Sass特性,更多知识详见官方文档。

嵌套中使用&

日常中,我们习惯创建一个盒子的时候,给容器命名一个class类,再给容器内各部分基于容器class类进行扩展命名,如:

.card {}
.card_title {}
.card_content{}
.card_extra{}
复制代码

我们总是不得不对容器class类名进行重写,而Sass可以很好地让我们少敲一些不必要的代码。这篇文章介绍了我们如何利用Sass来解决BEM命名方法产生很冗余的长命名问题,例如:

// scss
.card {
  &_title {}
  &_content {}
  &_extra {}
}

// 编译后 css
.card_title {}
.card_content{}
.card_extra{}
复制代码

循环

不得不说sass循环着实为我们减少代码的重复编写,解放我们的双手。

@for

用法

// start <= $var < end
@for $var from start to end
  
// start <= $var <= end
@for $var from start through end
复制代码

若我们使用html写一个loading样式

loading.gif

我们的loading元素是这样的

<div class="loading">
  {Array.from({ length: 12 }).map((_, i) => (
    <span key={i} />
  ))}
</div>
复制代码

每个span元素都是一个长方条,我们让他们旋转不同的角度,那么可以:

.loading span {
  // 省略...
  width: 3px;
  height: 7px;
  animation: roate 0.96s infinite;

  @for $i from 1 through 11 {
    &:nth-child(#{$i + 1}) {
      animation-delay: 0.08s * $i;
      transform: rotate(30deg * $i);
    }
  }
}
复制代码

@each

@each可以用来循环list或者map数据

假设我们有四个状态样式successwaringinfoerror,我们可以这样做:

// scss
$statusMap: (
  success: #3ccf3c,
  warning: #30baff,
  info: #ff9830,
  error: #ff2a2a
);

@each $header, $attrs in $statusMap {
  .#{$header} {
    color: $attrs;
  }
}

// 编译后 css
.success {
  color: #3ccf3c;
}
.warning {
  color: #30baff;
}
.info {
  color: #ff9830;
}
.error {
  color: #ff2a2a;
}
复制代码

这样便于我们维护和添加新的状态样式。

有时我们的状态样式并不是只有特定color,还有其他属性,那么map数据可以改成

$statusMap: (
  success: (
    border: 1px solid rgba(60, 207, 60, 0.3),
    background: rgba(60, 207, 60, 0.1),
    color: #3ccf3c
  ),
  warning: (
    border: 1px solid rgba(48, 186, 255, 0.3),
    background: rgba(48, 186, 255, 0.1),
    color: #30baff
  ),
  info: (
    border: 1px solid rgba(255, 152, 48, 0.3),
    background: rgba(255, 152, 48, 0.1),
    color: #ff9830
  ),
  error: (
    border: 1px solid rgba(255, 42, 42, 0.3),
    background: rgba(255, 42, 42, 0.1),
    color: #ff2a2a
  )
);
复制代码

然后我们可以进行双层遍历

@each $header, $attrs in $statusMap {
  .#{$header} {
    @each $key, $attr in $attrs {
      #{$key}:  $attr;
    }
  }
}
复制代码

编译得到我们想要的结果

.success {
  border: 1px solid rgba(60, 207, 60, 0.3);
  background: rgba(60, 207, 60, 0.1);
  color: #3ccf3c;
}
// 省略...
复制代码

同时状态样式可以结合@mixin使用。比如,有时候页面有些地方我们想只有color,有些又要color和background……

status.png

那么我们可以封装成@mixin,然后传入参数决定要哪些属性值

@mixin status($options...) { // 将多个参数处理为list
  // 默认color
  $array: if(list.length($options) > 0, $options, color);

  @each $label, $attrs in $statusMap {
    .#{$label} {
      @each $key in $array {
        #{$key}: map.get($attrs, $key);
      }
      // 内容占位符
      @content;
    }
  }
}
复制代码

现在调用这个mixin

.box1 {
  @include status;
}

.box2 {
  @include status(color, border) {
    border-radius: 4px;
  };
}
复制代码

编译后css

.box1 .success {
  color: #3ccf3c;
}
.box1 .warning {
  color: #30baff;
}
// 省略...

.box2 .success {
  color: #3ccf3c;
  border: 1px solid rgba(60, 207, 60, 0.3);
  border-radius: 4px;
}
// 省略...
复制代码

At-Rules

@mixin

@mixin是我们抽取公用样式块的利器。

用法

@mixin clearfix() {
  &::after {
    display: block;
    clear: both;
    content: "";
  }
}

.box {
  @include clearfix;
}
复制代码

我们还可以为@mixin添加参数,也可以导入内容@content。这两个@mixin的特性我们会经常用得到。

例如我们抽取了boostrap的表单部分片段

@mixin form-validation-state-selector($state) {
  @if ($state == "valid" or $state == "invalid") {
    .was-validated #{if(&, "&", "")}:#{$state},
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  } @else {
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  }
}
复制代码

这个mixin可以给不同表单校验状态给特定的类名添加自定义的内容。

我们举例给valid状态input框的class类添加这个mixin

.form-check-input {
  @include form-validation-state-selector(valid) {
    $color: #198754;
    border-color: $color;
    
    &:checked {
      background-color: $color;
    }
  }
}
复制代码

编译后css

.was-validated .form-check-input:valid, .form-check-input.is-valid {
  border-color: #198754;
}
.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {
  background-color: #198754;
}
复制代码

同时,我们注意到上面的mixinif(&, "&", "")。为何做这个判断呢?是因为如果定义的@mixin里有class类,那么@include不一定非要在某一个类嵌套里使用。例如像boostrap直接全局使用,而不需要嵌套里面使用。

$state: valid;
@include form-validation-state-selector($state) {
  ~ .#{$state}-feedback,
  ~ .#{$state}-tooltip {
    display: block;
  }
}
复制代码

这时的&父选择器是为空的,因为有if(&, "&", "")判断,那么编译的时候用空字符串代替

// 编译后 css
.was-validated :valid ~ .valid-feedback,
.was-validated :valid ~ .valid-tooltip,
.is-valid ~ .valid-feedback,
.is-valid ~ .valid-tooltip {
  display: block;
}
复制代码

关于mixin,还有我们比较少用的就是可以为@content添加参数

我们可以使用@content($var),并且当用到@include时可以用using($type)来接受参数。

// scss
@mixin media($types...) {
  @each $type in $types {
    @media #{$type} {
      @content($type);
    }
  }
}

@include media(screen, print) using ($type) {
  h1 {
    font-size: 40px;
    @if $type == print {
      font-family: Calluna;
    }
  }
}

// 编译后 css
@media screen {
  h1 {
    font-size: 40px;
  }
}
@media print {
  h1 {
    font-size: 40px;
    font-family: Calluna;
  }
}
复制代码

@extend

关于项目是否需要使用@extend,每个人的观点都不一样。从这篇文章分析来讲,@mixin@extend性能更好,能使用@mixin则使用它。

如果确切要使用@extend,我们必须先搞清楚选择器的层级关系,否则很容易适得其反。如果非要实际中找出比较普遍使用@extend场景,那就是@extend与占位符选择器 %foo结合使用。

// scss
%heading {
  margin-top: 0;
  margin-bottom: 0.5rem;
  font-weight: 500;
  line-height: 1.2;
  color: #222;
}

h1 {
  @extend %heading;
  font-size: 24px;
}
h2 {
  @extend %heading;
  font-size: 22px;
}
h3 {
  @extend %heading;
  font-size: 20px;
}

// 编译后css
h3, h2, h1 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  font-weight: 500;
  line-height: 1.2;
  color: #222;
}

h1 {
  font-size: 24px;
}
h2 {
  font-size: 22px;
}
h3 {
  font-size: 20px;
}
复制代码

@use

@use是用来代替@import。官方也说明了2022年会放弃对@import的支持。@import具体有什么劣势?例如

  • 当我们import很多scss文件时,针对某一个mixin或者函数,我们不能够方便地知道它是来自于哪个文件
  • 我们很容易产生命名冲突,导致不必要的错误。

更多问题官方文档已经为我们详细介绍了。

具体用法

// variables.scss
$red: #dc3545;

// index.scss
@use 'variables';
.box {
  color: variables.$red;
}
复制代码

我们还可以使用as更名

// index.scss
@use 'variables' as v;
.box {
  color: v.$red;
}
复制代码

又或者可以使用as *,省略模板名。但是如果引入多个模板,几个模板有相同名称的mixin或函数的话,很容易有冲突。请确保你想这样做。

// index.scss
@use 'variables' as *;
.box {
  color: $red;
}
复制代码

更多的就不再列举了,参照sass.bootcss.com/blog/the-mo…

额外

关于Visual Studio Code插件Live Sass Compiler可将Sass或Scss实时编译为CSS,这里推荐的插件github.com/ritwickdey/…,并没有跟sass更新而更新,很多新语法都会编译失败。建议使用另外一个github.com/glenn2223/v…

小结

合理地使用Sass,能够更好地管理我们的项目,同时便于维护。本次是个人使用Sass过程中的一些使用心得,之后会继续尝试更多更有实用的写法。若文章存在有误,欢迎各位指出。

参考资料

medium.com/@GarrettLev…

www.sass.hk/skill/sass1…

sass.bootcss.com/blog/featur…

sass.bootcss.com/blog/the-mo…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享