本章概述

本章将深入学习如何自定义 Bootstrap,包括 Sass 变量定制、自定义主题创建、组件样式修改等高级技术。通过本章学习,你将能够创建独特的设计风格,满足项目的特定需求。

学习目标

  • 掌握 Bootstrap Sass 变量系统
  • 学会创建自定义主题
  • 了解组件样式定制方法
  • 掌握颜色系统和排版定制
  • 学习构建工具集成

Sass 变量定制

1. Bootstrap Sass 变量系统

// _custom-variables.scss
// Bootstrap 核心变量定制

// 颜色系统定制
$primary: #6f42c1;        // 主色调
$secondary: #6c757d;      // 次要色
$success: #198754;        // 成功色
$info: #0dcaf0;          // 信息色
$warning: #ffc107;        // 警告色
$danger: #dc3545;         // 危险色
$light: #f8f9fa;         // 浅色
$dark: #212529;          // 深色

// 灰度色系
$white: #fff;
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
$gray-400: #ced4da;
$gray-500: #adb5bd;
$gray-600: #6c757d;
$gray-700: #495057;
$gray-800: #343a40;
$gray-900: #212529;
$black: #000;

// 字体系统
$font-family-sans-serif: "Helvetica Neue", Arial, "Noto Sans", sans-serif;
$font-family-monospace: "SF Mono", Monaco, Inconsolata, "Roboto Mono", monospace;
$font-family-base: $font-family-sans-serif;

// 字体大小
$font-size-root: 16px;
$font-size-base: 1rem;
$font-size-sm: $font-size-base * 0.875;
$font-size-lg: $font-size-base * 1.25;

// 字重
$font-weight-lighter: lighter;
$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-semibold: 600;
$font-weight-bold: 700;
$font-weight-bolder: bolder;

// 行高
$line-height-base: 1.5;
$line-height-sm: 1.25;
$line-height-lg: 2;

// 标题字体大小
$h1-font-size: $font-size-base * 2.5;
$h2-font-size: $font-size-base * 2;
$h3-font-size: $font-size-base * 1.75;
$h4-font-size: $font-size-base * 1.5;
$h5-font-size: $font-size-base * 1.25;
$h6-font-size: $font-size-base;

// 间距系统
$spacer: 1rem;
$spacers: (
  0: 0,
  1: $spacer * 0.25,
  2: $spacer * 0.5,
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
  6: $spacer * 4,
  7: $spacer * 5
);

// 边框
$border-width: 1px;
$border-style: solid;
$border-color: $gray-300;
$border-radius: 0.375rem;
$border-radius-sm: 0.25rem;
$border-radius-lg: 0.5rem;
$border-radius-xl: 1rem;
$border-radius-2xl: 2rem;
$border-radius-pill: 50rem;

// 阴影
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15);
$box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075);
$box-shadow-lg: 0 1rem 3rem rgba($black, 0.175);
$box-shadow-inset: inset 0 1px 2px rgba($black, 0.075);

// 组件特定变量
// 按钮
$btn-padding-y: 0.375rem;
$btn-padding-x: 0.75rem;
$btn-font-family: null;
$btn-font-size: $font-size-base;
$btn-line-height: $line-height-base;
$btn-white-space: null;
$btn-padding-y-sm: 0.25rem;
$btn-padding-x-sm: 0.5rem;
$btn-font-size-sm: $font-size-sm;
$btn-padding-y-lg: 0.5rem;
$btn-padding-x-lg: 1rem;
$btn-font-size-lg: $font-size-lg;
$btn-border-width: $border-width;
$btn-font-weight: $font-weight-normal;
$btn-box-shadow: inset 0 1px 0 rgba($white, 0.15), 0 1px 1px rgba($black, 0.075);
$btn-focus-width: 0.25rem;
$btn-focus-box-shadow: 0 0 0 $btn-focus-width rgba(mix($primary, $white, 15%), 0.5);
$btn-disabled-opacity: 0.65;
$btn-active-box-shadow: inset 0 3px 5px rgba($black, 0.125);
$btn-border-radius: $border-radius;
$btn-border-radius-sm: $border-radius-sm;
$btn-border-radius-lg: $border-radius-lg;
$btn-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;

// 卡片
$card-spacer-y: $spacer;
$card-spacer-x: $spacer;
$card-title-spacer-y: $spacer * 0.5;
$card-title-color: null;
$card-subtitle-color: $gray-600;
$card-border-width: $border-width;
$card-border-color: rgba($black, 0.125);
$card-border-radius: $border-radius;
$card-box-shadow: null;
$card-inner-border-radius: subtract($card-border-radius, $card-border-width);
$card-cap-padding-y: $card-spacer-y * 0.5;
$card-cap-padding-x: $card-spacer-x;
$card-cap-bg: rgba($black, 0.03);
$card-cap-color: null;
$card-height: null;
$card-color: null;
$card-bg: $white;
$card-img-overlay-padding: $spacer;
$card-group-margin: $grid-gutter-width * 0.5;

// 导航栏
$navbar-padding-y: $spacer * 0.5;
$navbar-padding-x: null;
$navbar-nav-link-padding-x: 0.5rem;
$navbar-brand-font-size: $font-size-lg;
$navbar-brand-height: $navbar-brand-font-size * $line-height-base;
$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * 0.5;
$navbar-brand-margin-end: 1rem;
$navbar-toggler-padding-y: 0.25rem;
$navbar-toggler-padding-x: 0.75rem;
$navbar-toggler-font-size: $font-size-lg;
$navbar-toggler-border-radius: $btn-border-radius;
$navbar-toggler-focus-width: $btn-focus-width;
$navbar-toggler-transition: box-shadow 0.15s ease-in-out;

// 模态框
$modal-inner-padding: $spacer;
$modal-footer-margin-between: 0.5rem;
$modal-dialog-margin: 0.5rem;
$modal-dialog-margin-y-sm-up: 1.75rem;
$modal-title-line-height: $line-height-base;
$modal-content-color: null;
$modal-content-bg: $white;
$modal-content-border-color: rgba($black, 0.2);
$modal-content-border-width: $border-width;
$modal-content-border-radius: $border-radius-lg;
$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width);
$modal-content-box-shadow-xs: 0 0.25rem 0.5rem rgba($black, 0.5);
$modal-content-box-shadow-sm-up: 0 0.5rem 1rem rgba($black, 0.5);
$modal-backdrop-bg: $black;
$modal-backdrop-opacity: 0.5;
$modal-header-border-color: $border-color;
$modal-footer-border-color: $modal-header-border-color;
$modal-header-border-width: $modal-content-border-width;
$modal-footer-border-width: $modal-header-border-width;
$modal-header-padding-y: $modal-inner-padding;
$modal-header-padding-x: $modal-inner-padding;
$modal-header-padding: $modal-header-padding-y $modal-header-padding-x;

// 断点系统
$grid-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
);

// 容器最大宽度
$container-max-widths: (
  sm: 540px,
  md: 720px,
  lg: 960px,
  xl: 1140px,
  xxl: 1320px
);

// 网格系统
$grid-columns: 12;
$grid-gutter-width: 1.5rem;
$grid-row-columns: 6;

2. 自定义主题配置

// _theme-config.scss
// 主题配置文件

// 导入 Bootstrap 函数和变量
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";

// 自定义变量(覆盖默认值)
@import "custom-variables";

// 导入 Bootstrap mixins
@import "~bootstrap/scss/mixins";

// 自定义 mixins
@import "custom-mixins";

// 导入 Bootstrap 核心样式
@import "~bootstrap/scss/root";
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/images";
@import "~bootstrap/scss/containers";
@import "~bootstrap/scss/grid";
@import "~bootstrap/scss/tables";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/transitions";
@import "~bootstrap/scss/dropdown";
@import "~bootstrap/scss/button-group";
@import "~bootstrap/scss/nav";
@import "~bootstrap/scss/navbar";
@import "~bootstrap/scss/card";
@import "~bootstrap/scss/accordion";
@import "~bootstrap/scss/breadcrumb";
@import "~bootstrap/scss/pagination";
@import "~bootstrap/scss/badge";
@import "~bootstrap/scss/alert";
@import "~bootstrap/scss/progress";
@import "~bootstrap/scss/list-group";
@import "~bootstrap/scss/close";
@import "~bootstrap/scss/toasts";
@import "~bootstrap/scss/modal";
@import "~bootstrap/scss/tooltip";
@import "~bootstrap/scss/popover";
@import "~bootstrap/scss/carousel";
@import "~bootstrap/scss/spinners";
@import "~bootstrap/scss/offcanvas";
@import "~bootstrap/scss/placeholders";

// 工具类
@import "~bootstrap/scss/helpers";
@import "~bootstrap/scss/utilities/api";

// 自定义组件样式
@import "custom-components";

// 自定义工具类
@import "custom-utilities";

3. 自定义 Mixins

// _custom-mixins.scss
// 自定义混合器

// 渐变背景混合器
@mixin gradient-bg($color1, $color2, $direction: to right) {
  background: linear-gradient($direction, $color1, $color2);
}

// 卡片阴影混合器
@mixin card-shadow($level: 1) {
  @if $level == 1 {
    box-shadow: 0 2px 4px rgba($black, 0.1);
  }
}

// 动画关键帧
@keyframes checkmark {
  0% {
    transform: translate(-50%, -50%) scale(0);
  }
  50% {
    transform: translate(-50%, -50%) scale(1.2);
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
  }
}

@keyframes progress-bar-stripes {
  0% {
    background-position-x: 1rem;
  }
}

2. 自定义工具类

// _custom-utilities.scss
// 自定义工具类

// 间距工具类扩展
$custom-spacers: (
  6: $spacer * 4,
  7: $spacer * 5,
  8: $spacer * 6,
  9: $spacer * 8,
  10: $spacer * 10
);

@each $key, $value in $custom-spacers {
  .m-#{$key} { margin: $value !important; }
  .mt-#{$key} { margin-top: $value !important; }
  .mr-#{$key} { margin-right: $value !important; }
  .mb-#{$key} { margin-bottom: $value !important; }
  .ml-#{$key} { margin-left: $value !important; }
  .mx-#{$key} {
    margin-right: $value !important;
    margin-left: $value !important;
  }
  .my-#{$key} {
    margin-top: $value !important;
    margin-bottom: $value !important;
  }
  
  .p-#{$key} { padding: $value !important; }
  .pt-#{$key} { padding-top: $value !important; }
  .pr-#{$key} { padding-right: $value !important; }
  .pb-#{$key} { padding-bottom: $value !important; }
  .pl-#{$key} { padding-left: $value !important; }
  .px-#{$key} {
    padding-right: $value !important;
    padding-left: $value !important;
  }
  .py-#{$key} {
    padding-top: $value !important;
    padding-bottom: $value !important;
  }
}

