CSS 架构
概览
使用 BEM(Block Element Modifier)、SMACSS 和 CSS-in-JS 模式构建可维护的 CSS 系统,采用适当的组织和约定。
何时使用
- 大型样式表
- 基于组件的样式
- 设计系统开发
- 多团队协作
- CSS 可扩展性和可重用性
实施示例
1. BEM(Block Element Modifier)模式
/* 块 - 独立组件 */
.button {
display: inline-block;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: all 0.3s ease;
}
/* 元素 - 组件部分 */
.button__icon {
margin-right: 8px;
vertical-align: middle;
}
/* 修饰符 - 变体 */
.button--primary {
background-color: #007bff;
color: white;
}
.button--primary:hover {
background-color: #0056b3;
}
.button--secondary {
background-color: #6c757d;
color: white;
}
.button--disabled {
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
}
.button--large {
padding: 15px 30px;
font-size: 18px;
}
.button--small {
padding: 5px 10px;
font-size: 12px;
}
/* 卡片块与元素 */
.card {
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card__header {
padding: 16px;
border-bottom: 1px solid #e0e0e0;
background-color: #f8f9fa;
}
.card__body {
padding: 16px;
}
.card__footer {
padding: 16px;
border-top: 1px solid #e0e0e0;
background-color: #f8f9fa;
}
.card--elevated {
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
2. SMACSS(Scalable and Modular Architecture for CSS)
/* 1. 基础样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
color: #333;
line-height: 1.6;
}
body {
background-color: #fff;
}
a {
color: #007bff;
text-decoration: none;
}
/* 2. 布局样式 */
.layout-main {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px;
padding: 20px;
}
.layout-header {
padding: 16px;
background-color: #333;
color: white;
}
.layout-sidebar {
width: 250px;
background-color: #f5f5f5;
padding: 16px;
}
/* 3. 模块样式 */
.module-card {
padding: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
.module-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.module-form__input {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
}
/* 4. 状态样式 */
.is-hidden {
display: none;
}
.is-active {
background-color: #007bff;
color: white;
}
.is-disabled {
opacity: 0.6;
cursor: not-allowed;
}
.is-error {
border-color: #dc3545;
color: #dc3545;
}
/* 5. 主题样式 */
.theme-dark {
background-color: #222;
color: #fff;
}
.theme-dark .module-card {
border-color: #444;
}
3. CSS-in-JS 与 Styled Components
// styled-components 示例
import styled from 'styled-components';
interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}
const StyledButton = styled.button<ButtonProps>`
display: inline-block;
border: none;
border-radius: 4px;
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
font-size: ${props => {
switch (props.size) {
case 'sm': return '12px';
case 'lg': return '18px';
default: return '16px';
}
}};
padding: ${props => {
switch (props.size) {
case 'sm': return '5px 10px';
case 'lg': return '15px 30px';
default: return '10px 20px';
}
}};
background-color: ${props => {
if (props.disabled) return '#ccc';
return props.variant === 'secondary' ? '#6c757d' : '#007bff';
}};
color: white;
opacity: ${props => props.disabled ? 0.6 : 1};
transition: all 0.3s ease;
&:hover:not(:disabled) {
background-color: ${props =>
props.variant === 'secondary' ? '#5a6268' : '#0056b3'
};
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
&:active:not(:disabled) {
transform: translateY(0);
}
`;
export const Button = (props: ButtonProps) => <StyledButton {...props} />;
4. CSS 变量(自定义属性)
/* 根变量 */
:root {
/* 颜色 */
--color-primary: #007bff;
--color-secondary: #6c757d;
--color-danger: #dc3545;
--color-success: #28a745;
--color-warning: #ffc107;
--color-text: #333;
--color-background: #fff;
--color-border: #e0e0e0;
/* 排版 */
--font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-size-base: 16px;
--font-size-lg: 18px;
--font-size-sm: 14px;
--line-height-base: 1.6;
/* 间距 */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
/* 阴影 */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 2px 4px rgba(0,0,0,0.1);
--shadow-lg: 0 4px 8px rgba(0,0,0,0.15);
/* 边框半径 */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
}
/* 暗色主题覆盖 */
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e0e0e0;
--color-background: #1e1e1e;
--color-border: #333;
}
}
/* 使用 */
.button {
background-color: var(--color-primary);
color: white;
padding: var(--spacing-md) var(--spacing-lg);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
font-family: var(--font-family-base);
font-size: var(--font-size-base);
line-height: var(--line-height-base);
}
.card {
background-color: var(--color-background);
color: var(--color-text);
border: 1px solid var(--color-border);
padding: var(--spacing-lg);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
}
5. 实用优先 CSS(Tailwind 模式)
<!-- 实用类提供细粒度控制 -->
<div class="flex flex-col gap-4 p-6 bg-white rounded-lg shadow-md">
<h2 class="text-2xl font-bold text-gray-900">标题</h2>
<p class="text-gray-600 leading-relaxed">描述</p>
<div class="flex gap-2">
<button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">
主要
</button>
<button class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600 transition">
次要
</button>
</div>
</div>
<style>
/* 实用类 */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.gap-4 { gap: 1rem; }
.gap-2 { gap: 0.5rem; }
.p-6 { padding: 1.5rem; }
.px-4 { padding-left: 1rem; padding-right: 1rem; }
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.bg-white { background-color: white; }
.bg-blue-500 { background-color: #3b82f6; }
.text-white { color: white; }
.text-gray-900 { color: #111827; }
.text-2xl { font-size: 1.5rem; }
.font-bold { font-weight: bold; }
.rounded { border-radius: 0.375rem; }
.rounded-lg { border-radius: 0.5rem; }
.shadow-md { box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
</style>
最佳实践
- 选择一种方法并坚持使用
- 使用 CSS 变量进行主题设置
- 保持特异性低
- 按功能组织文件
- 使用预处理器(Sass/Less)编写 DRY 代码
- 文档化命名约定
- 实施适当的文件结构
- 使用 linting 工具(stylelint)