前端 前端工程 构建工具 骨架屏 性能优化 用户体验

为什么 (Why)

在7月份的某一天,我打算为一个项目卡片列表优化体验,项目数据从远程加载。为了提升用户感知性能,我决定为卡片列表添加骨架屏。

简单的,我需要一个 loading 状态变量和一个项目卡片的骨架屏组件。等数据加载完成后,切换 loading 状态变量,显示真实的项目卡片。

“没什么难度”,我想。

当我开始编写骨架屏组件时,我发现这确实不难,但有些繁琐。

项目卡片组件包含图片、标题、描述、标签部分。为了让骨架屏看起来更像真实内容,我需要为每个部分设计对应的占位符。 这意味着我需要手动编写大量的骨架屏代码,重复的工作令人疲惫。

更令人难过的是,随着需求变化,组件会不断迭代,添加或修改内容。每次修改后,我都需要手动更新骨架屏组件,确保它与真实内容保持一致。

现在我碰到了问题,我需要一个能随着组件变化而自动更新的骨架屏生成方案。就像往常一样,我在网上搜索解决方案。

令人惊讶的是,相关的结果并不多。大多数现有的骨架屏方案都专注于首屏加载,或者需要在构建时生成静态骨架屏代码。

而我需要的是一个客户端生成的骨架,我需要的是一个小的能够放在下拉菜单里,或者放在局部区域的骨架。而不是一个全屏的骨架。

所以,为了满足我的需求,我决定自己动手。

先让我展示一下成果😊!

为什么我选择用”占位骨架”而非”骨架屏”?

骨架屏(Skeleton Screen)概念最初由 Luke Wroblewski 在 2013 年的文章 Mobile Design Details: Avoid The Spinner 中提出,主要应用场景是移动端应用 Polar

受限于移动设备的屏幕尺寸,移动端应用往往需要将内容铺满整个可视区域来最大化信息展示,因此早期的骨架屏设计通常覆盖全屏。

随着 Web 应用和桌面应用的发展,“骨架屏”的应用场景已经大大扩展,不再局限于全屏展示。在现代应用中,我们经常在弹窗、下拉菜单、卡片组件等局部区域看到类似的加载占位效果。

考虑到本文主要专注于生成局部区域的加载占位效果,而非传统意义上的全屏骨架屏,我更倾向于使用”占位骨架”这个术语,以更准确地描述其应用范围和功能特点。

实现 (How)

根据上述的原因,这个项目的核心功能如下:

  1. 自动化生成
    1. 避免手动编写骨架代码,交给工具自动生成。
    2. 这也便于在页面修改时,骨架屏能够自动适配。
  2. 客户端渲染
    1. 客户端生成,避免设备尺寸适配问题
    2. 部分生成,细粒度控制
自动化生成的挑战性

自动化生成的挑战性在于,如何处理并兼容众多的 UI 库。这绝不是一件容易的事情,因为不同的 UI 库有不同的组件结构和样式体系。

我的决定做一个折中的方案,提供一些配置选项,允许用户根据自己的 UI 库进行调整。这种方式不能创建完美的占位骨架,但一个看起来差不多的占位骨架也不错。

查看 fuzzy 在线示例 体验。

客户端渲染的挑战性

客户端渲染的难点在于,当页面需要接收到远端数据才能渲染时,如何在数据加载前生成合适的骨架屏。

一个例子是渲染一个文章卡片组件列表,只有当数据从远端获取到之后,才能渲染出文章卡片。那么在数据加载前,如何根据文章卡片的 DOM 结构生成一个合适的占位骨架?

这看起来是一个悖论,因为在数据未加载前,我们并不知道文章卡片的具体结构和内容。

我的做法是,

  1. 开发阶段收集一部分远端数据作为样本。将这些样本数据传递给骨架屏生成工具,用于生成占位骨架。
  2. 然后在构建阶段,将这些样本数据内嵌到构建代码中,在生产环境中使用内嵌的样本数据来生成占位骨架。

这要求骨架屏生成工具能够在构建时访问到这些样本数据,并根据样本数据的结构生成对应的占位骨架。这也是为什么需要开发构建工具插件的原因。

外围功能设计

核心功能完成后,还需要外围辅助功能来提升易用性和适配性:

  1. 全局配置: 提供配置选项,允许用户根据自身需求调整全局的占位骨架生成逻辑。当然,也可以针对特定页面或组件进行覆盖配置。
  2. 构建工具集成:通过 unplugin 实现对 Nuxt、Vite、Webpack 等多构建工具的支持
  3. 多种框架兼容: 受限于个人能力,目前只支持 Vue 3,但架构设计允许方便的扩展到 React、Svelte 等其他框架。
  4. 文档和示例: 提供友好的文档和示例,帮助用户快速上手和理解使用方法。

上述 1,2,3 点都是常见做法,略过不谈。对多框架兼容的文档工具改造感兴趣的话,可以查看我的另一篇文章 基于 Astro Starlight 的多框架文档

结果 (What)

经过一段时间的开发,我完成了这个项目,并将其命名为 Gueleton。

Gueleton 的名字由 中文 ”骨(Gu)“ 和英文 “Skeleton” 组合而成。

目前,Gueleton 支持 Vue 3,基于 unplugin 架构,捆绑器/构建工具上支持 Nuxt、Vite、Webpack、Vue-CLI。