侧边栏收缩可以有以下几种方案
| 方案 | 触发 Reflow? | 触发 Repaint? | 是否影响布局 | 硬件加速 | 适用场景 |
|---|---|---|---|---|---|
width + transition | ✅ 是 | ✅ 是 | ✅ 影响 | ❌ 否 | 宽度变化(简单) |
@keyframes width | ✅ 是 | ✅ 是 | ✅ 影响 | ❌ 否 | 复杂 width 动画 |
JS 逐步 width | ✅ 是 | ✅ 是 | ✅ 影响 | ❌ 否 | 细粒度控制 |
scaleX() | ❌ 否 | ✅ 是 | ❌ 不影响 | ✅ 是 | 最佳,适合收缩 |
translateX() | ❌ 否 | ✅ 是 | ❌ 不影响 | ✅ 是 | 最佳,适合隐藏 |
| left: -200px | ✅ 触发 | ❌ 否 |
关于性能可以通过Performance Monitor面板来监控网页性能
# 方案 1:使用 animation 过渡 width
css
复制编辑
.sidebar {
width: 200px;
transition: width 0.3s ease-in-out;
}
.sidebar.collapsed {
width: 50px;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
✅ 优点:
- 使用
transition,浏览器可以优化动画,性能较好。 - 代码简洁,易于维护。
transition仅在width发生变化时触发,不会持续执行。
❌ 缺点:
- 只适用于单一方向的过渡(不能控制更复杂的动画)。
# 方案 2:使用@keyframes
css
复制编辑
@keyframes collapse {
from {
width: 200px;
}
to {
width: 50px;
}
}
@keyframes expand {
from {
width: 50px;
}
to {
width: 200px;
}
}
.sidebar {
width: 200px;
}
.sidebar.collapsed {
animation: collapse 0.3s forwards;
}
.sidebar.expanded {
animation: expand 0.3s forwards;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
✅ 优点:
@keyframes允许更复杂的动画(比如非线性变化、结合opacity)。- 可以更自由地控制动画的
timing function,支持steps()等细粒度控制。
❌ 缺点:
- 需要
animation触发,每次状态变化都会执行动画,可能带来额外的性能消耗。 - 代码稍显冗余,不如
transition直观。
# 方案 3:使用 style.width 逐步调整
const [width, setWidth] = useState(200);
const toggleSidebar = () => {
let targetWidth = width === 200 ? 50 : 200;
let step = width > targetWidth ? -5 : 5;
let timer = setInterval(() => {
setWidth(prev => {
let newWidth = prev + step;
if ((step > 0 && newWidth >= targetWidth) || (step < 0 && newWidth <= targetWidth)) {
clearInterval(timer);
return targetWidth;
}
return newWidth;
});
}, 10);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
✅ 优点:
- 可以手动控制
width的每一步变化,实现更复杂的交互效果。 - 可以与
requestAnimationFrame结合优化性能。
❌ 缺点:
- 手动计算
width变化,代码复杂度较高。 - 不如 CSS 方案高效,可能影响性能。
# ✅ 方案 4:使用 transform scaleX
.sidebar {
width: 200px; /* 侧边栏的原始宽度 */
transform-origin: left; /* 变换原点在左侧 */
transform: scaleX(1);
transition: transform 0.3s ease-in-out;
}
.sidebar.collapsed {
transform: scaleX(0);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 🎯 方案原理
scaleX(1)表示正常大小,scaleX(0)让侧边栏水平收缩至 0,不改变其width。transform不会影响布局,比width变化性能更好。- 结合
transform-origin: left确保收缩方向正确。
✅ 优点:
- 高性能,利用 GPU 硬件加速,不卡顿。
- 不会触发 reflow(回流),仅触发 compositing(合成层)优化。
- 不会影响相邻元素的布局(不像
width会影响)。
❌ 缺点:
- 无法影响
overflow: hidden里的内容,如果sidebar内部有absolute布局元素,可能仍然会显示。 - 可能影响内部元素的动画(
scaleX(0)会缩放内部所有内容)。
# ✅ 方案 5:使用translateX()
.sidebar {
width: 200px;
transform: translateX(0);
transition: transform 0.3s ease-in-out;
}
.sidebar.collapsed {
transform: translateX(-100%);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 🎯 方案原理
translateX(0)表示侧边栏在原位,translateX(-100%)让其完全移动到左侧 (隐藏)- 适用于侧边栏完全隐藏的情况,而非缩小宽度。
✅ 优点:
- 性能极佳(GPU 加速),不会影响 DOM 结构。
- 不会影响内部元素的缩放。
❌ 缺点:
- 只能用于隐藏/显示,不能用于宽度缩放。
- 可能需要额外的
overflow: hidden处理滚动条问题。