Skip to content
On this page

Sass 实战案例

本章将通过实际项目案例来展示如何在真实场景中应用Sass,包括完整的项目搭建、组件开发、响应式设计实现等。

案例一:企业官网样式系统

项目初始化

scss
// abstracts/_variables.scss
// 企业官网设计系统变量
$brand-colors: (
  primary: #2563eb,
  secondary: #64748b,
  accent: #f59e0b,
  success: #10b981,
  warning: #f59e0b,
  danger: #ef4444,
  dark: #1e293b,
  light: #f8fafc
);

$typography: (
  family-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif,
  family-serif: 'Playfair Display', Georgia, 'Times New Roman', serif,
  family-mono: 'Fira Code', Consolas, monospace,
  
  sizes: (
    xs: 0.75rem,
    sm: 0.875rem,
    base: 1rem,
    lg: 1.125rem,
    xl: 1.25rem,
    '2xl': 1.5rem,
    '3xl': 1.875rem,
    '4xl': 2.25rem,
    '5xl': 3rem,
    '6xl': 3.75rem
  ),
  
  weights: (
    thin: 100,
    extralight: 200,
    light: 300,
    normal: 400,
    medium: 500,
    semibold: 600,
    bold: 700,
    extrabold: 800,
    black: 900
  )
);

$spacing: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.25rem,
  6: 1.5rem,
  8: 2rem,
  10: 2.5rem,
  12: 3rem,
  16: 4rem,
  20: 5rem,
  24: 6rem,
  32: 8rem
);

$breakpoints: (
  sm: 640px,
  md: 768px,
  lg: 1024px,
  xl: 1280px,
  '2xl': 1536px
);

$border-radius: (
  none: 0,
  sm: 0.125rem,
  default: 0.25rem,
  md: 0.375rem,
  lg: 0.5rem,
  xl: 0.75rem,
  '2xl': 1rem,
  full: 9999px
);

$shadows: (
  sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05),
  default: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 
  md: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
  lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
  xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1)
);
scss
// abstracts/_functions.scss
@function brand-color($key) {
  @return map-get($brand-colors, $key);
}

@function font-size($key) {
  @return map-get(map-get($typography, sizes), $key);
}

@function font-weight($key) {
  @return map-get(map-get($typography, weights), $key);
}

@function spacing($key) {
  @return map-get($spacing, $key);
}

@function breakpoint($key) {
  @return map-get($breakpoints, $key);
}

@function border-radius($key) {
  @return map-get($border-radius, $key);
}

@function shadow($key) {
  @return map-get($shadows, $key);
}
scss
// abstracts/_mixins.scss
@mixin respond-above($breakpoint) {
  @media (min-width: breakpoint($breakpoint)) {
    @content;
  }
}

@mixin respond-below($breakpoint) {
  @media (max-width: breakpoint($breakpoint) - 1px) {
    @content;
  }
}

@mixin respond-between($lower, $upper) {
  @media (min-width: breakpoint($lower)) and (max-width: breakpoint($upper) - 1px) {
    @content;
  }
}

@mixin container {
  width: 100%;
  padding-right: spacing(4);
  padding-left: spacing(4);
  margin-right: auto;
  margin-left: auto;
  
  @include respond-above(lg) {
    max-width: 1024px;
  }
  
  @include respond-above(xl) {
    max-width: 1280px;
  }
}

@mixin button-base {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: map-get($typography, family-sans);
  font-weight: font-weight(semibold);
  text-decoration: none;
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
  border-radius: border-radius(default);
  
  &:hover {
    transform: translateY(-1px);
    box-shadow: shadow(md);
  }
  
  &:active {
    transform: translateY(0);
  }
  
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}

@mixin card {
  background-color: white;
  border-radius: border-radius(lg);
  box-shadow: shadow(default);
  overflow: hidden;
}

组件开发

