src/assets/styles/
├── index.scss # 主入口文件
├── variables.scss # 全局CSS变量定义
├── mixins.scss # SCSS混入
├── reset.scss # 样式重置
└── theme/
├── light.scss # 亮色主题
└── dark.scss # 暗色主题
@use './theme/dark.scss';
@use './theme/light.scss';
@use './reset.scss';
@use './mixins.scss';
@use './variables.scss';
项目建立了完整的CSS变量系统,包括:
采用BEM命名规范,使用ms-
前缀:
--ms-color-primary
: 主色调--ms-font-size-base
: 基础字体大小--ms-border-radius-base
: 基础圆角主题切换功能基于以下技术实现:
// 亮色主题
[data-theme="light"] {
--ms-bg-color: #ffffff;
--ms-text-color-primary: #303133;
// ... 其他变量
}
// 暗色主题
[data-theme="dark"] {
--ms-bg-color: #141414;
--ms-text-color-primary: #e5eaf3;
// ... 其他变量
}
// src/utils/theme.ts
export function setTheme(theme: ThemeType): void {
// 保存到localStorage
localStorage.setItem(THEME_KEY, theme);
// 设置HTML属性
document.documentElement.setAttribute('data-theme', theme);
// 触发主题变化事件
window.dispatchEvent(new CustomEvent('theme-change', { detail: { theme } }));
}
// src/main.ts
import { getCurrentTheme } from './utils/theme'
// 初始化主题
const theme = getCurrentTheme();
document.documentElement.setAttribute('data-theme', theme);
prefers-color-scheme
媒体查询export function watchSystemTheme(): (() => void) | undefined {
if (window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = (e: MediaQueryListEvent) => {
const newTheme: ThemeType = e.matches ? 'dark' : 'light';
// 只有在没有手动设置主题时才跟随系统
if (!localStorage.getItem(THEME_KEY)) {
setTheme(newTheme);
}
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}
return undefined;
}
// src/components/button/Button.scss
.ms-button {
--ms-button-font-weight: var(--ms-font-weight-primary);
--ms-button-border-color: var(--ms-border-color);
--ms-button-bg-color: var(--ms-fill-color-blank);
--ms-button-text-color: var(--ms-text-color-regular);
// ... 其他变量
color: var(--ms-button-text-color);
background-color: var(--ms-button-bg-color);
border-color: var(--ms-button-border-color);
transition: 0.1s;
}
项目采用了Element UI的色彩系统,包括:
每个语义化颜色都有多个变体:
--ms-color-primary-light-3
: 浅色变体--ms-color-primary-light-5
: 更浅色变体--ms-color-primary-light-7
: 最浅色变体--ms-color-primary-dark-2
: 深色变体主题切换时提供平滑的过渡效果:
.app-container {
transition: background-color var(--ms-transition-duration);
}
.theme-switch {
transition: all var(--ms-transition-duration);
}
PostCSS 是一个强大的 CSS 处理工具,可以通过插件链实现自动加前缀、现代特性降级、压缩优化等功能。
在你的项目中,PostCSS 主要负责:
postcss.config.cjs
module.exports = {
plugins: [
require('postcss-flexbugs-fixes'),
require('autoprefixer'),
require('postcss-preset-env')({
stage: 1,
features: {
'nesting-rules': true
}
}),
require('cssnano')({ preset: 'default' })
]
}
.browserslistrc
>1%
last 20 versions
not dead
not ie 11
autoprefixer:根据 .browserslistrc 自动为 CSS 添加 -webkit-、-ms- 等前缀,保证兼容主流浏览器。
postcss-preset-env:让你可以直接写现代 CSS(如嵌套、逻辑属性、容器查询等),自动降级为目标浏览器支持的语法。
postcss-flexbugs-fixes:修复 flexbox 在部分浏览器下的已知 bug。
cssnano:生产环境下压缩 CSS,移除注释、空格、重复代码等,极大减小体积。
指定目标浏览器范围,autoprefixer 和 postcss-preset-env 会据此决定哪些特性需要降级、哪些前缀需要添加。
开发时
你可以直接使用现代 CSS 语法和特性(如嵌套、变量、容器查询等),无需手动添加前缀或考虑兼容性。
构建时(npm run build)
验证
开发时写法:
.delete-button {
display: flex;
user-select: none;
&:hover {
color: var(--ms-primary);
}
}
构建后产物:
.delete-button {
display: flex;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none
}
.delete-button:hover {
color: var(--ms-primary)
}