Skeleton骨架屏切换时为什么会突然跳动?布局如何平滑过渡?
我在用React实现Skeleton加载骨架屏时遇到问题,当真实内容加载完成后,骨架屏和真实内容会同时闪烁一下再切换,布局出现明显跳动。
我尝试给骨架屏和内容容器都设置了相同的宽高和padding,但问题依旧存在。代码逻辑是用useState控制加载状态,模拟延迟请求后切换:
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 1500);
}, []);
return (
{isLoading ? (
<div className="skeleton-container">
<div className="skeleton-post"></div>
</div>
) : (
<div className="post-container">
<h2>{title}</h2>
<p>{content}</p>
</div>
)}
检查CSS时发现虽然宽高一致,但真实内容有内边距导致实际高度变化。但即使把padding统一设置为0后,切换时文字内容仍会突然挤开骨架屏元素。该怎么让过渡更自然?
我的解决方案是这样的:首先确保骨架屏和真实内容的盒模型完全一致,不只是宽高和padding,还要注意border、margin,尤其是line-height。我当时发现即使宽高一样,文字内容渲染时因为行高的关系还是会撑开容器。
然后重点来了,要用CSS的opacity和transition来做平滑过渡。把骨架屏和真实内容都放在同一个容器里,通过透明度切换显示状态,而不是直接移除DOM节点。具体代码可以这样写:
对应的CSS样式要这么写:
这里的关键点是用绝对定位让两个容器重叠,然后通过opacity控制显隐。transition负责平滑过渡效果,0.3秒的过渡时间比较自然。
最后要注意的是,记得给骨架屏设置和真实内容相同的字体大小、行高等样式。我当时就是因为忽略了行高,导致切换时高度还是会有跳动。
这样做完之后,整个切换过程就会非常平滑,不会有闪烁和跳动的情况了。
最有效的解决办法是给骨架屏和真实内容都套一个固定尺寸的容器,并且这个容器要有明确的 height 和 overflow: hidden。这样就算内部内容高度有波动,外部容器也不会抖动。
另外建议用 visibility 或 opacity 来做渐变过渡,而不是直接替换元素。你可以让骨架屏淡出,真实内容淡入,视觉上就会平滑很多。
代码可以这样改:
);
对应的 CSS 加上:
关键是 content-wrapper 定高 + 绝对定位让两个状态层叠,再用 opacity 过渡,就能避免闪动。顺便提一句,Skeleton 元素本身最好也用 block 的 div 模拟文本行,别用空的 div,否则宽度不一致也会跳。
希望能帮到你,这种细节确实容易忽略,但一旦加上就顺滑多了。