今天這個篇文章主要想分享一下我在工作上遇到的一個問題與最後的解決方案的選擇。

.sidebar {
width: 240px;
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar.collapsed {
width: 80px;
}
.divider {
height: 10px;
margin: 0.5rem 0;
background-image: linear-gradient(
to right,
transparent calc(50% - 150px),
#d3d3d3 calc(50% - 150px),
#d3d3d3 calc(50% + 150px),
transparent calc(50% + 150px)
);
background-size: 100% 1px;
background-position: center;
background-repeat: no-repeat;
}
當選單 width 從 240px 變成 80px 時:
calc() 表達式需要在動畫的每一幀重新計算:
在深入介紹我的解決方案之前,我想先解釋為什麼在這個案例中,為什麼我選擇不是效能本來就好的 transform 而是針對 width 去處理!
有人可能會說:「為什麼不用 transform 避免重排?」
關於瀏覽器的選染跟重新繪製我有寫一篇文章專門介紹,有興趣可以先看看
https://thecodingpro.com/b/1pXFBuxCnFuTUIhHoo8O
.sidebar {
width: 240px;
transform: scaleX(1);
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar.collapsed {
transform: scaleX(0.333);
}
表面上看起來不錯,效能跟體驗都挺棒的,因為 transform 只涉及繪製,不涉及重排
但問題來了!!! 子元件也會被縮放!
選單寬度 240px → 使用 scaleX(0.333)
.menu-item {
transform: scaleX(3); /* 反向縮放來抵消 */
transform-origin: left;
}
.divider {
transform: scaleX(3); /* 每個子元件都要寫 */
transform-origin: left;
}
/* 如果有更多子組件... 每個都要加 */
.sidebar {
width: 240px;
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
/* 添加這一行就好 */
contain: layout style paint;
}
.sidebar.collapsed {
width: 80px;
}
/* 子元件完全不用改 */
.menu-item {
padding: 0.75rem;
cursor: pointer;
border-radius: 0.375rem;
}
.divider {
height: 10px;
margin: 0.5rem 0;
background-image: linear-gradient(
to right,
transparent calc(50% - 150px),
#d3d3d3 calc(50% - 150px),
#d3d3d3 calc(50% + 150px),
transparent calc(50% + 150px)
);
background-size: 100% 1px;
background-position: center;
background-repeat: no-repeat;
}
MDN 是這個說的:
contain 標示了元素及其內容盡可能獨立於文檔樹的其餘部分。限制使 DOM 的一部分得以被隔離,且透過將佈局、樣式、繪製、尺寸或其任意組合的計算限制於 DOM 子樹而非整個頁面使效能受益。限制也可用於限制 CSS 計數器和引號的作用域。
contain 三個值的含義
contain: layout style paint;
效能對比| 指標 | 沒有 contain | 有 contain | 提升 |
|---|---|---|---|
| 幀率 | 低 | 高 | 20-40% |
| divider calc() 重新計算 | 影響整個頁面 | 只影響選單區域 | 隔離化 |
| 瀏覽器需要檢查 | 整個頁面 layout | 只檢查選單 | 大幅減少 |
| 使用者體驗 | 明顯卡頓 | 流暢無感 | 體驗極好 |
特別適合的場景:
不需要的場景:
如果你的網站有其他動畫卡頓的問題,先問自己:
往往只需要一行 CSS,就能帶來巨大的改善!
最後的建議:效能優化不一定很複雜。有時候簡單的一行 contain: layout style paint 就能帶來 60% 以上的動畫效能提升。當遇到動畫卡頓,先試試看 contain 吧!