【Vue3】SCSS 基础篇

SCSS(Sass)作为前端最主流的CSS预处理器,凭借变量、混合器、嵌套等强大扩展特性,彻底解决了原生CSS可维护性差、复用性低、逻辑冗余等痛点,成为前端开发的必备工具。

🌟**【青柠代码录】--- 青柠来相伴,代码更简单** 🌟

🔥**【全栈】博客合集:** https://www.yuque.com/u12587869/zplytb/ur5ohwqxd2axtiny 🔥

🎯**【Java】面试题:** https://www.yuque.com/u12587869/zplytb/eh7yqzitiab693og 🎯


1. 为何选择SCSS

在前端开发中,原生CSS的局限性(无变量、复用性差、嵌套混乱)导致样式管理成为一大挑战。

SCSS作为CSS的超集,不仅兼容所有CSS语法,还引入了多项实用特性,简化了样式开发与维护工作。

1.1 SCSS的核心优势

  1. 高效复用:通过变量、混合器、继承等特性,可以高效地重复利用样式逻辑。

  2. 提高可读性:嵌套语法符合HTML DOM结构,提升了代码的可读性和可维护性,特别适用于复杂组件的样式设计。

  3. 扩展性强:支持条件判断、循环和自定义函数,满足复杂样式逻辑的需求。

  4. 良好的生态:无缝集成Vue3、Vite、React等主流技术栈,并支持Element Plus、Ant Design Vue等组件库的样式定制。

1.2 SCSS与Vue3 + Vite的完美结合

  • Vite对SCSS的支持 :安装sass依赖后,Vite能自动编译SCSS文件,支持全局变量注入等功能。

  • Vue3与SCSS的协作 :Vue3单文件组件中使用SCSS时,可通过scoped属性实现样式隔离,并支持动态控制样式变化。

  • 协同优势:三者结合,能够实现快速开发、构建优化及热更新,是现代前端项目的理想选择。


2. 环境搭建

Vite对SCSS的原生支持的,无需复杂配置,只需完成"初始化Vue3 + Vite项目→安装SCSS依赖→验证集成"三步,即可快速实现SCSS落地。

2.1 步骤1:初始化Vue3 + Vite项目

打开终端,执行以下命令,初始化标准Vue3 + Vite项目(推荐TypeScript,提升代码可维护性,JavaScript步骤完全一致):

复制代码
# 初始化Vue3 + Vite项目(按需勾选配置,推荐选项如下)
npm create vue@latest vue3-vite-scss-demo
# 进入项目目录
cd vue3-vite-scss-demo
# 安装项目依赖(Vite项目依赖安装速度极快)
npm install

初始化配置建议(勾选选项参考,重点适配SCSS开发):

  • Project name:vue3-vite-scss-demo(自定义,建议包含scss标识,便于区分技术栈)

  • Package name:默认即可,与项目名称一致

  • Add TypeScript?:Yes(项目首选,提升代码健壮性,便于SCSS与逻辑协同)

  • Add JSX Support?:No(非必要不勾选,避免冗余)

  • Add Vue Router?:Yes(单页应用必备,不影响SCSS使用)

  • Add Pinia?:Yes(Vue3官方状态管理,后续可实现SCSS变量与响应式协同)

  • Add Vitest?:No(按需选择,小型项目可暂不勾选)

  • Add ESLint?:Yes(代码规范必备,避免多人协作时SCSS样式混乱)

  • Add Prettier?:Yes(代码格式化,统一SCSS代码风格)

  • Add production-ready starter template?:No(自定义配置更灵活,贴合SCSS工程化需求)

2.2 步骤2:安装SCSS依赖

Vite编译SCSS需依赖sass(即dart-sass,官方推荐),无需安装其他loader,dart-sass比node-sass更稳定、更快,无系统兼容性问题(开发已全面淘汰node-sass),执行以下命令安装开发依赖:

复制代码
# 安装sass(开发依赖,仅开发时使用,生产环境会编译为CSS)
npm install -D sass

2.3 步骤3:验证SCSS集成成功

修改入口组件App.vue,在<style>标签添加lang="scss",书写SCSS核心语法(变量、嵌套、运算),测试是否能正常编译,步骤如下:

复制代码
<template>
  <div class="app">
    <h1 class="app-title">SCSS集成测试()</h1>
    <div class="demo-card">
      <p class="demo-desc">变量、嵌套、运算语法验证</p>
    </div>
  </div>