// 字体大小工具类扩展
.fs-xs { font-size: 0.75rem !important; }
.fs-xxl { font-size: 2rem !important; }
.fs-xxxl { font-size: 2.5rem !important; }

// 行高工具类
.lh-1 { line-height: 1 !important; }
.lh-sm { line-height: 1.25 !important; }
.lh-base { line-height: 1.5 !important; }
.lh-lg { line-height: 2 !important; }

// 字重工具类扩展
.fw-medium { font-weight: 500 !important; }
.fw-semibold { font-weight: 600 !important; }

// 边框半径工具类扩展
.rounded-xs { border-radius: 0.125rem !important; }
.rounded-xl { border-radius: 1rem !important; }
.rounded-2xl { border-radius: 1.5rem !important; }
.rounded-3xl { border-radius: 2rem !important; }

// 阴影工具类
.shadow-xs { box-shadow: 0 1px 2px rgba($black, 0.05) !important; }
.shadow-xl { box-shadow: 0 20px 25px -5px rgba($black, 0.1), 0 10px 10px -5px rgba($black, 0.04) !important; }
.shadow-2xl { box-shadow: 0 25px 50px -12px rgba($black, 0.25) !important; }
.shadow-inner { box-shadow: inset 0 2px 4px 0 rgba($black, 0.06) !important; }

// 变换工具类
.transform { transform: translateZ(0) !important; }
.scale-50 { transform: scale(0.5) !important; }
.scale-75 { transform: scale(0.75) !important; }
.scale-90 { transform: scale(0.9) !important; }
.scale-95 { transform: scale(0.95) !important; }
.scale-105 { transform: scale(1.05) !important; }
.scale-110 { transform: scale(1.1) !important; }
.scale-125 { transform: scale(1.25) !important; }
.scale-150 { transform: scale(1.5) !important; }

.rotate-1 { transform: rotate(1deg) !important; }
.rotate-2 { transform: rotate(2deg) !important; }
.rotate-3 { transform: rotate(3deg) !important; }
.rotate-6 { transform: rotate(6deg) !important; }
.rotate-12 { transform: rotate(12deg) !important; }
.rotate-45 { transform: rotate(45deg) !important; }
.rotate-90 { transform: rotate(90deg) !important; }
.rotate-180 { transform: rotate(180deg) !important; }

.-rotate-1 { transform: rotate(-1deg) !important; }
.-rotate-2 { transform: rotate(-2deg) !important; }
.-rotate-3 { transform: rotate(-3deg) !important; }
.-rotate-6 { transform: rotate(-6deg) !important; }
.-rotate-12 { transform: rotate(-12deg) !important; }
.-rotate-45 { transform: rotate(-45deg) !important; }
.-rotate-90 { transform: rotate(-90deg) !important; }
.-rotate-180 { transform: rotate(-180deg) !important; }

// 过渡工具类
.transition { transition: all 0.15s ease-in-out !important; }
.transition-none { transition: none !important; }
.transition-colors { transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out !important; }
.transition-opacity { transition: opacity 0.15s ease-in-out !important; }
.transition-shadow { transition: box-shadow 0.15s ease-in-out !important; }
.transition-transform { transition: transform 0.15s ease-in-out !important; }

// 持续时间工具类
.duration-75 { transition-duration: 75ms !important; }
.duration-100 { transition-duration: 100ms !important; }
.duration-150 { transition-duration: 150ms !important; }
.duration-200 { transition-duration: 200ms !important; }
.duration-300 { transition-duration: 300ms !important; }
.duration-500 { transition-duration: 500ms !important; }
.duration-700 { transition-duration: 700ms !important; }
.duration-1000 { transition-duration: 1000ms !important; }

// 缓动函数工具类
.ease-linear { transition-timing-function: linear !important; }
.ease-in { transition-timing-function: cubic-bezier(0.4, 0, 1, 1) !important; }
.ease-out { transition-timing-function: cubic-bezier(0, 0, 0.2, 1) !important; }
.ease-in-out { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) !important; }

// 光标工具类
.cursor-auto { cursor: auto !important; }
.cursor-default { cursor: default !important; }
.cursor-pointer { cursor: pointer !important; }
.cursor-wait { cursor: wait !important; }
.cursor-text { cursor: text !important; }
.cursor-move { cursor: move !important; }
.cursor-help { cursor: help !important; }
.cursor-not-allowed { cursor: not-allowed !important; }

// 用户选择工具类
.select-none { user-select: none !important; }
.select-text { user-select: text !important; }
.select-all { user-select: all !important; }
.select-auto { user-select: auto !important; }

// 指针事件工具类
.pointer-events-none { pointer-events: none !important; }
.pointer-events-auto { pointer-events: auto !important; }

// 滚动行为工具类
.scroll-smooth { scroll-behavior: smooth !important; }
.scroll-auto { scroll-behavior: auto !important; }

// 对象适应工具类
.object-contain { object-fit: contain !important; }
.object-cover { object-fit: cover !important; }
.object-fill { object-fit: fill !important; }
.object-none { object-fit: none !important; }
.object-scale-down { object-fit: scale-down !important; }

// 对象位置工具类
.object-bottom { object-position: bottom !important; }
.object-center { object-position: center !important; }
.object-left { object-position: left !important; }
.object-left-bottom { object-position: left bottom !important; }
.object-left-top { object-position: left top !important; }
.object-right { object-position: right !important; }
.object-right-bottom { object-position: right bottom !important; }
.object-right-top { object-position: right top !important; }
.object-top { object-position: top !important; }

颜色系统定制

1. 扩展颜色调色板

// _color-system.scss
// 颜色系统定制

// 扩展颜色调色板
$custom-colors: (
  "purple": #6f42c1,
  "pink": #e83e8c,
  "orange": #fd7e14,
  "yellow": #ffc107,
  "green": #28a745,
  "teal": #20c997,
  "cyan": #17a2b8,
  "indigo": #6610f2,
  "lime": #32cd32,
  "emerald": #10b981,
  "sky": #0ea5e9,
  "violet": #8b5cf6,
  "fuchsia": #d946ef,
  "rose": #f43f5e,
  "amber": #f59e0b,
  "slate": #64748b
);

// 生成颜色变体
@each $color, $value in $custom-colors {
  // 主色调
  .text-#{$color} {
    color: $value !important;
  }
  
  .bg-#{$color} {
    background-color: $value !important;
  }
  
  .border-#{$color} {
    border-color: $value !important;
  }
  
  // 浅色变体
  .text-#{$color}-light {
    color: tint-color($value, 40%) !important;
  }
  
  .bg-#{$color}-light {
    background-color: tint-color($value, 80%) !important;
  }
  
  .border-#{$color}-light {
    border-color: tint-color($value, 60%) !important;
  }
  
  // 深色变体
  .text-#{$color}-dark {
    color: shade-color($value, 40%) !important;
  }
  
  .bg-#{$color}-dark {
    background-color: shade-color($value, 20%) !important;
  }
  
  .border-#{$color}-dark {
    border-color: shade-color($value, 20%) !important;
  }
  
  // 按钮变体
  .btn-#{$color} {
    @include button-variant($value, $value);
  }
  
  .btn-outline-#{$color} {
    @include button-outline-variant($value);
  }
  
  // 警告框变体
  .alert-#{$color} {
    @include alert-variant(
      tint-color($value, 80%),
      tint-color($value, 70%),
      shade-color($value, 60%)
    );
  }
  
  // 徽章变体
  .badge-#{$color} {
    color: color-contrast($value);
    background-color: $value;
  }
}

// 渐变色系统
$gradients: (
  "primary-secondary": linear-gradient(135deg, $primary 0%, $secondary 100%),
  "success-info": linear-gradient(135deg, $success 0%, $info 100%),
  "warning-danger": linear-gradient(135deg, $warning 0%, $danger 100%),
  "purple-pink": linear-gradient(135deg, map-get($custom-colors, "purple") 0%, map-get($custom-colors, "pink") 100%),
  "blue-purple": linear-gradient(135deg, $primary 0%, map-get($custom-colors, "purple") 100%),
  "green-blue": linear-gradient(135deg, $success 0%, $info 100%),
  "orange-red": linear-gradient(135deg, map-get($custom-colors, "orange") 0%, $danger 100%),
  "sunset": linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%),
  "ocean": linear-gradient(135deg, #667eea 0%, #764ba2 100%),
  "forest": linear-gradient(135deg, #134e5e 0%, #71b280 100%),
  "fire": linear-gradient(135deg, #f093fb 0%, #f5576c 100%),
  "sky": linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)
);

@each $name, $gradient in $gradients {
  .bg-gradient-#{$name} {
    background: $gradient !important;
  }
  
  .text-gradient-#{$name} {
    background: $gradient;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }
}

// 透明度工具类
$opacities: (0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 95, 100);

@each $opacity in $opacities {
  .opacity-#{$opacity} {
    opacity: $opacity * 0.01 !important;
  }
}

// 颜色混合工具类
.mix-blend-normal { mix-blend-mode: normal !important; }
.mix-blend-multiply { mix-blend-mode: multiply !important; }
.mix-blend-screen { mix-blend-mode: screen !important; }
.mix-blend-overlay { mix-blend-mode: overlay !important; }
.mix-blend-darken { mix-blend-mode: darken !important; }
.mix-blend-lighten { mix-blend-mode: lighten !important; }
.mix-blend-color-dodge { mix-blend-mode: color-dodge !important; }
.mix-blend-color-burn { mix-blend-mode: color-burn !important; }
.mix-blend-hard-light { mix-blend-mode: hard-light !important; }
.mix-blend-soft-light { mix-blend-mode: soft-light !important; }
.mix-blend-difference { mix-blend-mode: difference !important; }
.mix-blend-exclusion { mix-blend-mode: exclusion !important; }

2. 动态颜色主题

// _dynamic-colors.scss
// 动态颜色主题