scss
// components/_header.scss
.header {
  background-color: white;
  box-shadow: shadow(default);
  position: sticky;
  top: 0;
  z-index: 50;
  
  @include respond-above(lg) {
    padding: spacing(4) 0;
  }
  
  &__container {
    @include container;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  &__logo {
    font-family: map-get($typography, family-serif);
    font-size: font-size('xl');
    font-weight: font-weight(bold);
    color: brand-color(primary);
    text-decoration: none;
    
    @include respond-above(md) {
      font-size: font-size('2xl');
    }
  }
  
  &__nav {
    display: none;
    
    @include respond-above(lg) {
      display: flex;
      align-items: center;
    }
  }
  
  &__nav-list {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    gap: spacing(6);
  }
  
  &__nav-link {
    text-decoration: none;
    color: brand-color(dark);
    font-weight: font-weight(medium);
    padding: spacing(2) spacing(3);
    border-radius: border-radius(default);
    transition: color 0.2s ease;
    
    &:hover {
      color: brand-color(primary);
      background-color: rgba(brand-color(primary), 0.1);
    }
    
    &--active {
      color: brand-color(primary);
      background-color: rgba(brand-color(primary), 0.1);
    }
  }
  
  &__mobile-toggle {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 30px;
    height: 21px;
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 0;
    z-index: 100;
    
    @include respond-above(lg) {
      display: none;
    }
    
    &-line {
      width: 100%;
      height: 3px;
      background-color: brand-color(dark);
      border-radius: 2px;
      transition: all 0.3s ease;
    }
  }
}

// 移动端导航
.mobile-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(white, 0.95);
  backdrop-filter: blur(10px);
  z-index: 40;
  display: flex;
  flex-direction: column;
  padding: spacing(6) spacing(4);
  transform: translateX(-100%);
  transition: transform 0.3s ease;
  
  &--open {
    transform: translateX(0);
  }
  
  &__close {
    align-self: flex-end;
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    padding: spacing(2);
    margin-bottom: spacing(6);
  }
  
  &__menu {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  
  &__item {
    margin-bottom: spacing(4);
  }
  
  &__link {
    text-decoration: none;
    color: brand-color(dark);
    font-size: font-size(xl);
    font-weight: font-weight(semibold);
    display: block;
    padding: spacing(3);
    border-radius: border-radius(default);
    
    &:hover {
      background-color: rgba(brand-color(primary), 0.1);
      color: brand-color(primary);
    }
  }
}
scss
// components/_hero.scss
.hero {
  padding: spacing(12) spacing(4);
  background: linear-gradient(135deg, brand-color(primary) 0%, brand-color(secondary) 100%);
  color: white;
  text-align: center;
  
  @include respond-above(md) {
    padding: spacing(20) spacing(4);
  }
  
  &__container {
    @include container;
  }
  
  &__title {
    font-size: font-size('4xl');
    font-weight: font-weight(extrabold);
    margin-bottom: spacing(4);
    line-height: 1.2;
    
    @include respond-above(md) {
      font-size: font-size('5xl');
    }
    
    @include respond-above(lg) {
      font-size: font-size('6xl');
    }
  }
  
  &__subtitle {
    font-size: font-size(lg);
    margin-bottom: spacing(8);
    max-width: 2xl;
    margin-left: auto;
    margin-right: auto;
    
    @include respond-above(md) {
      font-size: font-size(xl);
    }
  }
  
  &__actions {
    display: flex;
    flex-direction: column;
    gap: spacing(4);
    align-items: center;
    
    @include respond-above(sm) {
      flex-direction: row;
      justify-content: center;
    }
  }
  
  &__button {
    @include button-base;
    background-color: brand-color(accent);
    color: brand-color(dark);
    padding: spacing(3) spacing(6);
    font-size: font-size(lg);
    
    &:hover {
      background-color: darken(brand-color(accent), 10%);
    }
  }
  
  &__button--secondary {
    @include button-base;
    background-color: transparent;
    color: white;
    padding: spacing(3) spacing(6);
    font-size: font-size(lg);
    border: 2px solid white;
    
    &:hover {
      background-color: rgba(white, 0.1);
    }
  }
}
scss
// components/_features.scss
.features {
  padding: spacing(16) spacing(4);
  
  @include respond-above(md) {
    padding: spacing(20) spacing(4);
  }
  
  &__container {
    @include container;
  }
  
  &__header {
    text-align: center;
    margin-bottom: spacing(12);
  }
  
  &__title {
    font-size: font-size('3xl');
    font-weight: font-weight(bold);
    color: brand-color(dark);
    margin-bottom: spacing(3);
    
    @include respond-above(md) {
      font-size: font-size('4xl');
    }
  }
  
  &__subtitle {
    font-size: font-size(lg);
    color: brand-color(secondary);
    max-width: 2xl;
    margin: 0 auto;
  }
  
  &__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: spacing(8);
    
    @include respond-above(md) {
      grid-template-columns: repeat(2, 1fr);
      gap: spacing(10);
    }
    
    @include respond-above(lg) {
      grid-template-columns: repeat(3, 1fr);
    }
  }
  
  &__item {
    @include card;
    padding: spacing(6);
    text-align: center;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    
    &:hover {
      transform: translateY(-5px);
      box-shadow: shadow(lg);
    }
  }
  
  &__icon {
    width: 3rem;
    height: 3rem;
    background-color: rgba(brand-color(primary), 0.1);
    border-radius: border-radius(full);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto spacing(4);
    color: brand-color(primary);
    font-size: font-size(xl);
  }
  
  &__item-title {
    font-size: font-size(xl);
    font-weight: font-weight(semibold);
    color: brand-color(dark);
    margin-bottom: spacing(3);
  }
  
  &__item-description {
    color: brand-color(secondary);
    line-height: 1.6;
  }
}
scss
// components/_testimonials.scss
.testimonials {
  padding: spacing(16) spacing(4);
  background-color: brand-color(light);
  
  @include respond-above(md) {
    padding: spacing(20) spacing(4);
  }
  
  &__container {
    @include container;
  }
  
  &__header {
    text-align: center;
    margin-bottom: spacing(12);
  }
  
  &__title {
    font-size: font-size('3xl');
    font-weight: font-weight(bold);
    color: brand-color(dark);
    margin-bottom: spacing(3);
    
    @include respond-above(md) {
      font-size: font-size('4xl');
    }
  }
  
  &__subtitle {
    font-size: font-size(lg);
    color: brand-color(secondary);
    max-width: 2xl;
    margin: 0 auto;
  }
  
  &__carousel {
    position: relative;
    overflow: hidden;
    border-radius: border-radius(xl);
  }
  
  &__slides {
    display: flex;
    transition: transform 0.5s ease;
  }
  
  &__slide {
    min-width: 100%;
    padding: spacing(8);
    background-color: white;
    box-shadow: shadow(md);
  }
  
  &__quote {
    font-size: font-size(lg);
    font-style: italic;
    color: brand-color(dark);
    text-align: center;
    margin-bottom: spacing(6);
    
    @include respond-above(md) {
      font-size: font-size(xl);
    }
  }
  
  &__author {
    text-align: center;
  }
  
  &__author-name {
    font-weight: font-weight(semibold);
    color: brand-color(dark);
  }
  
  &__author-title {
    color: brand-color(secondary);
    font-size: font-size(sm);
  }
  
  &__controls {
    display: flex;
    justify-content: center;
    gap: spacing(2);
    margin-top: spacing(6);
  }
  
  &__control {
    width: 12px;
    height: 12px;
    border-radius: border-radius(full);
    background-color: brand-color(secondary);
    border: none;
    cursor: pointer;
    transition: background-color 0.3s ease;
    
    &--active {
      background-color: brand-color(primary);
    }
  }
}

