大家都知道骨架屏的作用是提升用户体验,那你知道是如何提升的吗?
骨架屏的作用是优雅的占位,所谓优雅,就是贴合的尺寸,适时的退场。
想要做到优雅,就要理解骨架屏的两大核心元素,状态和时机。
状态处理
只有开、关两种状态,初始值为开。
上图是一个常见的骨架屏应用场景,有若干个步骤组成。
- 展示骨架屏
- 请求数据
- 处理数据
- 关闭骨架屏
- 展示数据
如果在第二步,或者第三步的时候出现了问题,比如
- 接口报 502。
- 接口响应超时。
- 接口返回了空数据。
- 业务逻辑要求返回空数据。
就需要进行异常处理
- 决定骨架屏的状态
- 决定下一步的行为(自动重试请求,错误提示,出再试一次按钮,显示兜底内容…)
细心的同学可能已经发现了,正常流程下的接续处理步骤与异常处理是一样的。经过泛化,我们称之为「后处理」吧。
时长处理
我们无法提前知道接口返回需要的时长,如果前端根据接口响应时间来控制开关的状态,那么骨架屏可能会展示很久,也可能会一闪而过,这都不是好的用户体验。
依赖接口响应时长,等于让后端去保证用户体验,这不是很滑稽吗。
严肃的说,不去思考这个问题,就是前端的不作为,用户体验应该由前端兜底。
让我们分别来看看前端如何兜底吧。
首先看看展示过久的情况,一般接口层会切断超时连接。如果有进一步的需求,前端也能够在请求层统一设置超时阈值。
到达旗帜的时刻,就是需要进行「后处理」的时机了。
再来看一闪而过的情况。 最简单的方案是,在关闭骨架屏时添加一个简单的高度动画过渡。
.skeleton {
height: 100px;
opacity: 1;
transition: all 0.3s;
}
.fadeOut {
height: 0;
opacity: 0;
}
还有一种复杂的方案,完全由前端控制,引入了相当的复杂度,一般不推荐使用。
上图中,添加了一个绿色的长方形,用来人为控制最小响应时间,不管接口实际返回的耗时。具体逻辑如下。
// 响应时长 R
// 最小响应时长 E
if R < E return E
if R > E return R
是否需要添加这个时机,取决于使用场景,以及「后处理」方案。
例子
让我们用一个例子来说明吧。
绿色方块是一个定高元素,但它的数据需要异步调用接口获取。
但由于异步,页面高度抖动。领导说让你优化一下。很简单,这个时候加一个高度相同的占位元素就搞定了。
「后处理」可以是
- 如果数据获取成功,关闭骨架屏显示,显示取到的数据。
if (showSkeleton) {
return <Skeleton />
} else {
return <DataBlock />
}
- 如果数据获取失败,关闭骨架屏显示,显示兜底内容。
if (showSkeleton) {
return <Skeleton />
} else {
return showDataBlock ? <DataBlock /> : <DataAlternative />
}
后来业务逻辑变了,根据接口返回的数据,绿色方块有一定的条件不会出。
因为涉及到了高度,如果直接取消显示,会带来高度抖动。「后处理」的方案就很显然了,由于是定高元素,可以通过动画关闭,延长取消的感知时间。
但是产品还不满意呀,不想要动画效果,但是又要保证不能一闪而过怎么办?
- 和产品 PK 一下吧。
- PK 不过,那只能通过额外的控制位,兼容接口响应时长的逻辑了。
结尾
骨架屏在很多人看来就只是一个转场。但是其实想要做好并不容易,承前启后的功能定位,天然就会涉及到前端的很多方面,接口请求,视图逻辑,交互体验等。还要控制住代码复杂度,其实并不是一件简单的事情。
之前知乎看到一个问题,用户体验是否应该由前端保证?
这个问题太大了,很难回答。但是在骨架屏这个小点上,我想是的。