骨架屏应作为依附于具体Block的Element,而非独立Block;必须使用带归属的BEM命名如.card__skeleton,禁用泛义类.skeleton,修饰符需语义化(如--pending)、绑定容器,伪元素须挂载在真实Element上并设aspect-ratio。

骨架屏该作为 Block 还是 Element?
骨架屏不是独立功能模块,而是某个容器的视觉占位反馈,所以它必须依附于已有 Block,不能单独定义 .skeleton 这类泛义 Block。比如卡片加载时的占位,应是 .card__skeleton;列表底部加载提示,应是 .list__loader(再加修饰符控制状态)。常见错误是写 .skeleton 或 .loading ——这类类名没归属,CSS 无法精准作用于特定上下文,JS 切换状态时也容易误触其他组件。
怎么给骨架元素加 loading 状态修饰符?
修饰符必须绑定到具体 Block 或 Element,且语义表达「意图」而非「实现」:.card--loading 表示整张卡片处于加载态(可配合 pointer-events: none、遮罩等);.card__skeleton--visible 表示骨架占位显隐切换。禁止用 --loading,因为:
- 它暴露 JS 状态名(如后端返回 isLoading 就得硬套),换状态逻辑就得改 CSS 类
- 设计系统升级时,--loading 无法映射到主题变量,而 --pending 或 --fetching 更稳定
- 动画名必须对齐:若用 .card__skeleton--pending,对应 @keyframes card-skeleton-pending,不能简写为 @keyframes pending
伪元素做骨架占位时,BEM 类怎么挂?
伪元素(::before/::after)本身不参与 DOM,但必须挂载在真实 Block 容器上,否则尺寸、动画、z-index 都不可控。正确写法是:.card__image::before,其中 .card__image 是已定义的 Element;错误写法是 .loading::before ——浏览器不认 .loading 是 Block,也没办法继承宽高或 aspect-ratio。关键点:
- aspect-ratio 必须设在容器(如 .card__image)上,伪元素才能稳定占位
- 避免 z-index: -1,父级 overflow: hidden 会直接裁掉它
- 动画用 background-position + background-size: 200% 100% 实现流动效果,起始位置设为 -200% 保证首帧不可见
多个骨架区域共存时如何避免样式冲突?
不同 Block 的骨架元素不能共享类名,哪怕结构相似。例如用户头像和商品图标的骨架,必须分开定义:.user-card__avatar-skeleton 和 .product-card__image-skeleton。原因:
- Element 名称不含父级语义是错觉,__avatar-skeleton 不等于 __image-skeleton,它们承载的业务含义和尺寸约束不同
- 若强行复用,修改一个的 border-radius 或 width 会影响所有地方
- 构建工具(如 PostCSS)无法做作用域提取,.skeleton 类极易打包进全局样式表,污染其他页面
- 真实项目中,Skeleton 的尺寸、圆角、动画节奏往往随 Block 场景变化,硬统一反而增加维护成本


