案例二:电商平台组件库

设计系统建立

scss
// ecom-abstracts/_variables.scss
// 电商专用变量
$ecom-colors: (
  primary: #ff6b35,      // 橙色主色
  secondary: #2a9d8f,    // 绿色辅助色
  success: #2a9d8f,      // 成功色
  warning: #e9c46a,      // 警告色
  danger: #e76f51,       // 危险色
  info: #457b9d,         // 信息色
  background: #f8f9fa,   // 背景色
  surface: #ffffff,      // 表面色
  text-primary: #212529, // 主要文字
  text-secondary: #6c757d, // 次要文字
  border: #dee2e6        // 边框色
);

$ecom-typography: (
  family-primary: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif,
  family-display: 'Montserrat', sans-serif,
  
  sizes: (
    '2xs': 0.625rem,  // 10px
    xs: 0.75rem,      // 12px
    sm: 0.875rem,     // 14px
    base: 1rem,       // 16px
    lg: 1.125rem,     // 18px
    xl: 1.25rem,      // 20px
    '2xl': 1.5rem,    // 24px
    '3xl': 1.875rem,  // 30px
    '4xl': 2.25rem,   // 36px
    '5xl': 3rem,      // 48px
    '6xl': 3.75rem    // 60px
  )
);

$ecom-spacing: (
  0: 0,
  1: 0.25rem,    // 4px
  2: 0.5rem,     // 8px
  3: 0.75rem,    // 12px
  4: 1rem,       // 16px
  5: 1.25rem,    // 20px
  6: 1.5rem,     // 24px
  8: 2rem,       // 32px
  10: 2.5rem,    // 40px
  12: 3rem,      // 48px
  16: 4rem,      // 64px
  20: 5rem,      // 80px
  24: 6rem       // 96px
);