// CSS 自定义属性(CSS 变量)
:root {
  // 主色调变量
  --bs-primary-rgb: #{to-rgb($primary)};
  --bs-secondary-rgb: #{to-rgb($secondary)};
  --bs-success-rgb: #{to-rgb($success)};
  --bs-info-rgb: #{to-rgb($info)};
  --bs-warning-rgb: #{to-rgb($warning)};
  --bs-danger-rgb: #{to-rgb($danger)};
  --bs-light-rgb: #{to-rgb($light)};
  --bs-dark-rgb: #{to-rgb($dark)};
  
  // 动态主题变量
  --theme-primary: #{$primary};
  --theme-secondary: #{$secondary};
  --theme-accent: #ff6b35;
  --theme-background: #ffffff;
  --theme-surface: #f8f9fa;
  --theme-text: #212529;
  --theme-text-secondary: #6c757d;
  
  // 间距变量
  --theme-spacing-xs: 0.25rem;
  --theme-spacing-sm: 0.5rem;
  --theme-spacing-md: 1rem;
  --theme-spacing-lg: 1.5rem;
  --theme-spacing-xl: 3rem;
  
  // 边框半径变量
  --theme-radius-sm: 0.25rem;
  --theme-radius-md: 0.375rem;
  --theme-radius-lg: 0.5rem;
  --theme-radius-xl: 1rem;
  
  // 阴影变量
  --theme-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --theme-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
  --theme-shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1);
}

// 动态主题类
.theme-dynamic {
  // 使用 CSS 变量的组件
  .btn-dynamic {
    background-color: var(--theme-primary);
    border-color: var(--theme-primary);
    color: #ffffff;
    padding: var(--theme-spacing-sm) var(--theme-spacing-md);
    border-radius: var(--theme-radius-md);
    box-shadow: var(--theme-shadow-sm);
    transition: all 0.2s ease;
    
    &:hover {
      background-color: color-mix(in srgb, var(--theme-primary) 85%, black);
      border-color: color-mix(in srgb, var(--theme-primary) 85%, black);
      box-shadow: var(--theme-shadow-md);
    }
  }
  
  .card-dynamic {
    background-color: var(--theme-surface);
    border: 1px solid color-mix(in srgb, var(--theme-text) 10%, transparent);
    border-radius: var(--theme-radius-lg);
    box-shadow: var(--theme-shadow-sm);
    
    .card-header {
      background-color: var(--theme-primary);
      color: #ffffff;
      border-radius: var(--theme-radius-lg) var(--theme-radius-lg) 0 0;
    }
  }
  
  .navbar-dynamic {
    background-color: var(--theme-background);
    border-bottom: 1px solid color-mix(in srgb, var(--theme-text) 10%, transparent);
    
    .navbar-brand {
      color: var(--theme-primary);
    }
    
    .nav-link {
      color: var(--theme-text);
      
      &:hover {
        color: var(--theme-primary);
      }
    }
  }
}

// 主题切换器 JavaScript 支持
.theme-switcher {
  .theme-option {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    transition: all 0.2s ease;
    
    &:hover {
      transform: scale(1.1);
      border-color: rgba(0, 0, 0, 0.2);
    }
    
    &.active {
      border-color: var(--theme-primary);
      box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), 0.25);
    }
  }
}

排版定制

1. 字体系统定制

// _typography.scss
// 排版系统定制

// 导入自定义字体
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&family=Fira+Code:wght@300;400;500&display=swap');

// 字体变量定义
$font-family-primary: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
$font-family-heading: 'Poppins', $font-family-primary;
$font-family-code: 'Fira Code', 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', monospace;

// 字体大小比例系统
$font-scale-ratio: 1.25; // Major Third
$font-size-root: 16px;
$font-size-base: 1rem;

// 计算字体大小
$font-size-xs: $font-size-base / ($font-scale-ratio * $font-scale-ratio);
$font-size-sm: $font-size-base / $font-scale-ratio;
$font-size-md: $font-size-base;
$font-size-lg: $font-size-base * $font-scale-ratio;
$font-size-xl: $font-size-base * ($font-scale-ratio * $font-scale-ratio);
$font-size-2xl: $font-size-base * ($font-scale-ratio * $font-scale-ratio * $font-scale-ratio);
$font-size-3xl: $font-size-base * ($font-scale-ratio * $font-scale-ratio * $font-scale-ratio * $font-scale-ratio);

// 标题字体大小
$h1-font-size: $font-size-3xl;
$h2-font-size: $font-size-2xl;
$h3-font-size: $font-size-xl;
$h4-font-size: $font-size-lg;
$h5-font-size: $font-size-md;
$h6-font-size: $font-size-sm;

// 行高系统
$line-height-tight: 1.25;
$line-height-snug: 1.375;
$line-height-normal: 1.5;
$line-height-relaxed: 1.625;
$line-height-loose: 2;

// 字重系统
$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-semibold: 600;
$font-weight-bold: 700;

// 字间距系统
$letter-spacing-tighter: -0.05em;
$letter-spacing-tight: -0.025em;
$letter-spacing-normal: 0;
$letter-spacing-wide: 0.025em;
$letter-spacing-wider: 0.05em;
$letter-spacing-widest: 0.1em;

// 全局排版样式
body {
  font-family: $font-family-primary;
  font-size: $font-size-base;
  line-height: $line-height-normal;
  letter-spacing: $letter-spacing-normal;
}

// 标题样式定制
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: $font-family-heading;
  font-weight: $font-weight-semibold;
  line-height: $line-height-tight;
  letter-spacing: $letter-spacing-tight;
  margin-bottom: 0.5em;
}

h1, .h1 {
  font-size: $h1-font-size;
  font-weight: $font-weight-bold;
  letter-spacing: $letter-spacing-tighter;
}

h2, .h2 {
  font-size: $h2-font-size;
}

h3, .h3 {
  font-size: $h3-font-size;
}

h4, .h4 {
  font-size: $h4-font-size;
}

h5, .h5 {
  font-size: $h5-font-size;
}

h6, .h6 {
  font-size: $h6-font-size;
  font-weight: $font-weight-medium;
  text-transform: uppercase;
  letter-spacing: $letter-spacing-wide;
}

// 段落样式
p {
  margin-bottom: 1em;
  
  &.lead {
    font-size: $font-size-lg;
    font-weight: $font-weight-normal;
    line-height: $line-height-relaxed;
  }
  
  &.small {
    font-size: $font-size-sm;
    line-height: $line-height-normal;
  }
}

// 代码样式
code, kbd, pre, samp {
  font-family: $font-family-code;
}

code {
  font-size: 0.875em;
  background-color: rgba($primary, 0.1);
  color: shade-color($primary, 20%);
  padding: 0.125rem 0.25rem;
  border-radius: 0.25rem;
}

pre {
  background-color: $gray-100;
  border: 1px solid $gray-300;
  border-radius: 0.5rem;
  padding: 1rem;
  overflow-x: auto;
  
  code {
    background-color: transparent;
    color: inherit;
    padding: 0;
  }
}

// 引用样式
blockquote {
  border-left: 4px solid $primary;
  padding-left: 1rem;
  margin: 1.5rem 0;
  font-style: italic;
  font-size: $font-size-lg;
  line-height: $line-height-relaxed;
  
  footer {
    font-size: $font-size-sm;
    color: $gray-600;
    margin-top: 0.5rem;
    
    &::before {
      content: '— ';
    }
  }
}

// 列表样式
ul, ol {
  padding-left: 1.5rem;
  
  li {
    margin-bottom: 0.25rem;
  }
}

// 链接样式
a {
  color: $primary;
  text-decoration: none;
  transition: color 0.15s ease-in-out;
  
  &:hover {
    color: shade-color($primary, 15%);
    text-decoration: underline;
  }
  
  &:focus {
    outline: 2px solid rgba($primary, 0.5);
    outline-offset: 2px;
  }
}

// 排版工具类
.font-primary { font-family: $font-family-primary !important; }
.font-heading { font-family: $font-family-heading !important; }
.font-code { font-family: $font-family-code !important; }

.text-xs { font-size: $font-size-xs !important; }
.text-sm { font-size: $font-size-sm !important; }
.text-base { font-size: $font-size-md !important; }
.text-lg { font-size: $font-size-lg !important; }
.text-xl { font-size: $font-size-xl !important; }
.text-2xl { font-size: $font-size-2xl !important; }
.text-3xl { font-size: $font-size-3xl !important; }

.leading-tight { line-height: $line-height-tight !important; }
.leading-snug { line-height: $line-height-snug !important; }
.leading-normal { line-height: $line-height-normal !important; }
.leading-relaxed { line-height: $line-height-relaxed !important; }
.leading-loose { line-height: $line-height-loose !important; }

.tracking-tighter { letter-spacing: $letter-spacing-tighter !important; }
.tracking-tight { letter-spacing: $letter-spacing-tight !important; }
.tracking-normal { letter-spacing: $letter-spacing-normal !important; }
.tracking-wide { letter-spacing: $letter-spacing-wide !important; }
.tracking-wider { letter-spacing: $letter-spacing-wider !important; }
.tracking-widest { letter-spacing: $letter-spacing-widest !important; }

.font-light { font-weight: $font-weight-light !important; }
.font-normal { font-weight: $font-weight-normal !important; }
.font-medium { font-weight: $font-weight-medium !important; }
.font-semibold { font-weight: $font-weight-semibold !important; }
.font-bold { font-weight: $font-weight-bold !important; }

2. 响应式排版

// _responsive-typography.scss
// 响应式排版

