Skeleton
Framework7 comes with Skeleton Elements library (aka UI Skeletons, Skeleton Screens, Ghost Elements) - UI for improved perceived performance.
Skeleton Elements library already integrated into Framework7 and you don't have to install it separately. For the full API documentation and more examples check out the official Skeleton Elements documentation.
Skeleton Block
Skeleton block is just a usual block element with gray background color, that can be in any required size.
To create skeleton block element we just need to create div
element with skeleton-block
class and better with fixed width:
...
<div class="list">
<ul>
<li class="item-content">
<div class="item-inner">
<div class="item-title">
<!-- Use skeleton block instead of list item title -->
<div class="skeleton-block" style="width: 100px"></div>
</div>
</div>
</li>
</ul>
</div>
...
Skeleton Text
Skeleton text is more interesting thing. Framework7 comes with special built-in Skeleton font, that renders every character as small gray rectangle. When we apply skeleton-text
class to any element, it converts text to gray blocks/lines. Advantage over skeleton-block
is that such "skeleton text" can be fully responsive and its size will reflect actual text size.
Skeleton text font supports following characters set (including "space"):
0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ - . , : ; / ! / * & ' " | ( ) { } [ ]
...
<div class="list media-list">
<ul>
<!-- we just add "skeleton-text" class to list item and its text will be rendered as gray boxes -->
<li class="item-content skeleton-text">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Item Title</div>
</div>
<div class="item-subtitle">Item Subtitle</div>
<div class="item-text">Item text goes here, and it will be rendered as gray box too.</div>
</div>
</li>
<!-- In the next item we use "_" character instead of actual text -->
<li class="item-content skeleton-text">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">____ _____</div>
</div>
<div class="item-subtitle">____ _______</div>
<div class="item-text">____ ____ ____ _____ ___ __ ____ __ ________ __ ____ ___ ____</div>
</div>
</li>
</ul>
</div>
...
Skeleton Effects
Skeleton elements also support three animation effects: Fade, Wave and Pulse.
To enable special skeleton animation effect, we can need add one of the following classes to skeleton elements, or to parent element containing skeleton elements:
skeleton-effect-fade
- to add fade effectskeleton-effect-wave
- to add wave effectskeleton-effect-pulse
- to add pulse effect
CSS Variables
Below is the list of related CSS variables (CSS custom properties).
:root {
--skeleton-color: #ccc;
--skeleton-icon-color: rgba(0, 0, 0, 0.25);
}
.dark {
--skeleton-color: #515151;
--skeleton-icon-color: rgba(255, 255, 255, 0.25);
}
Examples
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner sliding">
<div class="left">
<a class="link back">
<i class="icon icon-back"></i>
<span class="if-not-md">返回</span>
</a>
</div>
<div class="title">骨架屏元素</div>
</div>
</div>
<div class="page-content">
<div class="block block-strong-ios block-outline-ios">
<p>骨架(或幽灵)元素旨在提高感知性能,使应用程序感觉更快。</p>
<p>Framework7提供了两种类型的这种元素:骨架块和骨架文本。骨架块是一个灰色的方块,可以用作任何元素的占位符。骨架文本使用特殊的内置骨架字体,将此类文本的每个字符呈现为灰色矩形。骨架文本可以使这些元素具有响应性,并且感觉更加自然。.</p>
<p>它可以在任何地方和与任何元素一起使用.</p>
</div>
<div class="block-title">骨架列表</div>
<div class="list list-strong-ios list-outline-ios list-dividers-ios media-list skeleton-text">
<ul>
<li class="item-content">
<div class="item-media">
<div class="skeleton-block" style="width: 40px; height: 40px; border-radius: 50%"></div>
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">标题</div>
</div>
<div class="item-subtitle">副标题</div>
<div class="item-text">
占位字符串1<br />
Text line 2
</div>
</div>
</li>
<li class="item-content">
<div class="item-media">
<div class="skeleton-block" style="width: 40px; height: 40px; border-radius: 50%"></div>
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">标题</div>
</div>
<div class="item-subtitle">副标题</div>
<div class="item-text">
占位字符串1<br />
Text line 2
</div>
</div>
</li>
</ul>
</div>
<div class="block-title">骨架屏卡片</div>
<div class="card card-outline skeleton-text">
<div class="card-header">Card Header</div>
<div class="card-content card-content-padding">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
lobortis et massa ac interdum. Cras consequat felis at consequat hendrerit.</div>
<div class="card-footer">Card Footer</div>
</div>
<div class="block-title">加载效果</div>
<div class="block block-strong-ios block-outline-ios">
<p>支持如下的加载效果</p>
<p class="grid grid-cols-3 grid-gap">
<a class="button button-fill button-small button-round" @click=${()=> load('fade')}>Fade淡入</a>
<a class="button button-fill button-small button-round" @click=${()=> load('wave')}>Wave波浪</a>
<a class="button button-fill button-small button-round" @click=${()=> load('pulse')}>pulse跳动</a>
</p>
</div>
<div class="list list-strong-ios list-outline-ios list-dividers-ios media-list">
<ul>
${loading ? $h`
<li class="item-content skeleton-text skeleton-effect-${effect}">
<div class="item-media">
<div class="skeleton-block" style="width: 40px; height: 40px; border-radius: 50%"></div>
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Full Name</div>
</div>
<div class="item-subtitle">Position</div>
<div class="item-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis et massa ac
interdum. Cras consequat felis at consequat hendrerit. Aliquam vestibulum vitae lorem ac iaculis.
Praesent nec pharetra massa, at blandit lectus. Sed tincidunt, lectus eu convallis elementum, nibh nisi
aliquet urna, nec imperdiet felis sapien at enim.</div>
</div>
</li>
<li class="item-content skeleton-text skeleton-effect-${effect}">
<div class="item-media">
<div class="skeleton-block" style="width: 40px; height: 40px; border-radius: 50%"></div>
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Full Name</div>
</div>
<div class="item-subtitle">Position</div>
<div class="item-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis et massa ac
interdum. Cras consequat felis at consequat hendrerit. Aliquam vestibulum vitae lorem ac iaculis.
Praesent nec pharetra massa, at blandit lectus. Sed tincidunt, lectus eu convallis elementum, nibh nisi
aliquet urna, nec imperdiet felis sapien at enim.</div>
</div>
</li>
<li class="item-content skeleton-text skeleton-effect-${effect}">
<div class="item-media">
<div class="skeleton-block" style="width: 40px; height: 40px; border-radius: 50%"></div>
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Full Name</div>
</div>
<div class="item-subtitle">Position</div>
<div class="item-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis et massa ac
interdum. Cras consequat felis at consequat hendrerit. Aliquam vestibulum vitae lorem ac iaculis.
Praesent nec pharetra massa, at blandit lectus. Sed tincidunt, lectus eu convallis elementum, nibh nisi
aliquet urna, nec imperdiet felis sapien at enim.</div>
</div>
</li>
` : $h`
<li class="item-content">
<div class="item-media">
<img src="https://placeimg.com/80/80/people/1" style="width: 40px; height: 40px; border-radius: 50%" />
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">John Doe</div>
</div>
<div class="item-subtitle">CEO</div>
<div class="item-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis et massa ac
interdum. Cras consequat felis at consequat hendrerit. Aliquam vestibulum vitae lorem ac iaculis.
Praesent nec pharetra massa, at blandit lectus. Sed tincidunt, lectus eu convallis elementum, nibh nisi
aliquet urna, nec imperdiet felis sapien at enim.</div>
</div>
</li>
<li class="item-content">
<div class="item-media">
<img src="https://placeimg.com/80/80/people/2" style="width: 40px; height: 40px; border-radius: 50%" />
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Jane Doe</div>
</div>
<div class="item-subtitle">Marketing</div>
<div class="item-text">Cras consequat felis at consequat hendrerit. Aliquam vestibulum vitae lorem ac
iaculis. Praesent nec pharetra massa, at blandit lectus. Sed tincidunt, lectus eu convallis elementum,
nibh nisi aliquet urna, nec imperdiet felis sapien at enim.</div>
</div>
</li>
<li class="item-content">
<div class="item-media">
<img src="https://placeimg.com/80/80/people/3" style="width: 40px; height: 40px; border-radius: 50%" />
</div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Kate Johnson</div>
</div>
<div class="item-subtitle">Admin</div>
<div class="item-text">Sed tincidunt, lectus eu convallis elementum, nibh nisi aliquet urna, nec imperdiet
felis sapien at enim.</div>
</div>
</li>
`}
</ul>
</div>
</div>
</div>
</template>
<script>
export default (props, { $update }) => {
let loading = false;
let effect = null;
const load = (newEffect) => {
if (loading) return;
effect = newEffect;
loading = true;
$update();
setTimeout(function () {
loading = false;
$update();
}, 3000);
}
return $render;
}
</script>