$ecom-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
);

$ecom-grid: (
  columns: 12,
  gutter: 1.5rem,
  container-max-widths: (
    sm: 540px,
    md: 720px,
    lg: 960px,
    xl: 1140px,
    xxl: 1320px
  )
);

产品卡片组件

scss
// ecom-components/_product-card.scss
@use '../ecom-abstracts/variables' as ecom;

.product-card {
  background-color: map-get(ecom.$ecom-colors, surface);
  border: 1px solid map-get(ecom.$ecom-colors, border);
  border-radius: 0.5rem;
  overflow: hidden;
  transition: all 0.3s ease;
  position: relative;
  
  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
  }
  
  &__badge {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    background-color: map-get(ecom.$ecom-colors, danger);
    color: white;
    padding: 0.25rem 0.5rem;
    border-radius: 0.25rem;
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), xs);
    font-weight: 600;
    z-index: 10;
    
    &--new {
      background-color: map-get(ecom.$ecom-colors, success);
    }
    
    &--sale {
      background-color: map-get(ecom.$ecom-colors, warning);
      color: #333;
    }
  }
  
  &__image-container {
    position: relative;
    padding-top: 100%; // 1:1 aspect ratio
    overflow: hidden;
    
    &::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: linear-gradient(45deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.3) 100%);
    }
  }
  
  &__image {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
    
    .product-card:hover & {
      transform: scale(1.05);
    }
  }
  
  &__info {
    padding: 1rem;
  }
  
  &__category {
    color: map-get(ecom.$ecom-colors, text-secondary);
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), xs);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 0.25rem;
  }
  
  &__title {
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), base);
    font-weight: 600;
    color: map-get(ecom.$ecom-colors, text-primary);
    margin-bottom: 0.5rem;
    line-height: 1.4;
    
    &:hover {
      color: map-get(ecom.$ecom-colors, primary);
    }
  }
  
  &__price-container {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
  }
  
  &__current-price {
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), lg);
    font-weight: 700;
    color: map-get(ecom.$ecom-colors, primary);
  }
  
  &__original-price {
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), sm);
    color: map-get(ecom.$ecom-colors, text-secondary);
    text-decoration: line-through;
  }
  
  &__discount {
    color: map-get(ecom.$ecom-colors, danger);
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), sm);
    font-weight: 600;
  }
  
  &__rating {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-bottom: 0.75rem;
  }
  
  &__stars {
    color: map-get(ecom.$ecom-colors, warning);
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), sm);
  }
  
  &__reviews {
    color: map-get(ecom.$ecom-colors, text-secondary);
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), xs);
  }
  
  &__actions {
    display: flex;
    gap: 0.5rem;
  }
  
  &__action-button {
    flex: 1;
    padding: 0.5rem;
    border: 1px solid map-get(ecom.$ecom-colors, border);
    border-radius: 0.375rem;
    background: white;
    cursor: pointer;
    transition: all 0.2s ease;
    
    &:hover {
      border-color: map-get(ecom.$ecom-colors, primary);
      color: map-get(ecom.$ecom-colors, primary);
    }
    
    &--add-to-cart {
      background-color: map-get(ecom.$ecom-colors, primary);
      color: white;
      border-color: map-get(ecom.$ecom-colors, primary);
      
      &:hover {
        background-color: darken(map-get(ecom.$ecom-colors, primary), 10%);
        border-color: darken(map-get(ecom.$ecom-colors, primary), 10%);
      }
    }
  }
}