// 响应式字体大小混合器
@mixin responsive-font-size($min-size, $max-size, $min-width: 320px, $max-width: 1200px) {
  font-size: $min-size;
  
  @media (min-width: $min-width) {
    font-size: calc(#{$min-size} + #{strip-unit($max-size - $min-size)} * ((100vw - #{$min-width}) / #{strip-unit($max-width - $min-width)}));
  }
  
  @media (min-width: $max-width) {
    font-size: $max-size;
  }
}

// 响应式标题
h1, .h1 {
  @include responsive-font-size(2rem, 3.5rem);
}

h2, .h2 {
  @include responsive-font-size(1.75rem, 2.5rem);
}

h3, .h3 {
  @include responsive-font-size(1.5rem, 2rem);
}

h4, .h4 {
  @include responsive-font-size(1.25rem, 1.5rem);
}

// 响应式段落
p {
  &.lead {
    @include responsive-font-size(1.125rem, 1.25rem);
  }
}

// 响应式间距
@include media-breakpoint-down(md) {
  h1, h2, h3, h4, h5, h6,
  .h1, .h2, .h3, .h4, .h5, .h6 {
    margin-bottom: 0.75rem;
  }
  
  p {
    margin-bottom: 1rem;
  }
  
  blockquote {
    margin: 1rem 0;
    padding-left: 0.75rem;
  }
}

// 响应式排版工具类
@each $breakpoint in map-keys($grid-breakpoints) {
  @include media-breakpoint-up($breakpoint) {
    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
    
    .text#{$infix}-xs { font-size: $font-size-xs !important; }
    .text#{$infix}-sm { font-size: $font-size-sm !important; }
    .text#{$infix}-base { font-size: $font-size-md !important; }
    .text#{$infix}-lg { font-size: $font-size-lg !important; }
    .text#{$infix}-xl { font-size: $font-size-xl !important; }
    .text#{$infix}-2xl { font-size: $font-size-2xl !important; }
    .text#{$infix}-3xl { font-size: $font-size-3xl !important; }
    
    .leading#{$infix}-tight { line-height: $line-height-tight !important; }
    .leading#{$infix}-normal { line-height: $line-height-normal !important; }
    .leading#{$infix}-relaxed { line-height: $line-height-relaxed !important; }
  }
}

构建工具集成

1. Webpack 配置

// webpack.config.js
// Webpack 配置文件

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';
  
  return {
    entry: {
      main: './src/scss/main.scss',
      theme: './src/scss/theme.scss'
    },
    
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'js/[name].[contenthash].js',
      clean: true
    },
    
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            {
              loader: 'css-loader',
              options: {
                sourceMap: !isProduction
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                postcssOptions: {
                  plugins: [
                    ['autoprefixer'],
                    isProduction && ['cssnano', { preset: 'default' }]
                  ].filter(Boolean)
                },
                sourceMap: !isProduction
              }
            },
            {
              loader: 'sass-loader',
              options: {
                implementation: require('sass'),
                sourceMap: !isProduction,
                sassOptions: {
                  includePaths: ['node_modules']
                }
              }
            }
          ]
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          type: 'asset/resource',
          generator: {
            filename: 'fonts/[name][ext]'
          }
        },
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/,
          type: 'asset/resource',
          generator: {
            filename: 'images/[name][ext]'
          }
        }
      ]
    },
    
    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash].css'
      })
    ],
    
    optimization: {
      minimizer: [
        new TerserPlugin(),
        new OptimizeCSSAssetsPlugin()
      ],
      splitChunks: {
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all'
          }
        }
      }
    },
    
    devServer: {
      contentBase: path.join(__dirname, 'dist'),
      compress: true,
      port: 3000,
      hot: true,
      open: true
    },
    
    devtool: isProduction ? 'source-map' : 'eval-source-map'
  };
};

2. Gulp 构建任务

// gulpfile.js
// Gulp 构建任务

const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');
const browserSync = require('browser-sync').create();
const del = require('del');

// 路径配置
const paths = {
  scss: {
    src: 'src/scss/**/*.scss',
    dest: 'dist/css/'
  },
  html: {
    src: 'src/**/*.html',
    dest: 'dist/'
  },
  js: {
    src: 'src/js/**/*.js',
    dest: 'dist/js/'
  }
};

// 清理任务
function clean() {
  return del(['dist']);
}

// SCSS 编译任务
function styles() {
  return gulp.src(paths.scss.src)
    .pipe(sourcemaps.init())
    .pipe(sass({
      includePaths: ['node_modules'],
      outputStyle: 'expanded'
    }).on('error', sass.logError))
    .pipe(postcss([
      autoprefixer()
    ]))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(paths.scss.dest))
    .pipe(browserSync.stream());
}

// SCSS 压缩任务
function stylesMin() {
  return gulp.src(paths.scss.src)
    .pipe(sass({
      includePaths: ['node_modules'],
      outputStyle: 'compressed'
    }).on('error', sass.logError))
    .pipe(postcss([
      autoprefixer(),
      cssnano()
    ]))
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest(paths.scss.dest));
}

// HTML 复制任务
function html() {
  return gulp.src(paths.html.src)
    .pipe(gulp.dest(paths.html.dest))
    .pipe(browserSync.stream());
}

// JavaScript 复制任务
function scripts() {
  return gulp.src(paths.js.src)
    .pipe(gulp.dest(paths.js.dest))
    .pipe(browserSync.stream());
}

// 开发服务器
function serve() {
  browserSync.init({
    server: {
      baseDir: './dist'
    },
    port: 3000
  });
  
  gulp.watch(paths.scss.src, styles);
  gulp.watch(paths.html.src, html);
  gulp.watch(paths.js.src, scripts);
}

// 监听任务
function watch() {
  gulp.watch(paths.scss.src, styles);
  gulp.watch(paths.html.src, html);
  gulp.watch(paths.js.src, scripts);
}

// 构建任务
const build = gulp.series(clean, gulp.parallel(styles, stylesMin, html, scripts));
const dev = gulp.series(clean, gulp.parallel(styles, html, scripts), serve);

// 导出任务
exports.clean = clean;
exports.styles = styles;
exports.stylesMin = stylesMin;
exports.html = html;
exports.scripts = scripts;
exports.watch = watch;
exports.serve = serve;
exports.build = build;
exports.dev = dev;
exports.default = dev;

3. package.json 配置

{
  "name": "bootstrap-custom-theme",
  "version": "1.0.0",
  "description": "Bootstrap 自定义主题项目",
  "main": "index.js",
  "scripts": {
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production",
    "build:css": "sass src/scss/main.scss dist/css/main.css --style=expanded",
    "build:css:min": "sass src/scss/main.scss dist/css/main.min.css --style=compressed",
    "watch": "sass --watch src/scss:dist/css",
    "gulp:dev": "gulp dev",
    "gulp:build": "gulp build",
    "lint:scss": "stylelint src/scss/**/*.scss",
    "lint:scss:fix": "stylelint src/scss/**/*.scss --fix",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "bootstrap",
    "sass",
    "css",
    "theme",
    "custom"
  ],
  "author": "Your Name",
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "autoprefixer": "^10.3.0",
    "babel-loader": "^8.2.0",
    "browser-sync": "^2.27.0",
    "css-loader": "^6.2.0",
    "cssnano": "^5.0.0",
    "del": "^6.0.0",
    "gulp": "^4.0.0",
    "gulp-postcss": "^9.0.0",
    "gulp-rename": "^2.0.0",
    "gulp-sass": "^5.0.0",
    "gulp-sourcemaps": "^3.0.0",
    "mini-css-extract-plugin": "^2.2.0",
    "optimize-css-assets-webpack-plugin": "^6.0.0",
    "postcss": "^8.3.0",
    "postcss-loader": "^6.1.0",
    "sass": "^1.38.0",
    "sass-loader": "^12.1.0",
    "style-loader": "^3.2.0",
    "stylelint": "^13.13.0",
    "stylelint-config-standard": "^22.0.0",
    "stylelint-scss": "^3.20.0",
    "terser-webpack-plugin": "^5.1.0",
    "webpack": "^5.51.0",
    "webpack-cli": "^4.8.0",
    "webpack-dev-server": "^4.0.0"
  },
  "dependencies": {
    "bootstrap": "^5.1.0"
  }
}
## 实际应用案例

1. 企业级管理后台主题

// _admin-theme.scss
// 企业级管理后台主题

// 主题色彩定义
$admin-primary: #2563eb;      // 专业蓝
$admin-secondary: #64748b;    // 中性灰
$admin-success: #059669;      // 成功绿
$admin-warning: #d97706;      // 警告橙
$admin-danger: #dc2626;       // 危险红
$admin-info: #0891b2;         // 信息青
$admin-light: #f8fafc;        // 浅色背景
$admin-dark: #1e293b;         // 深色文本

