侧边栏收缩可以有以下几种方案

方案 触发 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

✅ 优点:

  • 使用 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

✅ 优点:

  • @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

✅ 优点:

  • 可以手动控制 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

# 🎯 方案原理

  • 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

# 🎯 方案原理

  • translateX(0) 表示侧边栏在原位,translateX(-100%) 让其完全移动到左侧 (隐藏)
  • 适用于侧边栏完全隐藏的情况,而非缩小宽度。

✅ 优点:

  • 性能极佳(GPU 加速),不会影响 DOM 结构。
  • 不会影响内部元素的缩放。

❌ 缺点:

  • 只能用于隐藏/显示,不能用于宽度缩放。
  • 可能需要额外的 overflow: hidden 处理滚动条问题。

# 方案6:使用定位和left属性