// 响应式产品卡片
@include media-query(map-get(ecom.$ecom-breakpoints, md)) {
  .product-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 1.5rem;
  }
}

@include media-query(map-get(ecom.$ecom-breakpoints, lg)) {
  .product-card-grid {
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  }
}

购物车组件

scss
// ecom-components/_cart.scss
.cart {
  &__drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 100%;
    max-width: 400px;
    height: 100vh;
    background: white;
    box-shadow: -5px 0 15px rgba(0, 0, 0, 0.1);
    z-index: 1000;
    transform: translateX(100%);
    transition: transform 0.3s ease;
    
    &--open {
      transform: translateX(0);
    }
  }
  
  &__header {
    padding: 1rem;
    border-bottom: 1px solid map-get(ecom.$ecom-colors, border);
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  &__title {
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), xl);
    font-weight: 600;
    color: map-get(ecom.$ecom-colors, text-primary);
  }
  
  &__close {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: map-get(ecom.$ecom-colors, text-secondary);
  }
  
  &__items {
    padding: 1rem;
    max-height: calc(100vh - 200px);
    overflow-y: auto;
  }
  
  &__item {
    display: flex;
    gap: 1rem;
    padding: 1rem 0;
    border-bottom: 1px solid map-get(ecom.$ecom-colors, border);
  }
  
  &__item-image {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border-radius: 0.5rem;
  }
  
  &__item-details {
    flex: 1;
  }
  
  &__item-name {
    font-weight: 600;
    color: map-get(ecom.$ecom-colors, text-primary);
    margin-bottom: 0.25rem;
  }
  
  &__item-price {
    color: map-get(ecom.$ecom-colors, primary);
    font-weight: 600;
    margin-bottom: 0.5rem;
  }
  
  &__item-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  
  &__quantity {
    display: flex;
    align-items: center;
    border: 1px solid map-get(ecom.$ecom-colors, border);
    border-radius: 0.25rem;
    
    &-button {
      width: 2rem;
      height: 2rem;
      border: none;
      background: none;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      
      &:hover {
        background-color: map-get(ecom.$ecom-colors, background);
      }
    }
    
    &-input {
      width: 3rem;
      text-align: center;
      border: none;
      border-left: 1px solid map-get(ecom.$ecom-colors, border);
      border-right: 1px solid map-get(ecom.$ecom-colors, border);
    }
  }
  
  &__item-remove {
    color: map-get(ecom.$ecom-colors, danger);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.25rem;
    
    &:hover {
      color: darken(map-get(ecom.$ecom-colors, danger), 20%);
    }
  }
  
  &__footer {
    padding: 1rem;
    border-top: 1px solid map-get(ecom.$ecom-colors, border);
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: white;
  }
  
  &__total {
    display: flex;
    justify-content: space-between;
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), lg);
    font-weight: 600;
    margin-bottom: 1rem;
  }
  
  &__checkout-button {
    width: 100%;
    padding: 1rem;
    background-color: map-get(ecom.$ecom-colors, primary);
    color: white;
    border: none;
    border-radius: 0.5rem;
    font-size: map-get(map-get(ecom.$ecom-typography, sizes), lg);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s ease;
    
    &:hover {
      background-color: darken(map-get(ecom.$ecom-colors, primary), 10%);
    }
  }
}

