scss-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSCSS Best Practices
SCSS 最佳实践
You are an expert in SCSS (Sassy CSS), CSS architecture, and maintainable stylesheet development.
您是SCSS(Sassy CSS)、CSS架构和可维护样式表开发领域的专家。
Key Principles
核心原则
- Write modular, reusable SCSS that scales with project complexity
- Follow the DRY (Don't Repeat Yourself) principle using variables, mixins, and functions
- Maintain clear separation between structure, skin, and state styles
- Prioritize readability and maintainability over clever abstractions
- 编写模块化、可复用的SCSS,以适应项目复杂度的增长
- 遵循DRY(Don't Repeat Yourself,不重复造轮子)原则,使用变量、混合宏(mixins)和函数
- 清晰区分结构、外观和状态样式
- 优先考虑可读性和可维护性,而非巧妙的抽象
File Organization
文件组织
Architecture Pattern (7-1 Pattern)
架构模式(7-1模式)
scss/
├── abstracts/
│ ├── _variables.scss # Global variables
│ ├── _functions.scss # SCSS functions
│ ├── _mixins.scss # Reusable mixins
│ └── _placeholders.scss # Extendable placeholders
├── base/
│ ├── _reset.scss # CSS reset/normalize
│ ├── _typography.scss # Typography rules
│ └── _base.scss # Base element styles
├── components/
│ ├── _buttons.scss # Button components
│ ├── _cards.scss # Card components
│ └── _forms.scss # Form components
├── layout/
│ ├── _header.scss # Header layout
│ ├── _footer.scss # Footer layout
│ ├── _grid.scss # Grid system
│ └── _navigation.scss # Navigation layout
├── pages/
│ ├── _home.scss # Home page specific
│ └── _contact.scss # Contact page specific
├── themes/
│ └── _default.scss # Default theme
├── vendors/
│ └── _bootstrap.scss # Third-party overrides
└── main.scss # Main manifest filescss/
├── abstracts/
│ ├── _variables.scss # 全局变量
│ ├── _functions.scss # SCSS函数
│ ├── _mixins.scss # 可复用混合宏
│ └── _placeholders.scss # 可继承占位符
├── base/
│ ├── _reset.scss # CSS重置/标准化
│ ├── _typography.scss # 排版规则
│ └── _base.scss # 基础元素样式
├── components/
│ ├── _buttons.scss # 按钮组件
│ ├── _cards.scss # 卡片组件
│ └── _forms.scss # 表单组件
├── layout/
│ ├── _header.scss # 头部布局
│ ├── _footer.scss # 底部布局
│ ├── _grid.scss # 网格系统
│ └── _navigation.scss # 导航布局
├── pages/
│ ├── _home.scss # 首页专属样式
│ └── _contact.scss # 联系页专属样式
├── themes/
│ └── _default.scss # 默认主题
├── vendors/
│ └── _bootstrap.scss # 第三方库重写
└── main.scss # 主入口文件Import Order
导入顺序
scss
// main.scss
@use 'abstracts/variables';
@use 'abstracts/functions';
@use 'abstracts/mixins';
@use 'abstracts/placeholders';
@use 'vendors/normalize';
@use 'base/reset';
@use 'base/typography';
@use 'base/base';
@use 'layout/grid';
@use 'layout/header';
@use 'layout/navigation';
@use 'layout/footer';
@use 'components/buttons';
@use 'components/cards';
@use 'components/forms';
@use 'pages/home';
@use 'themes/default';scss
// main.scss
@use 'abstracts/variables';
@use 'abstracts/functions';
@use 'abstracts/mixins';
@use 'abstracts/placeholders';
@use 'vendors/normalize';
@use 'base/reset';
@use 'base/typography';
@use 'base/base';
@use 'layout/grid';
@use 'layout/header';
@use 'layout/navigation';
@use 'layout/footer';
@use 'components/buttons';
@use 'components/cards';
@use 'components/forms';
@use 'pages/home';
@use 'themes/default';Variables
变量
Naming Convention
命名规范
scss
// Use semantic, descriptive names
// Format: $category-property-variant
// Colors
$color-primary: #3498db;
$color-primary-light: lighten($color-primary, 15%);
$color-primary-dark: darken($color-primary, 15%);
$color-secondary: #2ecc71;
$color-text: #333333;
$color-text-muted: #666666;
$color-background: #ffffff;
$color-border: #e0e0e0;
$color-error: #e74c3c;
$color-success: #27ae60;
$color-warning: #f39c12;
// Typography
$font-family-base: 'Helvetica Neue', Arial, sans-serif;
$font-family-heading: 'Georgia', serif;
$font-size-base: 1rem;
$font-size-small: 0.875rem;
$font-size-large: 1.25rem;
$font-weight-normal: 400;
$font-weight-bold: 700;
$line-height-base: 1.5;
// Spacing (use consistent scale)
$spacing-unit: 8px;
$spacing-xs: $spacing-unit * 0.5; // 4px
$spacing-sm: $spacing-unit; // 8px
$spacing-md: $spacing-unit * 2; // 16px
$spacing-lg: $spacing-unit * 3; // 24px
$spacing-xl: $spacing-unit * 4; // 32px
$spacing-xxl: $spacing-unit * 6; // 48px
// Breakpoints
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
$breakpoint-xxl: 1400px;
// Z-index scale
$z-index-dropdown: 1000;
$z-index-sticky: 1020;
$z-index-fixed: 1030;
$z-index-modal-backdrop: 1040;
$z-index-modal: 1050;
$z-index-popover: 1060;
$z-index-tooltip: 1070;
// Transitions
$transition-base: 0.3s ease;
$transition-fast: 0.15s ease;
$transition-slow: 0.5s ease;
// Border radius
$border-radius-sm: 2px;
$border-radius-md: 4px;
$border-radius-lg: 8px;
$border-radius-pill: 50px;
$border-radius-circle: 50%;
// Shadows
$shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
$shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
$shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);scss
// 使用语义化、描述性名称
// 格式:$类别-属性-变体
// 颜色
$color-primary: #3498db;
$color-primary-light: lighten($color-primary, 15%);
$color-primary-dark: darken($color-primary, 15%);
$color-secondary: #2ecc71;
$color-text: #333333;
$color-text-muted: #666666;
$color-background: #ffffff;
$color-border: #e0e0e0;
$color-error: #e74c3c;
$color-success: #27ae60;
$color-warning: #f39c12;
// 排版
$font-family-base: 'Helvetica Neue', Arial, sans-serif;
$font-family-heading: 'Georgia', serif;
$font-size-base: 1rem;
$font-size-small: 0.875rem;
$font-size-large: 1.25rem;
$font-weight-normal: 400;
$font-weight-bold: 700;
$line-height-base: 1.5;
// 间距(使用统一比例)
$spacing-unit: 8px;
$spacing-xs: $spacing-unit * 0.5; // 4px
$spacing-sm: $spacing-unit; // 8px
$spacing-md: $spacing-unit * 2; // 16px
$spacing-lg: $spacing-unit * 3; // 24px
$spacing-xl: $spacing-unit * 4; // 32px
$spacing-xxl: $spacing-unit * 6; // 48px
// 断点
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
$breakpoint-xxl: 1400px;
// Z-index层级
$z-index-dropdown: 1000;
$z-index-sticky: 1020;
$z-index-fixed: 1030;
$z-index-modal-backdrop: 1040;
$z-index-modal: 1050;
$z-index-popover: 1060;
$z-index-tooltip: 1070;
// 过渡动画
$transition-base: 0.3s ease;
$transition-fast: 0.15s ease;
$transition-slow: 0.5s ease;
// 圆角
$border-radius-sm: 2px;
$border-radius-md: 4px;
$border-radius-lg: 8px;
$border-radius-pill: 50px;
$border-radius-circle: 50%;
// 阴影
$shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
$shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
$shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);Maps for Related Values
关联值使用映射表
scss
// Use maps for grouped values
$colors: (
'primary': #3498db,
'secondary': #2ecc71,
'danger': #e74c3c,
'warning': #f39c12,
'info': #17a2b8,
'success': #27ae60
);
$breakpoints: (
'sm': 576px,
'md': 768px,
'lg': 992px,
'xl': 1200px,
'xxl': 1400px
);
// Access with map-get
.element {
color: map-get($colors, 'primary');
}scss
// 使用映射表分组相关值
$colors: (
'primary': #3498db,
'secondary': #2ecc71,
'danger': #e74c3c,
'warning': #f39c12,
'info': #17a2b8,
'success': #27ae60
);
$breakpoints: (
'sm': 576px,
'md': 768px,
'lg': 992px,
'xl': 1200px,
'xxl': 1400px
);
// 使用map-get访问
.element {
color: map-get($colors, 'primary');
}Mixins
混合宏(Mixins)
Responsive Breakpoints
响应式断点
scss
@mixin respond-to($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
@media (min-width: map-get($breakpoints, $breakpoint)) {
@content;
}
} @else {
@warn "Unknown breakpoint: #{$breakpoint}";
}
}
// Usage
.element {
width: 100%;
@include respond-to('md') {
width: 50%;
}
@include respond-to('lg') {
width: 33.333%;
}
}scss
@mixin respond-to($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
@media (min-width: map-get($breakpoints, $breakpoint)) {
@content;
}
} @else {
@warn "Unknown breakpoint: #{$breakpoint}";
}
}
// 使用示例
.element {
width: 100%;
@include respond-to('md') {
width: 50%;
}
@include respond-to('lg') {
width: 33.333%;
}
}Flexbox Utilities
Flexbox工具类
scss
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
@mixin flex-column {
display: flex;
flex-direction: column;
}scss
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
@mixin flex-column {
display: flex;
flex-direction: column;
}Typography
排版
scss
@mixin font-size($size, $line-height: null) {
font-size: $size;
@if $line-height {
line-height: $line-height;
}
}
@mixin truncate($lines: 1) {
@if $lines == 1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} @else {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
}scss
@mixin font-size($size, $line-height: null) {
font-size: $size;
@if $line-height {
line-height: $line-height;
}
}
@mixin truncate($lines: 1) {
@if $lines == 1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} @else {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
}Accessibility
无障碍访问
scss
@mixin visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@mixin focus-visible {
&:focus-visible {
outline: 2px solid $color-primary;
outline-offset: 2px;
}
}scss
@mixin visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@mixin focus-visible {
&:focus-visible {
outline: 2px solid $color-primary;
outline-offset: 2px;
}
}BEM Naming Convention
BEM命名规范
Structure
结构
scss
// Block: Standalone component
// Element: Part of block (block__element)
// Modifier: Variant (block--modifier or block__element--modifier)
.card {
// Block styles
background: $color-background;
border-radius: $border-radius-md;
box-shadow: $shadow-md;
// Element
&__header {
padding: $spacing-md;
border-bottom: 1px solid $color-border;
}
&__title {
margin: 0;
font-size: $font-size-large;
font-weight: $font-weight-bold;
}
&__body {
padding: $spacing-md;
}
&__footer {
padding: $spacing-md;
border-top: 1px solid $color-border;
}
// Modifier
&--featured {
border: 2px solid $color-primary;
}
&--compact {
.card__header,
.card__body,
.card__footer {
padding: $spacing-sm;
}
}
}scss
// 块(Block):独立组件
// 元素(Element):块的组成部分(block__element)
// 修饰符(Modifier):变体(block--modifier 或 block__element--modifier)
.card {
// 块样式
background: $color-background;
border-radius: $border-radius-md;
box-shadow: $shadow-md;
// 元素
&__header {
padding: $spacing-md;
border-bottom: 1px solid $color-border;
}
&__title {
margin: 0;
font-size: $font-size-large;
font-weight: $font-weight-bold;
}
&__body {
padding: $spacing-md;
}
&__footer {
padding: $spacing-md;
border-top: 1px solid $color-border;
}
// 修饰符
&--featured {
border: 2px solid $color-primary;
}
&--compact {
.card__header,
.card__body,
.card__footer {
padding: $spacing-sm;
}
}
}Nesting Rules
嵌套规则
Maximum Nesting Depth
最大嵌套深度
scss
// BAD: Too deep nesting
.nav {
.nav-list {
.nav-item {
.nav-link {
.nav-icon {
// 5 levels deep - avoid this
}
}
}
}
}
// GOOD: Keep nesting to 3 levels maximum
.nav {
// Level 1
}
.nav__list {
// Level 1
}
.nav__item {
// Level 1
}
.nav__link {
color: $color-text;
&:hover,
&:focus {
// Level 2 - acceptable for states
color: $color-primary;
}
&--active {
// Level 2 - acceptable for modifiers
color: $color-primary;
font-weight: $font-weight-bold;
}
}scss
// 不良示例:嵌套过深
.nav {
.nav-list {
.nav-item {
.nav-link {
.nav-icon {
// 嵌套5层 - 避免这种写法
}
}
}
}
}
// 良好示例:嵌套最多3层
.nav {
// 第1层
}
.nav__list {
// 第1层
}
.nav__item {
// 第1层
}
.nav__link {
color: $color-text;
&:hover,
&:focus {
// 第2层 - 状态嵌套是可接受的
color: $color-primary;
}
&--active {
// 第2层 - 修饰符嵌套是可接受的
color: $color-primary;
font-weight: $font-weight-bold;
}
}Acceptable Nesting
可接受的嵌套场景
scss
.component {
// Direct child pseudo-elements
&::before,
&::after {
content: '';
}
// State modifiers
&:hover,
&:focus,
&:active {
// State styles
}
// BEM modifiers
&--variant {
// Modifier styles
}
// Media queries
@include respond-to('md') {
// Responsive styles
}
}scss
.component {
// 直接子元素的伪元素
&::before,
&::after {
content: '';
}
// 状态修饰符
&:hover,
&:focus,
&:active {
// 状态样式
}
// BEM修饰符
&--variant {
// 修饰符样式
}
// 媒体查询
@include respond-to('md') {
// 响应式样式
}
}Functions
函数
Color Functions
颜色函数
scss
@function tint($color, $percentage) {
@return mix(white, $color, $percentage);
}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
// Usage
.element {
background: tint($color-primary, 20%);
border-color: shade($color-primary, 10%);
}scss
@function tint($color, $percentage) {
@return mix(white, $color, $percentage);
}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
// 使用示例
.element {
background: tint($color-primary, 20%);
border-color: shade($color-primary, 10%);
}Unit Conversion
单位转换
scss
@function px-to-rem($px, $base: 16) {
@return ($px / $base) * 1rem;
}
@function rem-to-px($rem, $base: 16) {
@return ($rem / 1rem) * $base * 1px;
}
// Usage
.element {
font-size: px-to-rem(18); // 1.125rem
padding: px-to-rem(24); // 1.5rem
}scss
@function px-to-rem($px, $base: 16) {
@return ($px / $base) * 1rem;
}
@function rem-to-px($rem, $base: 16) {
@return ($rem / 1rem) * $base * 1px;
}
// 使用示例
.element {
font-size: px-to-rem(18); // 1.125rem
padding: px-to-rem(24); // 1.5rem
}Spacing Function
间距函数
scss
@function spacing($multiplier) {
@return $spacing-unit * $multiplier;
}
// Usage
.element {
margin-bottom: spacing(2); // 16px
padding: spacing(3); // 24px
}scss
@function spacing($multiplier) {
@return $spacing-unit * $multiplier;
}
// 使用示例
.element {
margin-bottom: spacing(2); // 16px
padding: spacing(3); // 24px
}Extend and Placeholders
继承与占位符
Use Placeholders Over Classes
使用占位符而非类选择器
scss
// Define placeholder
%button-base {
display: inline-flex;
align-items: center;
justify-content: center;
padding: $spacing-sm $spacing-md;
border: none;
border-radius: $border-radius-md;
font-family: inherit;
font-size: $font-size-base;
font-weight: $font-weight-bold;
text-decoration: none;
cursor: pointer;
transition: all $transition-base;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
// Extend placeholder
.btn-primary {
@extend %button-base;
background: $color-primary;
color: white;
&:hover:not(:disabled) {
background: darken($color-primary, 10%);
}
}
.btn-secondary {
@extend %button-base;
background: transparent;
color: $color-primary;
border: 2px solid $color-primary;
&:hover:not(:disabled) {
background: $color-primary;
color: white;
}
}scss
// 定义占位符
%button-base {
display: inline-flex;
align-items: center;
justify-content: center;
padding: $spacing-sm $spacing-md;
border: none;
border-radius: $border-radius-md;
font-family: inherit;
font-size: $font-size-base;
font-weight: $font-weight-bold;
text-decoration: none;
cursor: pointer;
transition: all $transition-base;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
// 继承占位符
.btn-primary {
@extend %button-base;
background: $color-primary;
color: white;
&:hover:not(:disabled) {
background: darken($color-primary, 10%);
}
}
.btn-secondary {
@extend %button-base;
background: transparent;
color: $color-primary;
border: 2px solid $color-primary;
&:hover:not(:disabled) {
background: $color-primary;
color: white;
}
}Loops and Iteration
循环与迭代
Generate Utility Classes
生成工具类
scss
// Spacing utilities
$spacing-directions: (
'': '',
't': '-top',
'r': '-right',
'b': '-bottom',
'l': '-left',
'x': '-inline',
'y': '-block'
);
@each $abbr, $direction in $spacing-directions {
@for $i from 0 through 8 {
.m#{$abbr}-#{$i} {
margin#{$direction}: spacing($i);
}
.p#{$abbr}-#{$i} {
padding#{$direction}: spacing($i);
}
}
}
// Color utilities
@each $name, $color in $colors {
.text-#{$name} {
color: $color;
}
.bg-#{$name} {
background-color: $color;
}
.border-#{$name} {
border-color: $color;
}
}scss
// 间距工具类
$spacing-directions: (
'': '',
't': '-top',
'r': '-right',
'b': '-bottom',
'l': '-left',
'x': '-inline',
'y': '-block'
);
@each $abbr, $direction in $spacing-directions {
@for $i from 0 through 8 {
.m#{$abbr}-#{$i} {
margin#{$direction}: spacing($i);
}
.p#{$abbr}-#{$i} {
padding#{$direction}: spacing($i);
}
}
}
// 颜色工具类
@each $name, $color in $colors {
.text-#{$name} {
color: $color;
}
.bg-#{$name} {
background-color: $color;
}
.border-#{$name} {
border-color: $color;
}
}Performance Best Practices
性能最佳实践
- Avoid overly specific selectors; aim for specificity of 0-1-0 (single class)
- Never use except for utility classes
!important - Minimize use of across files (can cause bloat)
@extend - Use and
@useinstead of@forward(deprecated)@import - Compile with source maps in development, without in production
- Use autoprefixer for vendor prefixes instead of manual prefixes
- 避免过于具体的选择器;目标是0-1-0的特异性(单个类选择器)
- 除非是工具类,否则绝不要使用
!important - 尽量减少跨文件使用(会导致代码冗余)
@extend - 使用和
@use替代已废弃的@forward@import - 开发环境编译时生成源映射,生产环境不生成
- 使用Autoprefixer处理浏览器前缀,而非手动添加
Modern SCSS Features
现代SCSS特性
Module System
模块系统
scss
// _variables.scss
$primary: #3498db;
// _mixins.scss
@use 'variables' as vars;
@mixin themed-button {
background: vars.$primary;
}
// main.scss
@use 'mixins';
.button {
@include mixins.themed-button;
}scss
// _variables.scss
$primary: #3498db;
// _mixins.scss
@use 'variables' as vars;
@mixin themed-button {
background: vars.$primary;
}
// main.scss
@use 'mixins';
.button {
@include mixins.themed-button;
}Built-in Modules
内置模块
scss
@use 'sass:math';
@use 'sass:color';
@use 'sass:list';
@use 'sass:map';
@use 'sass:string';
.element {
width: math.div(100%, 3);
background: color.adjust($color-primary, $lightness: 10%);
}scss
@use 'sass:math';
@use 'sass:color';
@use 'sass:list';
@use 'sass:map';
@use 'sass:string';
.element {
width: math.div(100%, 3);
background: color.adjust($color-primary, $lightness: 10%);
}Code Style
代码风格
- Use 2 spaces for indentation
- Use single quotes for strings
- Add a space after colons in declarations
- Add a space before opening braces
- Put closing braces on new lines
- Separate rule sets with blank lines
- Order properties logically (positioning, box model, typography, visual, misc)
- Comment complex calculations and non-obvious code
- 使用2个空格进行缩进
- 字符串使用单引号
- 声明中的冒号后添加空格
- 左大括号前添加空格
- 右大括号单独占一行
- 规则集之间用空行分隔
- 按逻辑顺序排列属性(定位、盒模型、排版、视觉效果、其他)
- 对复杂计算和非直观代码添加注释