实用技巧与模式
实用技巧与模式
常见布局实现
居中对齐
水平居中
/* 行内元素水平居中 */
.parent {
text-align: center;
}
/* 块级元素水平居中 */
.child {
margin: 0 auto;
width: 50%; /* 必须设置宽度 */
}
/* Flexbox水平居中 */
.parent {
display: flex;
justify-content: center;
}
/* Grid水平居中 */
.parent {
display: grid;
justify-items: center;
}
垂直居中
/* 单行文本垂直居中 */
.text {
height: 50px;
line-height: 50px; /* 与height相同 */
}
/* Flexbox垂直居中 */
.parent {
display: flex;
align-items: center;
height: 200px;
}
/* Grid垂直居中 */
.parent {
display: grid;
align-items: center;
height: 200px;
}
/* 绝对定位垂直居中 */
.parent {
position: relative;
height: 200px;
}
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
水平垂直居中
/* Flexbox方法 */
.parent {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
}
/* Grid方法 */
.parent {
display: grid;
place-items: center; /* align-items + justify-items 简写 */
height: 300px;
}
/* 绝对定位方法 */
.parent {
position: relative;
height: 300px;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
多列布局
等宽多列
/* Flexbox等宽多列 */
.container {
display: flex;
}
.column {
flex: 1; /* 所有列等宽 */
}
/* Grid等宽多列 */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3列等宽 */
gap: 20px;
}
/* CSS多列布局 */
.container {
column-count: 3; /* 3列 */
column-gap: 20px;
}
不等宽多列
/* Flexbox不等宽多列 */
.container {
display: flex;
}
.sidebar {
flex: 0 0 300px; /* 不增长不收缩,固定300px */
}
.content {
flex: 1; /* 占用剩余空间 */
}
/* Grid不等宽多列 */
.container {
display: grid;
grid-template-columns: 300px 1fr; /* 左侧300px,右侧自适应 */
gap: 20px;
}
粘性页脚
确保页脚始终在页面底部,即使内容不足以填充整个视口。
/* Flexbox方法 */
body {
display: flex;
flex-direction: column;
min-height: 100vh; /* 视口高度 */
margin: 0;
}
.content {
flex: 1; /* 占用所有可用空间 */
}
.footer {
/* 页脚样式 */
}
/* Grid方法 */
body {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
margin: 0;
}
.header {
/* 页眉样式 */
}
.content {
/* 内容样式 */
}
.footer {
/* 页脚样式 */
}
组件设计思想
组件化 CSS 原则
- 单一职责原则:每个组件只负责一个功能
- 封装性:组件内部样式不影响外部
- 可复用性:组件可在不同场景重复使用
- 可组合性:小组件可组合成更复杂的组件
原子 CSS 方法
原子 CSS 是一种创建小型、单一用途类的方法。
/* 间距类 */
.m-0 {
margin: 0;
}
.m-1 {
margin: 0.25rem;
}
.m-2 {
margin: 0.5rem;
}
.m-3 {
margin: 1rem;
}
.p-0 {
padding: 0;
}
.p-1 {
padding: 0.25rem;
}
.p-2 {
padding: 0.5rem;
}
.p-3 {
padding: 1rem;
}
/* 显示类 */
.d-block {
display: block;
}
.d-flex {
display: flex;
}
.d-grid {
display: grid;
}
/* 对齐类 */
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
/* 颜色类 */
.text-primary {
color: #3498db;
}
.bg-primary {
background-color: #3498db;
}
使用原子类:
<div class="d-flex p-3 bg-primary">
<div class="m-2 p-2">项目1</div>
<div class="m-2 p-2">项目2</div>
</div>
组件设计模式
基础/修饰符模式
/* 基础按钮 */
.btn {
display: inline-block;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* 修饰符 */
.btn--primary {
background-color: #3498db;
color: white;
}
.btn--success {
background-color: #2ecc71;
color: white;
}
.btn--large {
padding: 0.75rem 1.5rem;
font-size: 1.2rem;
}
<button class="btn btn--primary">主要按钮</button>
<button class="btn btn--success btn--large">大号成功按钮</button>
容器/内容模式
/* 容器 */
.card {
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* 内容 */
.card__header {
padding: 1rem;
border-bottom: 1px solid #eee;
}
.card__body {
padding: 1rem;
}
.card__footer {
padding: 1rem;
border-top: 1px solid #eee;
background-color: #f9f9f9;
}
<div class="card">
<div class="card__header">
<h3>卡片标题</h3>
</div>
<div class="card__body">
<p>卡片内容</p>
</div>
<div class="card__footer">
<button class="btn btn--primary">确认</button>
</div>
</div>
主题系统实现
使用 CSS 变量的主题系统
/* 定义根变量 */
:root {
/* 亮色主题(默认) */
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #333333;
--text-secondary: #666666;
--border-color: #dddddd;
--primary-color: #3498db;
--success-color: #2ecc71;
--warning-color: #f39c12;
--danger-color: #e74c3c;
}
/* 暗色主题 */
.theme-dark {
--bg-primary: #222222;
--bg-secondary: #333333;
--text-primary: #ffffff;
--text-secondary: #cccccc;
--border-color: #444444;
/* 主题色可以保持不变或稍微调整 */
}
/* 使用变量 */
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
.card {
background-color: var(--bg-primary);
border: 1px solid var(--border-color);
}
.button {
background-color: var(--primary-color);
color: white;
}
.button--success {
background-color: var(--success-color);
}
主题切换
<button id="theme-toggle">切换主题</button>
<script>
const themeToggle = document.getElementById("theme-toggle");
themeToggle.addEventListener("click", () => {
document.body.classList.toggle("theme-dark");
// 保存用户偏好
const isDarkTheme = document.body.classList.contains("theme-dark");
localStorage.setItem("theme", isDarkTheme ? "dark" : "light");
});
// 加载保存的主题
document.addEventListener("DOMContentLoaded", () => {
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark") {
document.body.classList.add("theme-dark");
}
});
</script>
使用媒体查询自动切换主题
/* 默认亮色主题 */
:root {
--bg-primary: #ffffff;
--text-primary: #333333;
/* 其他变量... */
}
/* 根据系统偏好自动切换到暗色主题 */
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #222222;
--text-primary: #ffffff;
/* 其他变量... */
}
}
/* 用户手动选择的主题优先级更高 */
.theme-light {
--bg-primary: #ffffff;
--text-primary: #333333;
/* 其他变量... */
}
.theme-dark {
--bg-primary: #222222;
--text-primary: #ffffff;
/* 其他变量... */
}
性能优化技巧
选择器优化
/* 避免 */
body div ul li a {
...;
} /* 过长的选择器链 */
/* 推荐 */
.nav-link {
...;
} /* 直接类选择器 */
减少重绘和回流
/* 避免 */
.box {
width: 300px;
height: 200px;
/* 分别设置会导致多次回流 */
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
}
/* 推荐 */
.box {
width: 300px;
height: 200px;
margin: 10px; /* 简写属性只触发一次回流 */
}
使用 transform 和 opacity 进行动画
/* 避免 */
@keyframes move-bad {
0% {
left: 0;
top: 0;
}
100% {
left: 100px;
top: 100px;
}
}
/* 推荐 */
@keyframes move-good {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(100px, 100px);
}
}
使用 will-change 提示浏览器
.animated-element {
will-change: transform, opacity;
}
避免@import
/* 避免 */
@import url("typography.css");
@import url("buttons.css");
/* 推荐 */
/* 使用<link>标签在HTML中引入多个CSS文件 */
/* 或使用构建工具合并CSS文件 */
实战示例:响应式导航栏
<header class="header">
<div class="container">
<div class="logo">Brand</div>
<button class="nav-toggle" aria-label="Toggle Navigation">
<span class="nav-toggle__bar"></span>
<span class="nav-toggle__bar"></span>
<span class="nav-toggle__bar"></span>
</button>
<nav class="nav">
<ul class="nav__list">
<li class="nav__item"><a href="#" class="nav__link">首页</a></li>
<li class="nav__item"><a href="#" class="nav__link">关于</a></li>
<li class="nav__item"><a href="#" class="nav__link">服务</a></li>
<li class="nav__item"><a href="#" class="nav__link">博客</a></li>
<li class="nav__item"><a href="#" class="nav__link">联系</a></li>
</ul>
</nav>
</div>
</header>
:root {
--primary-color: #3498db;
--text-color: #333;
--bg-color: #fff;
--nav-height: 70px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: var(--text-color);
background-color: var(--bg-color);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.header {
height: var(--nav-height);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
background-color: var(--bg-color);
z-index: 100;
}
.header .container {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary-color);
}
.nav__list {
display: flex;
list-style: none;
}
.nav__item {
margin-left: 30px;
}
.nav__link {
color: var(--text-color);
text-decoration: none;
font-weight: 500;
transition: color 0.3s ease;
position: relative;
}
.nav__link::after {
content: "";
position: absolute;
bottom: -5px;
left: 0;
width: 0;
height: 2px;
background-color: var(--primary-color);
transition: width 0.3s ease;
}
.nav__link:hover {
color: var(--primary-color);
}
.nav__link:hover::after {
width: 100%;
}
.nav-toggle {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 5px;
}
.nav-toggle__bar {
display: block;
width: 25px;
height: 3px;
background-color: var(--text-color);
margin: 5px 0;
border-radius: 3px;
transition: transform 0.3s ease, opacity 0.3s ease;
}
@media (max-width: 768px) {
.nav-toggle {
display: block;
z-index: 101;
}
.nav {
position: fixed;
top: 0;
right: 0;
width: 80%;
max-width: 300px;
height: 100vh;
background-color: var(--bg-color);
box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
transition: transform 0.3s ease;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
}
.nav.active {
transform: translateX(0);
}
.nav__list {
flex-direction: column;
align-items: center;
}
.nav__item {
margin: 15px 0;
}
.nav-toggle.active .nav-toggle__bar:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.nav-toggle.active .nav-toggle__bar:nth-child(2) {
opacity: 0;
}
.nav-toggle.active .nav-toggle__bar:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
}
document.addEventListener("DOMContentLoaded", () => {
const navToggle = document.querySelector(".nav-toggle");
const nav = document.querySelector(".nav");
navToggle.addEventListener("click", () => {
navToggle.classList.toggle("active");
nav.classList.toggle("active");
});
// 点击导航链接后关闭菜单
const navLinks = document.querySelectorAll(".nav__link");
navLinks.forEach((link) => {
link.addEventListener("click", () => {
navToggle.classList.remove("active");
nav.classList.remove("active");
});
});
});
这个响应式导航栏示例展示了如何结合 CSS 和 JavaScript 创建在桌面和移动设备上都能良好工作的导航组件。它使用了 CSS 变量、Flexbox 布局、过渡动画和媒体查询等技术。