案例三:仪表板界面

仪表板布局

scss
// dashboard/_layout.scss
.dashboard {
  display: grid;
  grid-template-areas: 
    "sidebar header"
    "sidebar main";
  grid-template-rows: 60px 1fr;
  grid-template-columns: 250px 1fr;
  height: 100vh;
  background-color: #f8fafc;
  
  @include respond-below(md) {
    grid-template-areas: 
      "header"
      "main";
    grid-template-columns: 1fr;
    grid-template-rows: 60px 1fr;
  }
  
  &__sidebar {
    grid-area: sidebar;
    background: white;
    border-right: 1px solid #e2e8f0;
    overflow-y: auto;
    
    @include respond-below(md) {
      position: fixed;
      left: -250px;
      top: 60px;
      bottom: 0;
      z-index: 90;
      width: 250px;
      transition: left 0.3s ease;
      
      &--open {
        left: 0;
      }
    }
  }
  
  &__header {
    grid-area: header;
    background: white;
    border-bottom: 1px solid #e2e8f0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1.5rem;
  }
  
  &__main {
    grid-area: main;
    overflow-y: auto;
    padding: 1.5rem;
  }
  
  &__mobile-toggle {
    display: none;
    
    @include respond-below(md) {
      display: block;
    }
  }
}

.sidebar {
  &__logo {
    padding: 1.5rem 1rem;
    border-bottom: 1px solid #e2e8f0;
    
    &-text {
      font-size: 1.25rem;
      font-weight: 700;
      color: #1e293b;
    }
  }
  
  &__nav {
    padding: 1rem 0;
  }
  
  &__nav-item {
    margin-bottom: 0.25rem;
    
    &:last-child {
      margin-bottom: 0;
    }
  }
  
  &__nav-link {
    display: flex;
    align-items: center;
    padding: 0.75rem 1rem;
    color: #64748b;
    text-decoration: none;
    transition: all 0.2s ease;
    
    &:hover {
      background-color: #f1f5f9;
      color: #1e293b;
    }
    
    &--active {
      background-color: #dbeafe;
      color: #1d4ed8;
      border-left: 3px solid #3b82f6;
    }
    
    &-icon {
      margin-right: 0.75rem;
      width: 1.25rem;
      height: 1.25rem;
    }
    
    &-text {
      font-size: 0.875rem;
      font-weight: 500;
    }
  }
}

数据可视化组件

scss
// dashboard/_charts.scss
.widget {
  background: white;
  border-radius: 0.5rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  
  &__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
  }
  
  &__title {
    font-size: 1.125rem;
    font-weight: 600;
    color: #1e293b;
  }
  
  &__subtitle {
    font-size: 0.875rem;
    color: #64748b;
  }
  
  &__chart-container {
    height: 300px;
    position: relative;
  }
  
  &__stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin-top: 1.5rem;
  }
  
  &__stat {
    text-align: center;
    padding: 1rem;
    background: #f8fafc;
    border-radius: 0.5rem;
  }
  
  &__stat-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: #1e293b;
    margin-bottom: 0.25rem;
  }
  
  &__stat-label {
    font-size: 0.875rem;
    color: #64748b;
  }
}

// 图表组件
.chart {
  &__bar {
    fill: #3b82f6;
    
    &:hover {
      fill: #1d4ed8;
    }
  }
  
  &__line {
    stroke: #3b82f6;
    stroke-width: 2;
    fill: none;
  }
  
  &__area {
    fill: url(#gradient);
  }
  
  &__tooltip {
    position: absolute;
    background: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 0.5rem;
    border-radius: 0.25rem;
    font-size: 0.75rem;
    pointer-events: none;
    z-index: 100;
  }
}

通过这些实战案例,我们可以看到Sass在实际项目中的应用方式,包括设计系统建立、组件开发、响应式实现等方面。