</template>
​
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('SCSS集成成功!')
</script>
​
<style lang="scss">
// SCSS变量(组件内局部变量,后续讲解全局变量)
$primary-color: #42b983; // 常用主色调(Element Plus同款)
$font-size-base: 14px; // 基础字体大小
$card-padding: 20px; // 卡片内边距
$border-radius: 8px; // 全局圆角
​
// SCSS嵌套语法(贴合HTML结构,减少父选择器重复书写)
.app {
  width: 100%;
  min-height: 100vh;
  padding: 40px;
  box-sizing: border-box;
  background-color: #f8f9fa;
​
  // 嵌套子选择器
  .app-title {
    color: $primary-color;
    font-size: $font-size-base * 1.6; // SCSS运算(动态计算)
    font-weight: 600;
    margin-bottom: 30px;
  }
​
  // 嵌套卡片样式
  .demo-card {
    background-color: #fff;
    padding: $card-padding;
    border-radius: $border-radius;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
​
    .demo-desc {
      color: #666;
      font-size: $font-size-base;
      line-height: 1.5;
    }
  }
}
</style>

执行启动命令,验证效果:

复制代码
# 启动开发服务器(Vite热更新开启,修改SCSS无需重启)
npm run dev

访问终端输出的地址(默认http://localhost:5173),若满足以下条件,说明SCSS集成成功:

  • 标题颜色为$primary-color定义的绿色(#42b983)

  • 卡片有圆角、阴影,内边距符合$card-padding定义

  • 标题字体大小为14px * 1.6 = 22.4px(SCSS运算生效)


3. SCSS核心语法

SCSS完全兼容原生CSS,开发中无需放弃原有CSS知识,重点掌握「变量、嵌套、混合器、继承、内置函数」五大核心特性,即可大幅提升样式开发效率。

3.1 变量(Variables)

SCSS变量使用$开头,用于存储颜色、字体、间距、尺寸等样式常量,支持全局与局部作用域,是开发中"样式统一、可维护"的关键,也是多人协作避免样式混乱的核心。

3.1.1 变量的定义与使用(基础实战)

开发中,变量通常用于统一设计规范(品牌色、字体、间距),示例:Vue3组件中用变量统一按钮样式,后续修改只需调整变量,无需逐个修改组件:

复制代码
<template>
  <div class="button-container">
    <button class="primary-btn">主要按钮</button>
    <button class="secondary-btn">次要按钮</button>
    <button class="disabled-btn">禁用按钮</button>
  </div>
</template>
​
<script setup lang="ts">
const isDisabled = ref(true)
</script>
​
<style lang="scss">
// 组件内局部变量(仅当前组件生效)
$primary-btn-color: #42b983; // 品牌主色
$secondary-btn-color: #64748b; // 次要色
$disabled-btn-color: #c0ccda; // 禁用色
$btn-padding: 8px 16px; // 统一内边距
$btn-border-radius: 4px; // 统一圆角
$btn-hover-opacity: 0.9; // 统一交互效果
​
// 主要按钮样式(复用变量)
.primary-btn {
  background-color: $primary-btn-color;
  color: #fff;
  padding: $btn-padding;
  border-radius: $btn-border-radius;
  border: none;
  cursor: pointer;
  transition: opacity 0.2s;
​
  &:hover {
    opacity: $btn-hover-opacity;
  }
}
​
// 次要按钮样式(复用变量,减少冗余)
.secondary-btn {
  background-color: $secondary-btn-color;
  color: #fff;
  padding: $btn-padding;
  border-radius: $btn-border-radius;
  border: none;
  cursor: pointer;
  margin: 0 10px;
  transition: opacity 0.2s;
​
  &:hover {
    opacity: $btn-hover-opacity;
  }
}
​
// 禁用按钮样式(复用变量)
.disabled-btn {
  background-color: $disabled-btn-color;
  color: #fff;
  padding: $btn-padding;
  border-radius: $btn-border-radius;
  border: none;
  cursor: not-allowed;
  opacity: 0.7;
}
</style>

应用场景:项目中所有按钮、卡片、表单的样式,均通过变量统一管理,后续若需修改品牌色、圆角大小,只需调整对应变量,无需逐个修改组件,维护成本大幅降低。

3.1.2 变量的作用域(避免样式污染)

SCSS变量分为「局部变量」和「全局变量」,开发中需严格区分,避免样式污染,核心规则如下:

  • 局部变量:定义在选择器、混合器、函数内部,仅当前作用域生效,适合组件内专属样式,不影响外部。

  • 全局变量:定义在所有选择器外部,或使用!global关键字声明,可在整个项目的SCSS文件、组件中生效,适合全局设计规范(品牌色、基础字体)。

示例:全局变量与局部变量的区别:

复制代码
// 全局变量(组件样式最外层,当前组件所有选择器可访问)
$global-color: #333; // 全局文本色
$global-padding: 20px; // 全局基础内边距
​
.app {
  // 局部变量(仅.app内部生效,外部无法访问)
  $local-bg-color: #f5f5f5;
  background-color: $local-bg-color;
  padding: $global-padding; // 复用全局变量
​
  .app-title {
    color: $global-color; // 访问全局变量
  }
​
  .app-content {
    // 嵌套作用域局部变量(仅.app-content内部生效)
    $content-color: #666;
    color: $content-color;
    padding: $global-padding / 2; // SCSS运算
  }
}
​
// 外部选择器(与.app同级)
.other-container {
  color: $global-color; // 可访问全局变量
  // background-color: $local-bg-color; // 报错:局部变量无法访问
}
​
// 慎用!global:将局部变量强制转为全局(易污染,开发尽量避免)
.box {
  $box-color: #999 !global;
  color: $box-color;
}
​
.another-box {
  color: $box-color; // 可访问(已转为全局)
}

SCSS开发规范:避免使用!global声明全局变量,建议将全局变量集中管理在单独的SCSS文件中(后续4.1节讲解),通过Vite全局注入,既保证全局可用,又避免样式污染。

3.1.3 变量默认值(组件封装必备)

使用!default关键字为变量设置默认值,当变量未被定义时使用默认值;若已定义,则不覆盖原有值,这是SCSS组件封装的核心技巧,允许使用者自定义样式,同时保留默认样式。

复制代码
<template>
  <div class="custom-card">
    <slot>默认卡片内容</slot>
  </div>
</template>
​
<style lang="scss">
// 变量默认值(!default关键字)
$card-bg-color: #fff !default; // 默认背景色
$card-border-radius: 8px !default; // 默认圆角
$card-padding: 20px !default; // 默认内边距
​
.custom-card {
  background-color: $card-bg-color;
  border-radius: $card-border-radius;
  padding: $card-padding;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
</style>

应用场景:封装通用卡片组件时,通过!default定义变量,其他页面使用该组件时,可重新定义变量覆盖默认样式,无需修改组件源码,实现组件的灵活性与复用性。

3.2 嵌套(Nesting):贴合结构,减少冗余

嵌套语法是SCSS最常用的特性,核心优势是「贴合HTML DOM结构」,无需重复书写父选择器,让样式代码更简洁、可读性更强,尤其适合复杂组件(表单、弹窗)的样式开发,同时避免选择器冲突。

3.2.1 基础嵌套(父子选择器)

SCSS允许在父选择器内部嵌套子选择器,子选择器自动继承父选择器作用域,相当于原生CSS的"父选择器+子选择器",示例(Vue3表单组件样式):

复制代码
<template>
  <form class="login-form">
    <div class="form-item">
      <label class="form-label">用户名</label>
      <input type="text" class="form-input" placeholder="请输入用户名">
    </div>
    <div class="form-item">
      <label class="form-label">密码</label>
      <input type="password" class="form-input" placeholder="请输入密码">
    </div>
    <button class="form-btn" type="submit">登录</button>
  </form>
</template>
​
<script setup lang="ts">
import { ref } from 'vue'
const username = ref('')
const password = ref('')
const handleSubmit = (e: Event) => {
  e.preventDefault()
  console.log('提交表单:', username.value, password.value)
}
</script>
​
<style lang="scss">
// 父选择器:表单容器
.login-form {
  width: 350px;
  margin: 50px auto;
  padding: 30px;
  background-color: #fff;
  border-radius: $border-radius;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
​
  // 嵌套子选择器:表单项(.login-form .form-item)
  .form-item {
    margin-bottom: 20px;
    position: relative;
​
    // 嵌套孙选择器:表单标签(.login-form .form-item .form-label)
    .form-label {
      display: block;
      margin-bottom: 8px;
      color: #333;
      font-size: $font-size-base;
      font-weight: 500;
    }
​
    // 嵌套孙选择器:表单输入框
    .form-input {
      width: 100%;
      height: 40px;
      padding: 0 12px;
      border: 1px solid #e5e6eb;
      border-radius: 4px;
      font-size: $font-size-base;
      box-sizing: border-box;
​
      // 伪类嵌套(&表示父选择器本身)
      &:focus {
        outline: none;
        border-color: $primary-color;
        box-shadow: 0 0 0 2px rgba(66, 185, 131, 0.2);
      }
​
      &:disabled {
        background-color: #f5f5f5;
        cursor: not-allowed;
        border-color: #c0ccda;
      }
    }
  }
​
  // 嵌套子选择器:登录按钮
  .form-btn {
    width: 100%;
    height: 44px;
    background-color: $primary-color;
    color: #fff;
    border: none;
    border-radius: 4px;
    font-size: $font-size-base;
    cursor: pointer;
    transition: background-color 0.2s;
​
    &:hover {
      background-color: darken($primary-color, 10%); // SCSS内置函数
    }
​
    &:disabled {
      background-color: #a0e5c8;
      cursor: not-allowed;
    }
  }
}
</style>

SCSS开发重点:嵌套层级不可超过3层,否则会导致编译后的CSS选择器过长,影响性能,同时降低可读性。可通过BEM命名规范减少嵌套层级,避免过度嵌套。

3.2.2 特殊嵌套:&符号的使用(必备技巧)

在SCSS嵌套中,&符号代表「父选择器本身」,主要用于伪类、伪元素、相邻选择器等场景,避免重复书写父选择器,是开发中SCSS嵌套的核心技巧:

复制代码
// 示例1:伪类嵌套(最常用)
.btn {
  background-color: $primary-color;
  color: #fff;
  // &代表.btn
  &:hover { background-color: darken($primary-color, 8%); }
  &:active { background-color: darken($primary-color, 15%); }
  &:disabled { background-color: #c0ccda; cursor: not-allowed; }
}

// 示例2:伪元素嵌套
.card {
  position: relative;
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 4px;
    background-color: $primary-color;
  }
  &::after {
    content: '';
    position: absolute;
    bottom: 0;
    right: 0;
    width: 40px;
    height: 40px;
    background: url('@/assets/icon.png') no-repeat center;
  }
}

// 示例3:组件样式批量生成(组件封装常用)
.btn {
  // 基础样式
  &-primary { @include btn-style($primary-color); }
  &-secondary { @include btn-style($secondary-color); }
  &-danger { @include btn-style($danger-color); }
}
// 编译后生成:.btn-primary、.btn-secondary、.btn-danger

应用场景:封装通用按钮、卡片组件时,使用&-xxx语法可快速生成不同类型的组件样式,无需重复书写基础样式,提升组件封装效率。

3.3 混合器(Mixin):复杂样式逻辑复用核心

混合器(@mixin)相当于CSS中的"函数",用于封装一段可复用的复杂样式逻辑,支持传递参数、设置默认值,是开发中重复样式复用的核心,适用于圆角、阴影、弹性布局等常用复杂样式。

3.3.1 无参数Mixin(简单样式复用)

无参数Mixin用于封装固定样式逻辑,可直接引用,示例(封装卡片基础样式):

复制代码
<template>
  <div class="card-container">
    <div class="card card1">卡片1(基础样式)</div>
    <div class="card card2">卡片2(基础样式+额外样式)</div>
  </div>
</template>
​
<style lang="scss">
// 定义无参数Mixin(@mixin关键字)
@mixin card-base {
  background-color: #fff;
  border-radius: $border-radius;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  box-sizing: border-box;
  transition: box-shadow 0.2s;
​
  &:hover {
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  }
}
​
// 引用Mixin(@include关键字)
.card-container {
  display: flex;
  gap: 20px;
  padding: 20px;
}
​
.card {
  width: 200px;
  @include card-base; // 引用卡片基础样式
​
  // 额外样式补充
  &.card1 { border-left: 4px solid $primary-color; }
  &.card2 { border-left: 4px solid #1890ff; }
}
</style>

应用场景:项目中所有卡片组件(列表卡片、详情卡片)均引用card-base混合器,统一基础样式,再添加个性化样式,实现"基础复用、灵活扩展"。

3.3.2 带参数Mixin(灵活复用)

带参数Mixin允许传递参数、设置默认值,适配不同场景,是开发中SCSS混合器的高频用法,示例(封装弹性布局、圆角、阴影等常用混合器):

复制代码
// 1. 弹性布局混合器(适配不同布局场景)
@mixin flex-layout($justify: center, $align: center, $direction: row, $gap: 0) {
  display: flex;
  justify-content: $justify;
  align-items: $align;
  flex-direction: $direction;
  gap: $gap;
}

// 2. 圆角混合器(可自定义圆角大小)
@mixin border-radius($radius: $border-radius) {
  border-radius: $radius;
  -webkit-border-radius: $radius; // 兼容旧浏览器
}

// 3. 阴影混合器(可自定义阴影深度)
@mixin box-shadow($depth: 1) {
  @if $depth == 1 { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
  @else if $depth == 2 { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); }
  @else if $depth == 3 { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16); }
}

// 引用带参数Mixin(传递不同参数,实现不同样式)
.header {
  @include flex-layout($justify: space-between, $align: center, $gap: 16px);
  padding: 0 20px;
  height: 60px;
  @include border-radius(0); // 取消圆角
  @include box-shadow(1);
}

.footer {
  @include flex-layout($justify: center, $align: center, $direction: column, $gap: 8px);
  padding: 20px;
  @include border-radius(8px);
  @include box-shadow(0); // 无阴影
}

SCSS开发重点:带参数Mixin的核心价值是"一次封装,多场景复用",例如flex-layout混合器可适配头部、底部、卡片等不同组件的布局需求,无需重复书写flex相关样式,降低维护成本。

3.4 继承(Extend):简单样式规则复用

继承(@extend)用于复用某个选择器的全部样式规则,与Mixin的区别在于:Mixin是"复制样式代码",继承是"合并选择器",可减少编译后的CSS冗余,适合复用简单样式规则(文本样式、基础状态)。

示例(Vue3组件中使用继承,复用文本样式):

复制代码
<template>
  <div class="text-container">
    <p class="text-primary">主要文本(加粗、主色调)</p>
    <p class="text-secondary">次要文本(常规、灰色)</p>
    <p class="text-primary text-large">主要大文本(加粗、主色调、大字体)</p>
  </div>
</template>

<style lang="scss">
// 基础文本样式(被继承的样式)
.text-base {
  font-size: $font-size-base;
  line-height: 1.5;
  margin: 8px 0;
}

// 继承基础文本样式,并添加额外样式
.text-primary {
  @extend .text-base; // 继承.text-base所有样式
  color: $primary-color;
  font-weight: 600;
}

.text-secondary {
  @extend .text-base; // 继承.text-base所有样式
  color: #666;
  font-weight: 400;
}

// 继承+额外样式(叠加效果)
.text-large {
  font-size: $font-size-base * 1.2;
}
</style>

SCSS开发注意事项:继承仅适用于简单样式复用,复杂样式逻辑(带参数、多层嵌套)建议使用Mixin;避免继承嵌套选择器,防止样式污染;多个选择器复用同一简单样式时,继承比Mixin更节省CSS体积。

3.5 SCSS内置函数(实用工具)

SCSS内置大量实用函数,用于颜色处理、数学运算等,开发中高频使用的函数如下:

3.5.1 颜色处理函数(最常用)

复制代码
// 1. darken($color, $percentage):加深颜色(百分比0-100%)
$primary-color: #42b983;
$primary-dark: darken($primary-color, 10%); // #359469
$primary-darker: darken($primary-color, 20%); // #286e4d

// 2. lighten($color, $percentage):变浅颜色
$primary-light: lighten($primary-color, 10%); // #5fc39c

// 3. rgba($color, $alpha):设置透明度(alpha 0-1)
$primary-opacity-50: rgba($primary-color, 0.5); // 半透明主色调

// 4. mix($color1, $color2, $percentage):混合两种颜色
$mix-color: mix($primary-color, #fff, 30%); // 30%主色+70%白色

// 应用示例(按钮交互样式)
.btn {
  background-color: $primary-color;
  &:hover { background-color: $primary-dark; } // 加深颜色,提升交互反馈
}

3.5.2 数学运算函数(响应式适配)

复制代码
// 1. 基础运算(+、-、*、/),自动处理单位
$container-width: 1200px;
$sidebar-width: 240px;
$content-width: $container-width - $sidebar-width; // 960px
​
$font-size-base: 14px;
$font-size-large: $font-size-base * 1.2; // 16.8px
​
// 2. 内置数学函数
$max-width: max(1200px, 100vw); // 取最大值(适配移动端)
$round-size: round(16.8px); // 四舍五入(17px)
​
// 响应式布局应用
.container {
  width: $max-width;
  margin: 0 auto;
}
​
.content {
  width: $content-width;
  padding: $font-size-base * 1.5; // 动态计算内边距
}

应用场景:响应式布局中,通过数学运算函数动态计算尺寸;颜色处理函数用于生成hover、active等交互状态的颜色,保持颜色统一性。


4. SCSS工程化配置(模块化、全局注入)

项目中,SCSS的使用需实现「全局资源共享、模块化管理、样式规范统一」,核心是SCSS文件模块化拆分与Vite全局注入配置,解决多人协作中的样式混乱、重复引入等问题,提升开发效率。

4.1 第一步:SCSS模块化拆分

将SCSS资源按功能拆分,集中管理,避免样式混乱,推荐目录结构:

复制代码
src/
├── styles/                # SCSS全局样式目录(核心)
│   ├── _variables.scss    # 全局变量(颜色、字体、间距等)
│   ├── _mixins.scss       # 全局混合器(布局、圆角、阴影等)
│   ├── _extends.scss      # 全局继承样式(基础文本、按钮等)
│   ├── _functions.scss    # 全局自定义函数(按需扩展)
│   └── main.scss          # 全局样式入口(引入所有模块化文件)
├── components/            # 组件目录(组件内SCSS样式)
├── views/                 # 页面目录(页面内SCSS样式)
└── App.vue                # 入口组件

目录说明(SCSS核心)

  • _variables.scss:存储全局变量,是样式规范的核心,所有组件、页面均使用这里的变量,确保样式统一。

  • _mixins.scss:存储全局混合器,封装项目中常用的复杂样式逻辑,供所有组件、页面引用。

  • _extends.scss:存储全局继承样式,封装简单基础样式,减少重复代码。

  • _functions.scss:自定义SCSS函数,按需扩展SCSS功能。

  • main.scss:全局样式入口,引入所有模块化SCSS文件,同时书写全局公共样式(重置样式、body样式)。

SCSS模块化注意 :模块化文件建议以开头(如variables.scss),表示"局部文件",不会被单独编译为CSS,需通过@import引入后生效,避免生成冗余CSS。

4.1.1 模块化文件实战示例

示例1:_variables.scss(全局变量,SCSS规范核心)

复制代码
// 一、品牌色(设计规范统一)
$primary-color: #42b983; // 主色调
$primary-dark: darken($primary-color, 10%); // 主色调加深
$primary-light: lighten($primary-color, 10%); // 主色调变浅
$secondary-color: #64748b; // 次要色调
$danger-color: #f56c6c; // 危险色
$success-color: #67c23a; // 成功色
$text-color: #333; // 主要文本色
$bg-color: #f8f9fa; // 页面背景色
$border-color: #e5e6eb; // 边框色

// 二、尺寸规范
$border-radius: 8px; // 全局圆角
$border-radius-sm: 4px; // 小圆角
$shadow-depth-1: 0 2px 8px rgba(0, 0, 0, 0.08); // 浅阴影

// 三、间距规范(统一间距,避免混乱)
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 24px;

// 四、字体规范
$font-size-base: 14px; // 基础字体大小
$font-weight-medium: 500; // 中等加粗

// 五、组件尺寸规范
$btn-height-base: 40px; // 基础按钮高度
$card-padding-base: 20px; // 基础卡片内边距

示例2:_mixins.scss(全局混合器,常用)

复制代码
// 引入全局变量(混合器中需使用变量)
@import './_variables.scss';
​
// 1. 弹性布局混合器
@mixin flex-layout($justify: center, $align: center, $direction: row, $gap: 0) {
  display: flex;
  justify-content: $justify;
  align-items: $align;
  flex-direction: $direction;
  gap: $gap;
  flex-wrap: wrap; // 默认换行,适配响应式
}
​
// 2. 圆角混合器
@mixin border-radius($radius: $border-radius) {
  border-radius: $radius;
  -webkit-border-radius: $radius;
}
​
// 3. 按钮样式混合器(核心混合器)
@mixin btn-style($color: $primary-color, $height: $btn-height-base) {
  height: $height;
  padding: $spacing-sm $spacing-md;
  font-size: $font-size-base;
  border: none;
  color: #fff;
  background-color: $color;
  @include border-radius($border-radius-sm);
  cursor: pointer;
  transition: background-color 0.2s;
​
  &:hover {
    background-color: darken($color, 8%);
  }
​
  &:disabled {
    background-color: lighten($color, 30%);
    cursor: not-allowed;
  }
}
​
// 4. 卡片基础混合器
@mixin card-base($padding: $card-padding-base) {
  background-color: #fff;
  padding: $padding;
  @include border-radius;
  @include box-shadow(1);
  box-sizing: border-box;
}
​
// 5. 响应式混合器(适配多端)
@mixin responsive($breakpoint) {
  @if $breakpoint == 'mobile' {
    @media (max-width: 767px) { @content; }
  } @else if $breakpoint == 'pc' {
    @media (min-width: 1200px) { @content; }
  }
}

示例3:main.scss(全局样式入口)

复制代码
// 引入所有模块化SCSS文件
@import './_variables.scss';
@import './_mixins.scss';
@import './_extends.scss';
​
// 全局重置样式(项目必备)
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
​
// 全局body样式(复用SCSS变量)
body {
  font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
  font-size: $font-size-base;
  color: $text-color;
  background-color: $bg-color;
  line-height: 1.5;
}
​
// 全局链接样式
a {
  text-decoration: none;
  color: $primary-color;
  &:hover { color: $primary-dark; }
}

4.2 第二步:Vite配置SCSS全局注入

模块化拆分后,若每个组件都手动@import全局变量、混合器,会非常繁琐且易遗漏。Vite提供全局资源注入配置,可将全局SCSS文件自动注入所有Vue组件的SCSS样式中,无需手动引入。

4.2.1 Vite配置步骤(vite.config.ts)

在项目根目录的vite.config.ts中添加以下配置(无则新建),重点配置SCSS全局注入:

复制代码
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
​
export default defineConfig({
  plugins: [vue()],
  // SCSS 全局注入配置(核心)
  css: {
    preprocessorOptions: {
      scss: {
        // 自动注入全局变量和混合器,无需手动 @import
        additionalData: `
          @import "@/styles/_variables.scss";
          @import "@/styles/_mixins.scss";
        `,
      },
    },
  },
  // 路径别名配置(可选,简化 SCSS 文件引入路径)
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'), // 配置 @ 为 src 目录别名
    },
  },
});

配置重点说明

  • additionalData :用于注入全局SCSS资源,这里注入了variables.scss和mixins.scss,后续所有Vue组件的<style lang="scss">中,可直接使用全局变量和混合器,无需手动@import。注意末尾的分号和换行,避免编译报错。

  • 路径别名 :配置@为src目录别名,SCSS文件中可通过@import "@/styles/*variables.scss"引入,无需书写相对路径(如../styles/*variables.scss),减少路径错误。

  • 配置生效:修改vite.config.ts后,需重启Vite服务(npm run dev),配置才能生效,否则全局注入不生效。

4.2.2 全局注入验证

配置完成后,新建一个Vue组件(如TestGlobal.vue),无需@import全局变量和混合器,直接使用,验证全局注入是否成功:

复制代码
<template>
  <div class="test-global">
    <button class="test-btn">全局混合器测试</button>
    <div class="test-card">全局变量测试</div>
  </div>
</template>
​
<style lang="scss">
// 直接使用全局变量(无需@import _variables.scss)
.test-global {
  padding: $spacing-lg; // 全局间距变量
  background-color: $bg-color; // 全局背景色变量
}
​
// 直接使用全局混合器(无需@import _mixins.scss)
.test-btn {
  @include btn-style($primary-color); // 全局按钮混合器
  margin-bottom: $spacing-md;
}
​
.test-card {
  @include card-base; // 全局卡片混合器
  border-left: 4px solid $primary-color;
}
</style>

启动服务后,若组件正常渲染,按钮和卡片样式符合全局配置,说明SCSS全局注入成功,后续开发可直接复用全局资源,大幅提升开发效率。

4.3 第三步:SCSS工程化规范

项目中,多人协作开发SCSS时,需遵循统一规范,避免样式混乱、代码冗余,以下是常用的SCSS工程化规范:

  • 命名规范:采用BEM命名规范(Block-Element-Modifier),避免选择器嵌套过深,例如.btn(Block)、.btn__icon(Element)、.btn--primary(Modifier),配合SCSS嵌套使用,兼顾可读性与可维护性。

  • 变量规范:全局变量统一放在_variables.scss中,按"功能分类"(品牌色、尺寸、间距等)整理,变量名采用"+功能+描述"格式(如primary-color、spacing-md),避免无意义变量名(如color1、$size2)。

  • 混合器规范:复杂样式逻辑(3行以上可复用样式)才封装为混合器,混合器名采用"功能+style"格式(如btn-style、flex-layout),带参数混合器需设置合理默认值,适配多场景复用。

  • 嵌套规范:嵌套层级不超过3层,避免编译后CSS选择器过长;伪类、伪元素、相邻选择器使用&符号,提升代码简洁度。

  • 注释规范 :模块化文件(*variables.scss、*mixins.scss)添加分类注释;复杂样式、特殊逻辑添加单行注释,说明用途,便于多人协作理解。


5. SCSS实战:开发可复用通用组件

结合前文讲解的SCSS核心语法与工程化配置,本节实战开发3个通用组件(按钮、卡片、表单)。

5.1 实战1:通用按钮组件(Button)

按钮是项目中最常用的组件,通过SCSS混合器、变量封装,实现多类型、可自定义的通用按钮,支持主要、次要、危险、禁用等状态,适配不同场景。

复制代码
<template>
  <button 
    class="btn"
    :class="{ 
      'btn--primary': type === 'primary',
      'btn--secondary': type === 'secondary',
      'btn--danger': type === 'danger',
      'btn--disabled': disabled
    }"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot>按钮</slot>
  </button>
</template>
​
<script setup lang="ts">
import { defineProps, emit } from 'vue';
​
// 组件props(支持自定义配置)
const props = defineProps({
  type: {
    type: String,
    default: 'primary', // 默认主要按钮
    validator: (value: string) => ['primary', 'secondary', 'danger'].includes(value)
  },
  disabled: {
    type: Boolean,
    default: false
  },
  size: {
    type: String,
    default: 'base',
    validator: (value: string) => ['small', 'base', 'large'].includes(value)
  }
});
​
const emit = emit('click');
const handleClick = () => {
  if (!props.disabled) {
    emit('click');
  }
};
</script>
​
<style lang="scss">
// 基础按钮样式(复用全局混合器,自定义参数)
.btn {
  @include btn-style($primary-color, $btn-height-base);
  padding: $spacing-sm $spacing-md;
  font-size: $font-size-base;
​
  // 尺寸适配(通过SCSS条件判断)
  @if $size == 'small' {
    height: $btn-height-base - 8px;
    padding: $spacing-xs $spacing-sm;
    font-size: $font-size-base - 2px;
  } @else if $size == 'large' {
    height: $btn-height-base + 8px;
    padding: $spacing-md $spacing-lg;
    font-size: $font-size-base + 2px;
  }
​
  // 不同类型按钮样式(复用全局变量)
  &--primary { background-color: $primary-color; }
  &--secondary { background-color: $secondary-color; }
  &--danger { background-color: $danger-color; }
​
  // 禁用状态(覆盖混合器默认禁用样式)
  &--disabled {
    background-color: $border-color;
    color: #999;
    cursor: not-allowed;
    &:hover { background-color: $border-color; }
  }
}
</style>

组件优势:通过全局混合器btn-style复用基础样式,结合props实现类型、尺寸、禁用状态的自定义,无需重复书写样式;全局变量修改后,按钮样式自动同步,维护成本极低,符合组件封装规范。

5.2 实战2:通用卡片组件(Card)

卡片组件用于展示内容,通过SCSS变量、混合器封装,支持自定义标题、边框、阴影、内边距,适配列表、详情等多种场景,兼顾美观与复用性。

复制代码
<template>
  <div class="card" :class="{ 'card--border': border, 'card--no-shadow': noShadow }">
    <div class="card__header" v-if="title">
      <h3 class="card__title">{{ title }}</h3>
    </div>
    <div class="card__body">
      <slot>卡片内容</slot>
    </div>
  </div>
</template>
​
<script setup lang="ts">
import { defineProps } from 'vue';
​
const props = defineProps({
  title: { type: String, default: '' }, // 卡片标题
  border: { type: Boolean, default: false }, // 是否显示边框
  noShadow: { type: Boolean, default: false }, // 是否取消阴影
  padding: { type: String, default: $card-padding-base } // 自定义内边距(SCSS变量默认值)
});
</script>
​
<style lang="scss">
// 基础卡片样式(复用全局混合器)
.card {
  @include card-base($padding); // 复用全局卡片混合器,支持自定义内边距
  margin-bottom: $spacing-md;
​
  // 卡片头部
  &__header {
    margin-bottom: $spacing-sm;
    padding-bottom: $spacing-sm;
    border-bottom: 1px solid $border-color;
  }
​
  // 卡片标题
  &__title {
    font-size: $font-size-base + 2px;
    color: $text-color;
    font-weight: $font-weight-medium;
    margin: 0;
  }
​
  // 卡片内容
  &__body {
    color: #666;
    line-height: 1.6;
  }
​
  // 边框样式(自定义状态)
  &--border {
    border: 1px solid $border-color;
  }
​
  // 取消阴影(自定义状态)
  &--no-shadow {
    box-shadow: none;
  }
}
</style>

应用场景:列表页卡片、详情页卡片、数据统计卡片等,通过props自定义配置,无需重复开发,同时保持样式统一,符合设计规范。

5.3 实战3:通用表单组件(FormItem)

表单是项目中核心组件,封装FormItem组件,结合SCSS嵌套、变量,实现表单标签、输入框、提示信息的统一样式,支持必填、禁用、错误提示等状态。

复制代码
<template>
  <div class="form-item">
    <label class="form-item__label" :class="{ 'form-item__label--required': required }">
      {{ label }}
      <span class="required-mark" v-if="required">*</span>
    </label>
    <div class="form-item__content"&gt;
      &lt;slot&gt;<!-- 插槽:输入框、下拉框等表单元素 --></slot>
      <p class="form-item__error" v-if="error">{{ error }}</p>
    </div>
  </div>
</template>
​
<script setup lang="ts">
import { defineProps } from 'vue';
​
const props = defineProps({
  label: { type: String, required: true }, // 表单标签
  required: { type: Boolean, default: false }, // 是否必填
  error: { type: String, default: '' }, // 错误提示
  disabled: { type: Boolean, default: false } // 是否禁用
});
</script>
​
<style lang="scss">
// 表单项基础样式(SCSS嵌套)
.form-item {
  margin-bottom: $spacing-md;
  position: relative;
​
  // 表单标签
  &__label {
    display: block;
    margin-bottom: $spacing-xs;
    color: $text-color;
    font-size: $font-size-base;
    font-weight: 500;
​
    // 必填标记
    .required-mark {
      color: $danger-color;
      margin-left: 2px;
    }
​
    // 禁用状态标签
    &--required {
      font-weight: 600;
    }
  }
​
  // 表单内容容器
  &__content {
    position: relative;
​
    // 错误提示
    &__error {
      position: absolute;
      bottom: -18px;
      left: 0;
      color: $danger-color;
      font-size: $font-size-base - 2px;
      margin: 0;
      line-height: 1.4;
    }
  }
​
  // 禁用状态(适配插槽内的表单元素)
  &:has(input:disabled),
  &:has(select:disabled) {
    .form-item__label {
      color: #999;
    }
  }
}
</style>

组件优势:通过SCSS嵌套贴合表单结构,复用全局变量统一样式,支持必填、错误提示等常用状态,插槽设计适配输入框、下拉框等多种表单元素,灵活性高,可直接复用在登录、注册、表单提交等场景。

相关推荐
为美好的生活献上中指2 小时前
*Java 沉淀重走长征路*之——《Java Web 应用开发完全指南:从零到企业实战(两万字深度解析)》
java·开发语言·前端·html·javaweb·js
阳火锅2 小时前
AI时代的到来,我想打造这样一款产品。
前端·javascript·vue.js
llxxyy卢2 小时前
polar-web题目
开发语言·前端·javascript
OpenTiny社区2 小时前
不仅是修复 Bug:TinyVue 3.29.0 把“无障碍信息”写进了组件的 DNA 里
前端·javascript·vue.js
鹿鹿鹿鹿isNotDefined2 小时前
Pixelium Design 更新:首版表格上线,完善表单、导航、反馈及视觉组件
前端·javascript
Pu_Nine_92 小时前
企业级 Axios 配置实战:从基础到完整封装
前端·ajax·axios·网络请求·企业级
低调小一2 小时前
OpenClaw 模型配置与火山 Coding Plan 支持清单(实践笔记)
java·前端·笔记·openclaw
毛骗导演2 小时前
万字解析 OpenClaw 源码架构-消息渠道集成简介
前端·架构
kyriewen2 小时前
别再直接 git push 了!这个"魔法"参数让你的代码质量翻倍
前端·git·命令行