Skip to content
On this page

Sass 控制指令

Sass提供了强大的控制指令,包括条件判断、循环和条件赋值等,使您能够编写动态和智能的样式代码。本章将详细介绍Sass中的各种控制指令。

@if, @else if, @else 指令

条件指令允许您根据条件来决定应用哪些样式。

基本条件判断

scss
// 简单条件判断
$theme: dark;

.element {
  @if $theme == dark {
    background-color: #333;
    color: white;
  } @else {
    background-color: white;
    color: #333;
  }
}

// 多重条件判断
$size: large;

.button {
  @if $size == small {
    padding: 5px 10px;
    font-size: 12px;
  } @else if $size == medium {
    padding: 10px 20px;
    font-size: 14px;
  } @else if $size == large {
    padding: 15px 30px;
    font-size: 16px;
  } @else {
    padding: 12px 24px;
    font-size: 15px;
  }
}

复杂条件判断

scss
// 嵌套条件判断
$theme: dark;
$has-border: true;
$border-width: 2px;

.card {
  @if $theme == dark {
    background-color: #333;
    color: white;
    
    @if $has-border {
      border: $border-width solid #555;
    }
  } @else {
    background-color: white;
    color: #333;
    
    @if $has-border {
      border: $border-width solid #ddd;
    }
  }
}

// 使用函数进行条件判断
@function is-light($color) {
  @return lightness($color) > 50%;
}

$primary-color: #3498db;

.element {
  background-color: $primary-color;
  
  @if is-light($primary-color) {
    color: #333;
  } @else {
    color: white;
  }
}

布尔条件

scss
// 布尔值条件判断
$enable-animations: true;
$enable-rtl: false;
$has-shadow: true;

.component {
  @if $enable-animations {
    animation: fadeIn 0.3s ease-in-out;
  }
  
  @if $has-shadow {
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  }
  
  direction: if($enable-rtl, rtl, ltr);
}

// 组合条件
$has-header: true;
$has-footer: false;
$layout-type: 'sidebar';

.container {
  @if $has-header and $has-footer {
    padding: 2rem 0;
  } @else if $has-header or $has-footer {
    padding: 1rem 0;
  } @else {
    padding: 0;
  }
  
  @if $layout-type == 'sidebar' and $has-header {
    display: grid;
    grid-template-areas: 
      "header header"
      "sidebar content";
  }
}

@for 指令

@for指令用于创建循环,可以指定范围来生成重复的样式。

基本@for循环

scss
// 从1到5的循环
@for $i from 1 through 5 {
  .col-#{$i} {
    width: 20% * $i;
  }
}

// 从0到4的循环
@for $i from 0 to 5 {
  .item-#{$i} {
    margin-left: 10px * $i;
    z-index: 10 - $i;
  }
}

// 生成网格系统
$grid-columns: 12;

@for $i from 1 through $grid-columns {
  .col-#{$i} {
    width: percentage($i / $grid-columns);
  }
}

@for $i from 1 through 6 {
  h#{$i} {
    font-size: 2rem - ($i - 1) * 0.2rem;
    margin-bottom: 1rem - ($i - 1) * 0.1rem;
  }
}

高级@for用法

scss
// 使用@for生成响应式类
$breakpoints: (320px, 480px, 768px, 1024px, 1200px);

@for $i from 1 through length($breakpoints) {
  $bp: nth($breakpoints, $i);
  .breakpoint-#{$i} {
    @media (min-width: $bp) {
      display: block;
    }
  }
}

// 生成阴影深度
@for $i from 1 through 5 {
  .shadow-#{$i} {
    box-shadow: 0 ($i * 2px) ($i * 4px) rgba(0,0,0, 0.1 * $i);
  }
}

// 生成透明度类
@for $i from 1 through 10 {
  .opacity-#{$i * 10} {
    opacity: $i * 0.1;
  }
}

@each 指令

@each指令用于遍历列表或映射,是处理集合数据的最佳选择。

遍历列表