// 侧边栏主题
.admin-sidebar {
  background: linear-gradient(180deg, #1e293b 0%, #334155 100%);
  border-right: 1px solid rgba(255, 255, 255, 0.1);
  
  .nav-link {
    color: rgba(255, 255, 255, 0.8);
    padding: 0.75rem 1.5rem;
    border-radius: 0.5rem;
    margin: 0.25rem 0.75rem;
    transition: all 0.2s ease;
    
    &:hover {
      background-color: rgba(255, 255, 255, 0.1);
      color: #ffffff;
    }
    
    &.active {
      background-color: $admin-primary;
      color: #ffffff;
      box-shadow: 0 4px 6px rgba($admin-primary, 0.3);
    }
    
    i {
      width: 20px;
      margin-right: 0.75rem;
    }
  }
  
  .sidebar-brand {
    padding: 1.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    
    h4 {
      color: #ffffff;
      margin: 0;
      font-weight: 600;
    }
  }
}

// 顶部导航栏
.admin-navbar {
  background-color: #ffffff;
  border-bottom: 1px solid #e2e8f0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  
  .navbar-brand {
    font-weight: 600;
    color: $admin-primary;
  }
  
  .nav-link {
    color: $admin-dark;
    
    &:hover {
      color: $admin-primary;
    }
  }
  
  .dropdown-menu {
    border: none;
    box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
    border-radius: 0.5rem;
  }
}

// 主内容区域
.admin-content {
  background-color: #f1f5f9;
  min-height: 100vh;
  
  .content-header {
    background-color: #ffffff;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    border-radius: 0.5rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    
    h1 {
      margin: 0;
      color: $admin-dark;
      font-weight: 600;
    }
    
    .breadcrumb {
      margin: 0;
      background: none;
      padding: 0;
      
      .breadcrumb-item {
        &.active {
          color: $admin-secondary;
        }
        
        a {
          color: $admin-primary;
          text-decoration: none;
          
          &:hover {
            text-decoration: underline;
          }
        }
      }
    }
  }
}

// 统计卡片
.admin-stat-card {
  background: linear-gradient(135deg, $admin-primary 0%, lighten($admin-primary, 10%) 100%);
  color: #ffffff;
  border-radius: 1rem;
  padding: 1.5rem;
  position: relative;
  overflow: hidden;
  
  &::before {
    content: '';
    position: absolute;
    top: -50%;
    right: -50%;
    width: 100%;
    height: 100%;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
  }
  
  .stat-icon {
    font-size: 2.5rem;
    opacity: 0.8;
  }
  
  .stat-number {
    font-size: 2rem;
    font-weight: 700;
    margin: 0.5rem 0;
  }
  
  .stat-label {
    font-size: 0.875rem;
    opacity: 0.9;
  }
  
  &.success {
    background: linear-gradient(135deg, $admin-success 0%, lighten($admin-success, 10%) 100%);
  }
  
  &.warning {
    background: linear-gradient(135deg, $admin-warning 0%, lighten($admin-warning, 10%) 100%);
  }
  
  &.danger {
    background: linear-gradient(135deg, $admin-danger 0%, lighten($admin-danger, 10%) 100%);
  }
}

// 数据表格
.admin-table {
  background-color: #ffffff;
  border-radius: 0.5rem;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  
  .table {
    margin: 0;
    
    thead {
      background-color: $admin-light;
      
      th {
        border: none;
        font-weight: 600;
        color: $admin-dark;
        padding: 1rem;
      }
    }
    
    tbody {
      tr {
        transition: background-color 0.2s ease;
        
        &:hover {
          background-color: rgba($admin-primary, 0.05);
        }
        
        td {
          border: none;
          border-top: 1px solid #e2e8f0;
          padding: 1rem;
          vertical-align: middle;
        }
      }
    }
  }
}

// 表单样式
.admin-form {
  .form-label {
    font-weight: 600;
    color: $admin-dark;
    margin-bottom: 0.5rem;
  }
  
  .form-control {
    border: 2px solid #e2e8f0;
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
    transition: all 0.2s ease;
    
    &:focus {
      border-color: $admin-primary;
      box-shadow: 0 0 0 3px rgba($admin-primary, 0.1);
    }
  }
  
  .btn-primary {
    background-color: $admin-primary;
    border-color: $admin-primary;
    padding: 0.75rem 2rem;
    font-weight: 600;
    border-radius: 0.5rem;
    
    &:hover {
      background-color: darken($admin-primary, 5%);
      border-color: darken($admin-primary, 5%);
    }
  }
}

2. 电商网站主题

// _ecommerce-theme.scss
// 电商网站主题

// 电商主题色彩
$ecom-primary: #ff6b35;       // 活力橙
$ecom-secondary: #004e89;     // 深海蓝
$ecom-accent: #ffd23f;        // 金黄色
$ecom-success: #06d6a0;       // 薄荷绿
$ecom-warning: #f18701;       // 琥珀色
$ecom-danger: #e63946;        // 珊瑚红

// 产品卡片
.product-card {
  border: none;
  border-radius: 1rem;
  overflow: hidden;
  transition: all 0.3s ease;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  
  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
  }
  
  .product-image {
    position: relative;
    overflow: hidden;
    
    img {
      transition: transform 0.3s ease;
    }
    
    &:hover img {
      transform: scale(1.05);
    }
    
    .product-badge {
      position: absolute;
      top: 1rem;
      left: 1rem;
      background-color: $ecom-danger;
      color: #ffffff;
      padding: 0.25rem 0.75rem;
      border-radius: 2rem;
      font-size: 0.75rem;
      font-weight: 600;
      text-transform: uppercase;
      
      &.new {
        background-color: $ecom-success;
      }
      
      &.sale {
        background-color: $ecom-warning;
      }
    }
    
    .product-actions {
      position: absolute;
      top: 1rem;
      right: 1rem;
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
      opacity: 0;
      transition: opacity 0.3s ease;
      
      .btn {
        width: 40px;
        height: 40px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: #ffffff;
        border: none;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        
        &:hover {
          background-color: $ecom-primary;
          color: #ffffff;
        }
      }
    }
    
    &:hover .product-actions {
      opacity: 1;
    }
  }
  
  .card-body {
    padding: 1.5rem;
    
    .product-title {
      font-weight: 600;
      margin-bottom: 0.5rem;
      
      a {
        color: inherit;
        text-decoration: none;
        
        &:hover {
          color: $ecom-primary;
        }
      }
    }
    
    .product-rating {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 0.75rem;
      
      .stars {
        color: $ecom-accent;
      }
      
      .rating-count {
        color: #6c757d;
        font-size: 0.875rem;
      }
    }
    
    .product-price {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 1rem;
      
      .current-price {
        font-size: 1.25rem;
        font-weight: 700;
        color: $ecom-primary;
      }
      
      .original-price {
        font-size: 1rem;
        color: #6c757d;
        text-decoration: line-through;
      }
      
      .discount {
        background-color: $ecom-success;
        color: #ffffff;
        padding: 0.125rem 0.5rem;
        border-radius: 0.25rem;
        font-size: 0.75rem;
        font-weight: 600;
      }
    }
    
    .add-to-cart {
      width: 100%;
      background-color: $ecom-primary;
      border-color: $ecom-primary;
      color: #ffffff;
      font-weight: 600;
      padding: 0.75rem;
      border-radius: 0.5rem;
      transition: all 0.2s ease;
      
      &:hover {
        background-color: darken($ecom-primary, 10%);
        border-color: darken($ecom-primary, 10%);
        transform: translateY(-1px);
      }
    }
  }
}

// 购物车样式
.shopping-cart {
  .cart-item {
    border-bottom: 1px solid #e9ecef;
    padding: 1.5rem 0;
    
    &:last-child {
      border-bottom: none;
    }
    
    .item-image {
      width: 80px;
      height: 80px;
      border-radius: 0.5rem;
      overflow: hidden;
    }
    
    .item-details {
      flex: 1;
      
      .item-title {
        font-weight: 600;
        margin-bottom: 0.25rem;
      }
      
      .item-variant {
        color: #6c757d;
        font-size: 0.875rem;
      }
    }
    
    .quantity-controls {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      
      .btn {
        width: 32px;
        height: 32px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        border: 1px solid #dee2e6;
        background-color: #ffffff;
        
        &:hover {
          background-color: $ecom-primary;
          border-color: $ecom-primary;
          color: #ffffff;
        }
      }
      
      .quantity {
        min-width: 40px;
        text-align: center;
        font-weight: 600;
      }
    }
    
    .item-price {
      font-weight: 700;
      color: $ecom-primary;
    }
  }
  
  .cart-summary {
    background-color: #f8f9fa;
    padding: 1.5rem;
    border-radius: 0.5rem;
    
    .summary-row {
      display: flex;
      justify-content: space-between;
      margin-bottom: 0.75rem;
      
      &.total {
        font-weight: 700;
        font-size: 1.125rem;
        border-top: 1px solid #dee2e6;
        padding-top: 0.75rem;
        margin-top: 1rem;
        margin-bottom: 0;
      }
    }
    
    .checkout-btn {
      width: 100%;
      background-color: $ecom-success;
      border-color: $ecom-success;
      color: #ffffff;
      font-weight: 600;
      padding: 1rem;
      border-radius: 0.5rem;
      margin-top: 1rem;
      
      &:hover {
        background-color: darken($ecom-success, 10%);
        border-color: darken($ecom-success, 10%);
      }
    }
  }
}

最佳实践

1. 主题开发流程

// 1. 规划阶段
// - 定义设计系统
// - 确定色彩方案
// - 制定组件规范
// - 设计响应式策略

// 2. 开发阶段
// - 创建变量文件
// - 开发自定义 mixins
// - 实现组件样式
// - 添加工具类

// 3. 测试阶段
// - 跨浏览器测试
// - 响应式测试
// - 可访问性测试
// - 性能测试

// 4. 优化阶段
// - CSS 压缩
// - 移除未使用样式
// - 优化加载性能
// - 文档编写

2. 代码组织结构

src/scss/
├── abstracts/
│   ├── _variables.scss      # 自定义变量
│   ├── _mixins.scss         # 自定义 mixins
│   └── _functions.scss      # 自定义函数
├── base/
│   ├── _reset.scss          # 重置样式
│   ├── _typography.scss     # 排版样式
│   └── _utilities.scss      # 工具类
├── components/
│   ├── _buttons.scss        # 按钮组件
│   ├── _cards.scss          # 卡片组件
│   ├── _forms.scss          # 表单组件
│   └── _navigation.scss     # 导航组件
├── layout/
│   ├── _header.scss         # 头部布局
│   ├── _sidebar.scss        # 侧边栏布局
│   └── _footer.scss         # 底部布局
├── pages/
│   ├── _home.scss           # 首页样式
│   ├── _about.scss          # 关于页面
│   └── _contact.scss        # 联系页面
├── themes/
│   ├── _light.scss          # 浅色主题
│   ├── _dark.scss           # 深色主题
│   └── _admin.scss          # 管理主题
├── vendors/
│   └── _bootstrap.scss      # Bootstrap 导入
└── main.scss                # 主入口文件

3. 性能优化建议

// 1. 选择器优化
// 避免过深的嵌套
.card {
  .header {
    .title {
      // 最多 3 层嵌套
    }
  }
}

// 2. 使用高效的选择器
// 优先使用类选择器
.btn-primary { } // 好
.btn.btn-primary { } // 避免

// 3. 合理使用 @extend
// 谨慎使用,可能导致 CSS 膨胀
%button-base {
  padding: 0.5rem 1rem;
  border-radius: 0.25rem;
}

.btn {
  @extend %button-base;
}

// 4. 优化媒体查询
// 使用 Bootstrap 的断点 mixins
@include media-breakpoint-up(md) {
  .custom-component {
    // 样式
  }
}

// 5. 移除未使用的样式
// 使用 PurgeCSS 或类似工具
// 在构建过程中自动移除

4. 可维护性建议

// 1. 使用语义化的变量名
$color-primary: #007bff;        // 好
$blue: #007bff;                 // 避免

// 2. 添加注释说明
// 主要品牌色,用于按钮、链接等
$brand-primary: #007bff;

// 3. 保持一致的命名规范
// 使用 BEM 方法论
.card {
  &__header {
    // 卡片头部
  }
  
  &__body {
    // 卡片主体
  }
  
  &--featured {
    // 特色卡片修饰符
  }
}

// 4. 模块化开发
// 每个组件独立文件
// 通过主文件导入
@import 'components/buttons';
@import 'components/cards';
@import 'components/forms';

// 5. 版本控制
// 使用语义化版本号
// 记录变更日志
// 保持向后兼容

本章总结

本章深入介绍了 Bootstrap 的自定义与主题化技术,涵盖了以下核心内容:

主要知识点

  1. Sass 变量定制

    • 颜色系统定制
    • 字体和排版变量
    • 间距和尺寸变量
    • 组件特定变量
  2. 自定义主题配置

    • Bootstrap 源码结构
    • 自定义构建流程
    • 主题文件组织
    • 变量覆盖策略
  3. 自定义 Mixins

    • 实用工具 mixins
    • 组件样式 mixins
    • 响应式 mixins
    • 动画效果 mixins
  4. 自定义组件样式

    • 按钮组件定制
    • 卡片组件定制
    • 导航组件定制
    • 表单组件定制
  5. 自定义工具类

    • 扩展间距系统
    • 自定义字体工具
    • 颜色工具类
    • 布局工具类
  6. 颜色系统定制

    • 扩展调色板
    • 颜色变体生成
    • 渐变色系统
    • 动态主题支持
  7. 排版定制

    • 字体系统设计
    • 响应式排版
    • 排版工具类
    • 可读性优化
  8. 构建工具集成

    • Webpack 配置
    • Gulp 任务设置
    • 开发环境配置
    • 生产构建优化

实践要点

  • 设计系统思维:建立一致的设计语言和组件规范
  • 模块化开发:合理组织代码结构,提高可维护性
  • 性能优化:注意 CSS 文件大小和加载性能
  • 响应式设计:确保主题在各种设备上的表现
  • 可访问性:遵循 Web 可访问性标准
  • 浏览器兼容:测试主题在不同浏览器中的兼容性

开发建议

  • 从小规模定制开始,逐步扩展
  • 保持与 Bootstrap 更新的同步
  • 建立完善的文档和示例
  • 进行充分的测试和验证
  • 考虑团队协作和代码规范

通过本章的学习,你应该能够: - 熟练使用 Sass 定制 Bootstrap 主题 - 创建符合项目需求的自定义组件 - 建立高效的开发和构建流程 - 实现响应式和可访问的主题设计 - 优化主题性能和可维护性

练习题

基础练习

  1. 变量定制练习

    • 创建一个深色主题,定制所有主要颜色变量
    • 实现一个大字体主题,调整所有字体大小变量
    • 设计一个紧凑主题,减少所有间距变量
  2. 组件定制练习

    • 创建一个圆角按钮主题,所有按钮都是圆形
    • 设计一个卡片阴影主题,为卡片添加多层阴影效果
    • 实现一个彩色导航主题,每个导航项使用不同颜色
  3. 工具类扩展练习

    • 添加更多的间距工具类(如 .p-7, .m-8 等)
    • 创建文本阴影工具类(如 .text-shadow-sm, .text-shadow-lg)
    • 实现边框样式工具类(如 .border-dashed, .border-dotted)

进阶练习

  1. 响应式主题练习

    • 创建一个在不同屏幕尺寸下使用不同颜色方案的主题
    • 实现响应式字体大小系统,在移动端自动缩放
    • 设计响应式间距系统,在小屏幕上减少间距
  2. 动态主题练习

    • 使用 CSS 变量实现可切换的明暗主题
    • 创建一个颜色主题选择器,用户可以选择不同的主色调
    • 实现一个季节主题系统,根据时间自动切换主题
  3. 性能优化练习

    • 使用 PurgeCSS 移除未使用的 Bootstrap 样式
    • 实现 CSS 的懒加载,按需加载主题文件
    • 优化 Sass 编译性能,减少构建时间

综合项目

  1. 企业级主题开发

    • 为一个虚拟公司设计完整的品牌主题
    • 包含所有常用组件的定制样式
    • 实现完整的构建和部署流程
    • 编写详细的使用文档
  2. 多主题系统

    • 创建一个支持多个主题的系统架构
    • 实现主题的动态切换功能
    • 支持用户自定义主题配置
    • 提供主题预览和导出功能

答案提示

练习答案和详细解释可以在以下资源中找到: - Bootstrap 官方文档 - 主题化 - Sass 官方文档 - CSS 自定义属性指南 - 响应式设计最佳实践

完成这些练习将帮助你深入理解 Bootstrap 主题化的各个方面,并能够在实际项目中灵活运用这些技术。 box-shadow: 0 16px 32px rgba($black, 0.25); } }

// 按钮变体混合器 @mixin button-variant-custom($background, $border, $color: color-contrast($background), $hover-background: shade-color($background, 15%), $hover-border: shade-color($border, 20%), $hover-color: color-contrast($hover-background), $active-background: shade-color($background, 20%), $active-border: shade-color($border, 25%), $active-color: color-contrast($active-background)) { color: $color; @include gradient-bg($background, shade-color($background, 10%)); border-color: $border; @include box-shadow($btn-box-shadow);

&:hover { color: $hover-color; @include gradient-bg($hover-background, shade-color($hover-background, 10%)); border-color: $hover-border; }

.btn-check:focus + &, &:focus { color: $hover-color; @include gradient-bg($hover-background, shade-color($hover-background, 10%)); border-color: $hover-border; @if $enable-shadows { @include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5)); } @else { box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5); } }

.btn-check:checked + &, .btn-check:active + &, &:active, &.active, .show > &.dropdown-toggle { color: $active-color; background-color: $active-background; background-image: if($enable-gradients, none, null); border-color: $active-border;

&:focus {
  @if $enable-shadows {
    @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));
  } @else {
    box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);
  }
}

}

&:disabled, &.disabled { color: $color; background-color: $background; background-image: if($enable-gradients, none, null); border-color: $border; } }

// 响应式字体大小混合器 @mixin responsive-font-size($min-size, $max-size, $min-width: 320px, $max-width: 1200px) { font-size: $min-size;

@media (min-width: $min-width) { font-size: calc(#{$min-size} + #{strip-unit($max-size - $min-size)} * ((100vw - #{$min-width}) / #{strip-unit($max-width - $min-width)})); }

@media (min-width: $max-width) { font-size: $max-size; } }

// 文本截断混合器 @mixin text-truncate($lines: 1) { @if $lines == 1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } @else { display: -webkit-box; -webkit-line-clamp: $lines; -webkit-box-orient: vertical; overflow: hidden; } }

// 居中混合器 @mixin center($position: absolute) { position: $position; top: 50%; left: 50%; transform: translate(-50%, -50%); }

// 清除浮动混合器 @mixin clearfix() { &::after { display: block; clear: both; content: “”; } }

// 三角形混合器 @mixin triangle($direction, $size, $color) { width: 0; height: 0;

@if $direction == up { border-left: $size solid transparent; border-right: $size solid transparent; border-bottom: $size solid $color; } @else if $direction == down { border-left: $size solid transparent; border-right: $size solid transparent; border-top: $size solid $color; } @else if $direction == left { border-top: $size solid transparent; border-bottom: $size solid transparent; border-right: $size solid $color; } @else if $direction == right { border-top: $size solid transparent; border-bottom: $size solid transparent; border-left: $size solid $color; } }

// 动画混合器 @mixin animation($name, $duration: 1s, $timing-function: ease, $delay: 0s, $iteration-count: 1, $direction: normal, $fill-mode: both) { animation: $name $duration $timing-function $delay $iteration-count $direction $fill-mode; }

// 过渡混合器 @mixin transition($properties…) { $transitions: ();

@each $property in $properties { $transitions: append($transitions, $property, comma); }

transition: $transitions; }

// 媒体查询混合器 @mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { $min: breakpoint-min($lower, $breakpoints); $max: breakpoint-max($upper, $breakpoints);

@if $min != null and $max != null { @media (min-width: $min) and (max-width: $max) { @content; } } @else if $max == null { @include media-breakpoint-up($lower, $breakpoints) { @content; } } @else if $min == null { @include media-breakpoint-down($upper, $breakpoints) { @content; } } }


## 自定义主题创建

### 1. 深色主题