scss
// 遍历颜色列表
$colors: red, blue, green, yellow, purple;

@each $color in $colors {
  .bg-#{$color} {
    background-color: $color;
  }
  
  .text-#{$color} {
    color: $color;
  }
}

// 遍历尺寸列表
$sizes: small, medium, large;

@each $size in $sizes {
  .btn-#{$size} {
    @if $size == small {
      padding: 5px 10px;
      font-size: 12px;
    } @else if $size == medium {
      padding: 10px 20px;
      font-size: 14px;
    } @else {
      padding: 15px 30px;
      font-size: 16px;
    }
  }
}

遍历映射

scss
// 遍历主题颜色映射
$theme-colors: (
  "primary": #007bff,
  "secondary": #6c757d,
  "success": #28a745,
  "danger": #dc3545,
  "warning": #ffc107,
  "info": #17a2b8,
  "light": #f8f9fa,
  "dark": #343a40
);

@each $name, $color in $theme-colors {
  .bg-#{$name} {
    background-color: $color;
  }
  
  .text-#{$name} {
    color: $color;
  }
  
  .border-#{$name} {
    border-color: $color;
  }
  
  .btn-#{$name} {
    background-color: $color;
    border-color: $color;
    color: if(lightness($color) > 50, #212529, #fff);
    
    &:hover {
      background-color: darken($color, 10%);
      border-color: darken($color, 10%);
    }
  }
}

// 遍历断点映射
$breakpoints: (
  "xs": 0,
  "sm": 576px,
  "md": 768px,
  "lg": 992px,
  "xl": 1200px,
  "xxl": 1400px
);

@each $name, $breakpoint in $breakpoints {
  @if $name != "xs" {
    .d-#{$name}-none {
      @media (min-width: $breakpoint) {
        display: none !important;
      }
    }
    
    .container-#{$name} {
      @media (min-width: $breakpoint) {
        max-width: $breakpoint + 200px;
      }
    }
  }
}

嵌套@each循环

scss
// 嵌套遍历生成颜色变体
$colors: (primary: #007bff, secondary: #6c757d);
$variants: (light, normal, dark);

@each $color-name, $color in $colors {
  @each $variant in $variants {
    .#{$color-name}-#{$variant} {
      @if $variant == light {
        background-color: lighten($color, 20%);
      } @else if $variant == dark {
        background-color: darken($color, 20%);
      } @else {
        background-color: $color;
      }
    }
  }
}

@while 指令

@while指令提供基于条件的循环,当条件为真时继续执行。

基本@while循环

scss
// 使用@while生成序列
$i: 1;
@while $i <= 5 {
  .item-#{$i} {
    width: 20px * $i;
    height: 20px * $i;
  }
  $i: $i + 1;
}

// 生成递增的字体大小
$factor: 1;
@while $factor <= 3 {
  .scale-#{$factor} {
    transform: scale($factor);
    font-size: 1rem * $factor;
  }
  $factor: $factor + 0.5;
}

复杂@while应用

scss
// 使用@while创建递减的透明度
$opacity: 1;
@while $opacity > 0 {
  .fade-#{round($opacity * 100)} {
    opacity: $opacity;
  }
  $opacity: $opacity - 0.1;
}

// 生成递减的边距
$margin: 50px;
@while $margin >= 5px {
  .m-#{round($margin / 1px)} {
    margin: $margin;
  }
  $margin: $margin * 0.8; // 每次减少20%
}

综合应用示例

响应式网格系统

scss
// 定义断点和列数
$breakpoints: (
  "mobile": 480px,
  "tablet": 768px,
  "desktop": 1024px
);

$columns: 12;

// 生成基础网格类
@for $i from 1 through $columns {
  .col-#{$i} {
    width: percentage($i / $columns);
  }
}

// 为每个断点生成响应式类
@each $name, $breakpoint in $breakpoints {
  @media (min-width: $breakpoint) {
    @for $i from 1 through $columns {
      .col-#{$name}-#{$i} {
        width: percentage($i / $columns);
      }
    }
  }
}