```scss
// _dark-theme.scss
// 深色主题定制

// 深色主题变量
$dark-theme-colors: (
  "primary": #0d6efd,
  "secondary": #6c757d,
  "success": #198754,
  "info": #0dcaf0,
  "warning": #ffc107,
  "danger": #dc3545,
  "light": #f8f9fa,
  "dark": #212529
);

$dark-theme-grays: (
  "100": #1a1d20,
  "200": #2c3034,
  "300": #3e4348,
  "400": #50565c,
  "500": #626970,
  "600": #747c84,
  "700": #868f98,
  "800": #98a2ac,
  "900": #aab5c0
);

// 深色主题基础样式
[data-bs-theme="dark"] {
  // 背景和文本颜色
  --bs-body-color: #{map-get($dark-theme-grays, "900")};
  --bs-body-bg: #{map-get($dark-theme-grays, "100")};
  --bs-emphasis-color: #ffffff;
  --bs-secondary-color: #{rgba(map-get($dark-theme-grays, "900"), 0.75)};
  --bs-tertiary-color: #{rgba(map-get($dark-theme-grays, "900"), 0.5)};
  
  // 边框颜色
  --bs-border-color: #{map-get($dark-theme-grays, "300")};
  --bs-border-color-translucent: #{rgba(#ffffff, 0.15)};
  
  // 链接颜色
  --bs-link-color: #{tint-color(map-get($dark-theme-colors, "primary"), 40%)};
  --bs-link-hover-color: #{tint-color(map-get($dark-theme-colors, "primary"), 60%)};
  
  // 表单控件
  --bs-form-control-bg: #{map-get($dark-theme-grays, "200")};
  --bs-form-control-border-color: #{map-get($dark-theme-grays, "400")};
  
  // 卡片
  .card {
    --bs-card-bg: #{map-get($dark-theme-grays, "200")};
    --bs-card-border-color: #{map-get($dark-theme-grays, "300")};
  }
  
  // 导航栏
  .navbar {
    &.navbar-dark {
      --bs-navbar-color: #{rgba(#ffffff, 0.85)};
      --bs-navbar-hover-color: #ffffff;
      --bs-navbar-brand-color: #ffffff;
      --bs-navbar-brand-hover-color: #ffffff;
      --bs-navbar-toggler-border-color: #{rgba(#ffffff, 0.1)};
      --bs-navbar-toggler-icon-bg: #{escape-svg(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='#{rgba(#ffffff, 0.85)}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"))};
    }
  }
  
  // 模态框
  .modal {
    --bs-modal-bg: #{map-get($dark-theme-grays, "200")};
    --bs-modal-border-color: #{map-get($dark-theme-grays, "300")};
    --bs-modal-header-border-color: #{map-get($dark-theme-grays, "300")};
    --bs-modal-footer-border-color: #{map-get($dark-theme-grays, "300")};
  }
  
  // 下拉菜单
  .dropdown-menu {
    --bs-dropdown-bg: #{map-get($dark-theme-grays, "200")};
    --bs-dropdown-border-color: #{map-get($dark-theme-grays, "300")};
    --bs-dropdown-link-color: #{map-get($dark-theme-grays, "900")};
    --bs-dropdown-link-hover-color: #ffffff;
    --bs-dropdown-link-hover-bg: #{map-get($dark-theme-grays, "400")};
  }
  
  // 表格
  .table {
    --bs-table-bg: transparent;
    --bs-table-border-color: #{map-get($dark-theme-grays, "300")};
    --bs-table-striped-bg: #{rgba(#ffffff, 0.05)};
    --bs-table-hover-bg: #{rgba(#ffffff, 0.075)};
  }
  
  // 警告框
  .alert {
    &.alert-primary {
      --bs-alert-color: #{tint-color(map-get($dark-theme-colors, "primary"), 40%)};
      --bs-alert-bg: #{rgba(map-get($dark-theme-colors, "primary"), 0.15)};
      --bs-alert-border-color: #{rgba(map-get($dark-theme-colors, "primary"), 0.2)};
    }
    
    &.alert-success {
      --bs-alert-color: #{tint-color(map-get($dark-theme-colors, "success"), 40%)};
      --bs-alert-bg: #{rgba(map-get($dark-theme-colors, "success"), 0.15)};
      --bs-alert-border-color: #{rgba(map-get($dark-theme-colors, "success"), 0.2)};
    }
    
    &.alert-warning {
      --bs-alert-color: #{tint-color(map-get($dark-theme-colors, "warning"), 40%)};
      --bs-alert-bg: #{rgba(map-get($dark-theme-colors, "warning"), 0.15)};
      --bs-alert-border-color: #{rgba(map-get($dark-theme-colors, "warning"), 0.2)};
    }
    
    &.alert-danger {
      --bs-alert-color: #{tint-color(map-get($dark-theme-colors, "danger"), 40%)};
      --bs-alert-bg: #{rgba(map-get($dark-theme-colors, "danger"), 0.15)};
      --bs-alert-border-color: #{rgba(map-get($dark-theme-colors, "danger"), 0.2)};
    }
  }
}

// 深色主题切换器
.theme-toggle {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 1050;
  
  .btn {
    border-radius: 50%;
    width: 50px;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    @include box-shadow(0 4px 8px rgba($black, 0.15));
    
    .icon {
      width: 20px;
      height: 20px;
      transition: transform 0.3s ease;
    }
    
    &:hover .icon {
      transform: scale(1.1);
    }
  }
}

// 深色主题动画
@keyframes theme-transition {
  0% {
    opacity: 0;
    transform: scale(0.95);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

[data-bs-theme="dark"] {
  animation: theme-transition 0.3s ease;
}

2. 企业主题

// _corporate-theme.scss
// 企业主题定制

// 企业主题颜色
$corporate-primary: #003366;      // 深蓝色
$corporate-secondary: #666666;    // 中灰色
$corporate-accent: #ff6b35;       // 橙色强调
$corporate-success: #28a745;      // 绿色
$corporate-warning: #ffc107;      // 黄色
$corporate-danger: #dc3545;       // 红色
$corporate-light: #f8f9fa;        // 浅灰色
$corporate-dark: #343a40;         // 深灰色

// 企业主题字体
$corporate-font-family: "Roboto", "Helvetica Neue", Arial, sans-serif;
$corporate-heading-font-family: "Roboto Slab", serif;

// 企业主题样式
.theme-corporate {
  // 全局字体
  font-family: $corporate-font-family;
  
  // 标题字体
  h1, h2, h3, h4, h5, h6,
  .h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: $corporate-heading-font-family;
    font-weight: 600;
    color: $corporate-primary;
  }
  
  // 主色调按钮
  .btn-primary {
    @include button-variant-custom(
      $corporate-primary,
      $corporate-primary,
      #ffffff,
      shade-color($corporate-primary, 15%),
      shade-color($corporate-primary, 20%),
      #ffffff
    );
  }
  
  // 强调色按钮
  .btn-accent {
    @include button-variant-custom(
      $corporate-accent,
      $corporate-accent,
      #ffffff,
      shade-color($corporate-accent, 15%),
      shade-color($corporate-accent, 20%),
      #ffffff
    );
  }
  
  // 导航栏样式
  .navbar {
    &.navbar-corporate {
      background: linear-gradient(135deg, $corporate-primary 0%, shade-color($corporate-primary, 20%) 100%);
      box-shadow: 0 2px 4px rgba($black, 0.1);
      
      .navbar-brand {
        font-family: $corporate-heading-font-family;
        font-weight: 700;
        font-size: 1.5rem;
        color: #ffffff !important;
        
        &:hover {
          color: tint-color($corporate-primary, 80%) !important;
        }
      }
      
      .navbar-nav {
        .nav-link {
          color: rgba(#ffffff, 0.9) !important;
          font-weight: 500;
          transition: all 0.3s ease;
          
          &:hover,
          &:focus {
            color: #ffffff !important;
            background-color: rgba(#ffffff, 0.1);
            border-radius: $border-radius;
          }
          
          &.active {
            color: #ffffff !important;
            background-color: rgba(#ffffff, 0.15);
            border-radius: $border-radius;
          }
        }
      }
    }
  }
  
  // 卡片样式
  .card {
    &.card-corporate {
      border: none;
      @include card-shadow(2);
      transition: all 0.3s ease;
      
      &:hover {
        @include card-shadow(3);
        transform: translateY(-2px);
      }
      
      .card-header {
        background: linear-gradient(135deg, $corporate-primary 0%, shade-color($corporate-primary, 10%) 100%);
        color: #ffffff;
        font-weight: 600;
        border-bottom: none;
        
        h1, h2, h3, h4, h5, h6,
        .h1, .h2, .h3, .h4, .h5, .h6 {
          color: #ffffff;
          margin-bottom: 0;
        }
      }
      
      .card-footer {
        background-color: $corporate-light;
        border-top: 1px solid rgba($corporate-primary, 0.1);
      }
    }
  }
  
  // 表单样式
  .form-control {
    &:focus {
      border-color: $corporate-primary;
      box-shadow: 0 0 0 0.25rem rgba($corporate-primary, 0.25);
    }
  }
  
  .form-check-input {
    &:checked {
      background-color: $corporate-primary;
      border-color: $corporate-primary;
    }
    
    &:focus {
      box-shadow: 0 0 0 0.25rem rgba($corporate-primary, 0.25);
    }
  }
  
  // 警告框样式
  .alert {
    &.alert-corporate {
      color: #ffffff;
      background: linear-gradient(135deg, $corporate-primary 0%, shade-color($corporate-primary, 15%) 100%);
      border: none;
      
      .alert-link {
        color: tint-color($corporate-primary, 80%);
      }
    }
  }
  
  // 进度条样式
  .progress {
    .progress-bar {
      &.bg-corporate {
        background: linear-gradient(90deg, $corporate-primary 0%, $corporate-accent 100%);
      }
    }
  }
  
  // 徽章样式
  .badge {
    &.bg-corporate {
      background: linear-gradient(135deg, $corporate-primary 0%, shade-color($corporate-primary, 15%) 100%);
    }
    
    &.bg-accent {
      background-color: $corporate-accent;
    }
  }
  
  // 分页样式
  .pagination {
    .page-link {
      color: $corporate-primary;
      
      &:hover {
        color: shade-color($corporate-primary, 15%);
        background-color: tint-color($corporate-primary, 90%);
        border-color: $corporate-primary;
      }
    }
    
    .page-item {
      &.active .page-link {
        background-color: $corporate-primary;
        border-color: $corporate-primary;
      }
    }
  }
  
  // 面包屑样式
  .breadcrumb {
    .breadcrumb-item {
      &.active {
        color: $corporate-primary;
      }
      
      a {
        color: $corporate-secondary;
        text-decoration: none;
        
        &:hover {
          color: $corporate-primary;
        }
      }
    }
  }
}

// 企业主题工具类
.text-corporate {
  color: $corporate-primary !important;
}

.text-accent {
  color: $corporate-accent !important;
}

.bg-corporate {
  background-color: $corporate-primary !important;
}

.bg-accent {
  background-color: $corporate-accent !important;
}

.border-corporate {
  border-color: $corporate-primary !important;
}

.border-accent {
  border-color: $corporate-accent !important;
}

3. 现代主题

// _modern-theme.scss
// 现代主题定制

// 现代主题颜色
$modern-primary: #6366f1;         // 靛蓝色
$modern-secondary: #64748b;       // 石板灰
$modern-accent: #f59e0b;          // 琥珀色
$modern-success: #10b981;         // 翠绿色
$modern-warning: #f59e0b;         // 琥珀色
$modern-danger: #ef4444;          // 红色
$modern-light: #f8fafc;           // 极浅灰
$modern-dark: #0f172a;            // 极深蓝

// 现代主题渐变
$modern-gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
$modern-gradient-secondary: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
$modern-gradient-success: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
$modern-gradient-warning: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
$modern-gradient-danger: linear-gradient(135deg, #fa709a 0%, #fee140 100%);

// 现代主题字体
$modern-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
$modern-heading-font-family: "Poppins", $modern-font-family;

// 现代主题样式
.theme-modern {
  // 全局字体
  font-family: $modern-font-family;
  line-height: 1.6;
  
  // 标题字体
  h1, h2, h3, h4, h5, h6,
  .h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: $modern-heading-font-family;
    font-weight: 600;
    letter-spacing: -0.025em;
  }
  
  // 现代按钮样式
  .btn {
    font-weight: 500;
    letter-spacing: 0.025em;
    border-radius: 0.5rem;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    
    &.btn-modern-primary {
      background: $modern-gradient-primary;
      border: none;
      color: #ffffff;
      
      &:hover {
        transform: translateY(-1px);
        box-shadow: 0 10px 25px rgba($modern-primary, 0.3);
      }
      
      &:active {
        transform: translateY(0);
      }
    }
    
    &.btn-modern-glass {
      background: rgba(#ffffff, 0.1);
      backdrop-filter: blur(10px);
      border: 1px solid rgba(#ffffff, 0.2);
      color: #ffffff;
      
      &:hover {
        background: rgba(#ffffff, 0.2);
        border-color: rgba(#ffffff, 0.3);
      }
    }
    
    &.btn-modern-outline {
      background: transparent;
      border: 2px solid $modern-primary;
      color: $modern-primary;
      position: relative;
      overflow: hidden;
      
      &::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: $modern-gradient-primary;
        transition: left 0.3s ease;
        z-index: -1;
      }
      
      &:hover {
        color: #ffffff;
        border-color: transparent;
        
        &::before {
          left: 0;
        }
      }
    }
  }
  
  // 现代卡片样式
  .card {
    &.card-modern {
      border: none;
      border-radius: 1rem;
      background: rgba(#ffffff, 0.8);
      backdrop-filter: blur(20px);
      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      
      &:hover {
        transform: translateY(-4px);
        box-shadow: 0 20px 40px rgba(31, 38, 135, 0.5);
      }
      
      .card-header {
        background: transparent;
        border-bottom: 1px solid rgba($modern-primary, 0.1);
        border-radius: 1rem 1rem 0 0;
      }
      
      .card-footer {
        background: transparent;
        border-top: 1px solid rgba($modern-primary, 0.1);
        border-radius: 0 0 1rem 1rem;
      }
    }
    
    &.card-gradient {
      background: $modern-gradient-primary;
      color: #ffffff;
      border: none;
      
      .card-header,
      .card-footer {
        background: transparent;
        border-color: rgba(#ffffff, 0.2);
      }
    }
  }
  
  // 现代导航栏
  .navbar {
    &.navbar-modern {
      background: rgba(#ffffff, 0.9);
      backdrop-filter: blur(20px);
      border-bottom: 1px solid rgba($modern-primary, 0.1);
      
      .navbar-brand {
        font-family: $modern-heading-font-family;
        font-weight: 700;
        background: $modern-gradient-primary;
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
      }
      
      .navbar-nav {
        .nav-link {
          font-weight: 500;
          color: $modern-dark;
          position: relative;
          
          &::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            width: 0;
            height: 2px;
            background: $modern-gradient-primary;
            transition: all 0.3s ease;
            transform: translateX(-50%);
          }
          
          &:hover,
          &.active {
            &::after {
              width: 100%;
            }
          }
        }
      }
    }
  }
  
  // 现代表单
  .form-control {
    &.form-control-modern {
      border: 2px solid rgba($modern-primary, 0.1);
      border-radius: 0.75rem;
      padding: 0.75rem 1rem;
      transition: all 0.2s ease;
      
      &:focus {
        border-color: $modern-primary;
        box-shadow: 0 0 0 3px rgba($modern-primary, 0.1);
        transform: translateY(-1px);
      }
    }
  }
  
  // 现代模态框
  .modal {
    &.modal-modern {
      .modal-content {
        border: none;
        border-radius: 1.5rem;
        background: rgba(#ffffff, 0.9);
        backdrop-filter: blur(20px);
        box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
        
        .modal-header {
          border-bottom: 1px solid rgba($modern-primary, 0.1);
          border-radius: 1.5rem 1.5rem 0 0;
          
          .modal-title {
            background: $modern-gradient-primary;
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
          }
        }
        
        .modal-footer {
          border-top: 1px solid rgba($modern-primary, 0.1);
          border-radius: 0 0 1.5rem 1.5rem;
        }
      }
    }
  }
  
  // 现代警告框
  .alert {
    &.alert-modern {
      border: none;
      border-radius: 1rem;
      border-left: 4px solid $modern-primary;
      background: linear-gradient(135deg, rgba($modern-primary, 0.1) 0%, rgba($modern-primary, 0.05) 100%);
      
      &.alert-success {
        border-left-color: $modern-success;
        background: linear-gradient(135deg, rgba($modern-success, 0.1) 0%, rgba($modern-success, 0.05) 100%);
      }
      
      &.alert-warning {
        border-left-color: $modern-warning;
        background: linear-gradient(135deg, rgba($modern-warning, 0.1) 0%, rgba($modern-warning, 0.05) 100%);
      }
      
      &.alert-danger {
        border-left-color: $modern-danger;
        background: linear-gradient(135deg, rgba($modern-danger, 0.1) 0%, rgba($modern-danger, 0.05) 100%);
      }
    }
  }
  
  // 现代进度条
  .progress {
    &.progress-modern {
      height: 0.75rem;
      border-radius: 1rem;
      background-color: rgba($modern-primary, 0.1);
      
      .progress-bar {
        background: $modern-gradient-primary;
        border-radius: 1rem;
        position: relative;
        overflow: hidden;
        
        &::after {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background: linear-gradient(90deg, transparent, rgba(#ffffff, 0.3), transparent);
          animation: shimmer 2s infinite;
        }
      }
    }
  }
}

// 现代主题动画
@keyframes shimmer {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

@keyframes float {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-10px);
  }
}

// 现代主题工具类
.gradient-text {
  background: $modern-gradient-primary;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.glass-effect {
  background: rgba(#ffffff, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(#ffffff, 0.2);
}

.floating-animation {
  animation: float 3s ease-in-out infinite;
}

组件样式定制

1. 自定义组件样式

”`scss // _custom-components.scss // 自定义组件样式

// 自定义按钮组件 .btn-custom { // 3D 按钮效果 &.btn-3d { position: relative; transform-style: preserve-3d; transition: all 0.2s ease;

&::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: inherit;
  transform: translateZ(-4px) translateY(4px);
  filter: brightness(0.8);
  border-radius: inherit;
}

&:hover {
  transform: translateY(-2px);
}

&:active {
  transform: translateY(0);
}

}

// 霓虹按钮效果 &.btn-neon { background: transparent; border: 2px solid $primary; color: $primary; text-shadow: 0 0 10px $primary; box-shadow: 0 0 10px $primary, inset 0 0 10px transparent; transition: all 0.3s ease;

&:hover {
  background: $primary;
  color: #ffffff;
  text-shadow: 0 0 20px #ffffff;
  box-shadow: 
    0 0 20px $primary,
    0 0 40px $primary,
    inset 0 0 20px rgba($primary, 0.2);
}

}

// 液体按钮效果 &.btn-liquid { position: relative; overflow: hidden;

&::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  background: rgba(#ffffff, 0.3);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition: width 0.6s ease, height 0.6s ease;
}

&:hover::before {
  width: 300px;
  height: 300px;
}

} }

// 自定义卡片组件 .card-custom { // 翻转卡片 &.card-flip { perspective: 1000px; height: 300px;

.card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  text-align: center;
  transition: transform 0.6s;
  transform-style: preserve-3d;
}

&:hover .card-inner {
  transform: rotateY(180deg);
}

.card-front,
.card-back {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  border-radius: $border-radius;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.card-back {
  transform: rotateY(180deg);
  background: $primary;
  color: #ffffff;
}

}

// 悬浮卡片 &.card-hover { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: pointer;

&:hover {
  transform: translateY(-8px) scale(1.02);
  box-shadow: 0 20px 40px rgba($black, 0.15);

  .card-img-top {
    transform: scale(1.1);
  }
}

.card-img-top {
  transition: transform 0.3s ease;
  overflow: hidden;
}

}

// 渐变边框卡片 &.card-gradient-border { position: relative; background: #ffffff; border: none;

&::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 2px;
  background: linear-gradient(45deg, $primary, $secondary, $success);
  border-radius: inherit;
  mask: linear-gradient(#ffffff 0 0) content-box, linear-gradient(#ffffff 0 0);
  mask-composite: exclude;
}

} }

// 自定义导航组件 .navbar-custom { // 滚动时变化的导航栏 &.navbar-scroll { transition: all 0.3s ease;

&.scrolled {
  background-color: rgba(#ffffff, 0.95) !important;
  backdrop-filter: blur(10px);
  box-shadow: 0 2px 20px rgba($black, 0.1);

  .navbar-brand {
    transform: scale(0.9);
  }

  .navbar-nav .nav-link {
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
  }
}

}

// 动画导航链接 .nav-link-animated { position: relative; overflow: hidden;

&::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba($primary, 0.1), transparent);
  transition: left 0.5s ease;
}

&:hover::before {
  left: 100%;
}

} }

// 自定义表单组件 .form-custom { // 浮动标签 .form-floating-custom { position: relative;

.form-control {
  padding-top: 1.625rem;
  padding-bottom: 0.625rem;

  &:focus,
  &:not(:placeholder-shown) {
    ~ label {
      opacity: 0.65;
      transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
    }
  }
}

label {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  padding: 1rem 0.75rem;
  pointer-events: none;
  border: 1px solid transparent;
  transform-origin: 0 0;
  transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
}

}

// 动画复选框 .form-check-animated { .form-check-input { position: relative;

  &:checked {
    &::after {
      content: '✓';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #ffffff;
      font-size: 0.75rem;
      animation: checkmark 0.3s ease;
    }
  }
}

} }

// 自定义模态框组件 .modal-custom { // 全屏模态框 &.modal-fullscreen-custom { .modal-dialog { margin: 0; width: 100vw; height: 100vh; max-width: none;

  .modal-content {
    height: 100vh;
    border: none;
    border-radius: 0;
  }
}

}

// 侧边滑入模态框 &.modal-slide { .modal-dialog { position: fixed; top: 0; right: 0; margin: 0; width: 400px; height: 100vh; transform: translateX(100%); transition: transform 0.3s ease;

  .modal-content {
    height: 100vh;
    border: none;
    border-radius: 0;
  }
}

&.show .modal-dialog {
  transform: translateX(0);
}

} }

// 自定义进度条组件 .progress-custom { // 条纹动画进度条 &.progress-striped-animated { .progress-bar { background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-size: 1rem 1rem; animation: progress-bar-stripes 1s linear infinite; } }

// 圆形进度条 &.progress-circle { width: 120px; height: 120px; border-radius: 50%; background: conic-gradient(from 0deg, $primary 0deg, $primary var(–progress, 0deg), $gray-200 var(–progress, 0deg)); display: flex; align-items: center; justify-content: center; position: relative;

&::before {
  content: '';
  position: absolute;
  width: 80%;
  height: 80%;
  background: #ffffff;
  border-radius: 50%;
}

.progress-text {
  position: relative;
  z-index: 1;
  font-weight: bold;
  font-size: 1.25rem;
}

}