主题变体生成

scss
// 定义主题配置
$themes: (
  light: (
    bg-color: #ffffff,
    text-color: #333333,
    border-color: #dddddd
  ),
  dark: (
    bg-color: #2d2d2d,
    text-color: #ffffff,
    border-color: #555555
  ),
  blue: (
    bg-color: #e3f2fd,
    text-color: #1a237e,
    border-color: #1e88e5
  )
);

// 生成主题类
@each $theme-name, $theme-map in $themes {
  .theme-#{$theme-name} {
    background-color: map-get($theme-map, bg-color);
    color: map-get($theme-map, text-color);
    border: 1px solid map-get($theme-map, border-color);
    
    // 为每个主题生成变体
    @each $element, $property in (header, nav, sidebar, footer) {
      &__#{$element} {
        @if $element == "header" or $element == "nav" {
          background-color: darken(map-get($theme-map, bg-color), 5%);
        } @else {
          background-color: lighten(map-get($theme-map, bg-color), 2%);
        }
      }
    }
  }
}

动画序列生成

scss
// 定义动画配置
$animations: (
  "fadeIn": (0, 1),
  "slideInLeft": (-100%, 0),
  "slideInRight": (100%, 0),
  "zoomIn": (0.5, 1)
);

// 生成动画类
@each $name, $values in $animations {
  @keyframes #{$name} {
    0% {
      @if $name == "fadeIn" {
        opacity: nth($values, 1);
      } @else if str-index($name, "slide") {
        transform: translateX(nth($values, 1));
      } @else if str-index($name, "zoom") {
        transform: scale(nth($values, 1));
        opacity: 0.5;
      }
    }
    100% {
      @if $name == "fadeIn" {
        opacity: nth($values, 2);
      } @else if str-index($name, "slide") {
        transform: translateX(nth($values, 2));
      } @else if str-index($name, "zoom") {
        transform: scale(nth($values, 2));
        opacity: 1;
      }
    }
  }
  
  .animate-#{$name} {
    animation: #{$name} 0.3s ease-in-out;
  }
}

条件样式生成

scss
// 配置变量
$include-animations: true;
$include-shadows: true;
$enable-rtl: false;

// 条件性地包含样式
.card {
  padding: 1rem;
  border-radius: 8px;
  
  @if $include-shadows {
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  }
  
  @if $include-animations {
    transition: all 0.3s ease-in-out;
    
    &:hover {
      @if $include-shadows {
        box-shadow: 0 4px 8px rgba(0,0,0,0.15);
      }
      transform: translateY(-2px);
    }
  }
  
  @if $enable-rtl {
    text-align: right;
    margin: 0 1rem 0 0;
  } @else {
    text-align: left;
    margin: 0 0 0 1rem;
  }
}

最佳实践

1. 避免过度复杂的条件

scss
// 不推荐:过于复杂的嵌套条件
.element {
  @if $condition1 {
    @if $condition2 {
      @if $condition3 {
        // 太深的嵌套难以维护
      }
    }
  }
}

// 推荐:提取复杂逻辑到函数
@function get-style($c1, $c2, $c3) {
  @if $c1 and $c2 and $c3 {
    @return complex-value;
  }
  @return default-value;
}

.element {
  property: get-style($condition1, $condition2, $condition3);
}

2. 合理使用循环

scss
// 注意性能:避免生成过多的CSS
// 推荐:设置合理的循环范围
@for $i from 1 through 12 {
  .col-#{$i} { width: percentage($i / 12); }
}

// 而不是
// @for $i from 1 through 100 { ... }

3. 有意义的变量命名

scss
// 好的命名
@for $column-count from 1 through 12 {
  .grid-span-#{$column-count} {
    grid-column: span $column-count;
  }
}

// 避免模糊的命名
@for $i from 1 through 12 {
  .class-#{$i} {
    // 不清楚$i代表什么
  }
}

Sass的控制指令提供了强大的逻辑处理能力,使您能够创建动态、灵活和可维护的样式系统。