mirror of
https://github.com/jgthms/bulma.git
synced 2024-12-12 13:28:30 +00:00
417 lines
12 KiB
HTML
417 lines
12 KiB
HTML
---
|
|
title: Skeletons in Bulma
|
|
layout: docs
|
|
markdown: true
|
|
theme: features
|
|
doc-tab: features
|
|
doc-subtab: skeletons
|
|
breadcrumb:
|
|
- home
|
|
- documentation
|
|
- features
|
|
- features-skeletons
|
|
---
|
|
|
|
{% capture title_is_skeleton %}
|
|
<h1 class="title is-skeleton">
|
|
Title
|
|
</h1>
|
|
{% endcapture %}
|
|
|
|
{% capture title_has_skeleton %}
|
|
<h1 class="title has-skeleton">
|
|
Title
|
|
</h1>
|
|
{% endcapture %}
|
|
|
|
{% capture subtitle_is_skeleton %}
|
|
<h2 class="subtitle is-skeleton">
|
|
Subtitle
|
|
</h2>
|
|
{% endcapture %}
|
|
|
|
{% capture subtitle_has_skeleton %}
|
|
<h2 class="subtitle has-skeleton">
|
|
Subtitle
|
|
</h2>
|
|
{% endcapture %}
|
|
|
|
{% capture title_and_subtitle_is_skeleton %}
|
|
<h1 class="title is-skeleton">
|
|
Title
|
|
</h1>
|
|
<h2 class="subtitle is-skeleton">
|
|
Subtitle
|
|
</h2>
|
|
{% endcapture %}
|
|
|
|
{% capture title_and_subtitle_has_skeleton %}
|
|
<h1 class="title has-skeleton">
|
|
Title
|
|
</h1>
|
|
<h2 class="subtitle has-skeleton">
|
|
Subtitle
|
|
</h2>
|
|
{% endcapture %}
|
|
|
|
{% capture skeleton_block %}
|
|
<div class="skeleton-block"></div>
|
|
{% endcapture %}
|
|
|
|
{% capture skeleton_block_with_text %}
|
|
<div class="skeleton-block">
|
|
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
|
|
Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh,
|
|
ut fermentum massa justo sit amet risus. Donec sed odio dui.
|
|
Nullam quis risus eget urna mollis ornare vel eu leo.
|
|
Cum sociis natoque penatibus et magnis dis parturient montes,
|
|
nascetur ridiculus mus. Nullam id dolor id
|
|
nibh ultricies vehicula ut id elit.
|
|
</div>
|
|
{% endcapture %}
|
|
|
|
{% capture skeleton_lines %}
|
|
<div class="skeleton-lines">
|
|
<div></div>
|
|
<div></div>
|
|
<div></div>
|
|
<div></div>
|
|
<div></div>
|
|
</div>
|
|
{% endcapture %}
|
|
|
|
{% capture markdown %}
|
|
A skeleton loader is a loading state that acts as a **placeholder** for content in an interface.
|
|
Bulma v1 ships with 2 skeleton elements, and skeleton variants for most Bulma components.
|
|
|
|
All skeleton loaders share these CSS variables:
|
|
|
|
```css
|
|
:root {
|
|
--bulma-skeleton-background: var(--bulma-border);
|
|
--bulma-skeleton-radius: var(--bulma-radius-small);
|
|
--bulma-skeleton-block-min-height: 4.5em;
|
|
--bulma-skeleton-lines-gap: 0.75em;
|
|
--bulma-skeleton-line-height: 0.75em;
|
|
}
|
|
```
|
|
{% endcapture %}
|
|
|
|
{% include markdown.html content=markdown %}
|
|
|
|
{% include docs/elements/anchor.html name="Skeleton Block" %}
|
|
|
|
{% capture markdown %}
|
|
The skeleton block is a simple block element with a pulsating background. It has a minimum height of `4.5em`.
|
|
{% endcapture %}
|
|
|
|
{% include markdown.html content=markdown %}
|
|
|
|
{% include docs/elements/snippet.html content=skeleton_block %}
|
|
|
|
{% capture markdown %}
|
|
If you insert text inside this block, you can make its height responsive:
|
|
{% endcapture %}
|
|
|
|
{% include markdown.html content=markdown %}
|
|
|
|
{% include docs/elements/snippet.html content=skeleton_block_with_text %}
|
|
|
|
{% include docs/elements/anchor.html name="Skeleton Lines" %}
|
|
|
|
{% capture markdown %}
|
|
The skeleton lines element is a loading element which resembles a **paragraph**. Each `<div></div>` will render as a separate loading line.
|
|
{% endcapture %}
|
|
|
|
{% include markdown.html content=markdown %}
|
|
|
|
{% include docs/elements/snippet.html content=skeleton_lines %}
|
|
|
|
{% include docs/elements/anchor.html name="Bulma components with skeletons" %}
|
|
|
|
{% capture markdown %}
|
|
Most Bulma elements and components have a skeleton variant, which can be enabled by adding either the `is-skeleton` or `has-skeleton` modifier.
|
|
{% endcapture %}
|
|
|
|
{% include markdown.html content=markdown %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Button" %}
|
|
|
|
{% capture button_skeleton %}
|
|
<div class="buttons">
|
|
<button class="button is-skeleton">Button</button>
|
|
<button class="button is-link is-skeleton">Link</button>
|
|
<button class="button is-primary is-skeleton">Primary</button>
|
|
<button class="button is-success is-skeleton">Success</button>
|
|
<button class="button is-info is-skeleton">Info</button>
|
|
<button class="button is-warning is-skeleton">Warning</button>
|
|
<button class="button is-danger is-skeleton">Danger</button>
|
|
</div>
|
|
{% endcapture %}
|
|
{% include docs/elements/snippet.html content=button_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Icon" %}
|
|
|
|
{% capture icon_skeleton %}
|
|
<span class="icon is-skeleton">
|
|
<i class="fas fa-reply"></i>
|
|
</span>
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=icon_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Image" %}
|
|
|
|
{% capture image_skeleton %}
|
|
<figure class="image is-16x16 is-skeleton">
|
|
<img alt="Placeholder" src="https://placehold.co/16x16">
|
|
</figure>
|
|
|
|
<figure class="image is-32x32 is-skeleton">
|
|
<img alt="Placeholder" src="https://placehold.co/32x32">
|
|
</figure>
|
|
|
|
<figure class="image is-64x64 is-skeleton">
|
|
<img alt="Placeholder" src="https://placehold.co/64x64">
|
|
</figure>
|
|
|
|
<figure class="image is-128x128 is-skeleton">
|
|
<img alt="Placeholder" src="https://placehold.co/128x128">
|
|
</figure>
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=image_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Media Object" %}
|
|
|
|
{% capture media_skeleton %}
|
|
|
|
<article class="media">
|
|
<figure class="media-left">
|
|
<p class="image is-64x64 is-skeleton">
|
|
<img src="https://placehold.co/128x128" alt="Placeholder image">
|
|
</p>
|
|
</figure>
|
|
<div class="media-content">
|
|
<div class="content is-skeleton">
|
|
<p>
|
|
<strong>John Smith</strong> <small>@johnsmith</small> <small>31m</small>
|
|
<br>
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ornare magna eros, eu pellentesque tortor
|
|
sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus est non commodo luctus,
|
|
nisi erat porttitor ligula, eget lacinia odio sem nec elit
|
|
vestibulum ut. Maecenas non massa sem. Etiam finibus odio quis feugiat facilisis.
|
|
</p>
|
|
</div>
|
|
<nav class="level is-mobile">
|
|
<div class="level-left">
|
|
<a class="level-item"><span class="icon is-small is-skeleton"><i class="fas fa-reply"></i></span></a>
|
|
<a class="level-item"><span class="icon is-small is-skeleton"><i class="fas fa-retweet"></i></span></a>
|
|
<a class="level-item"><span class="icon is-small is-skeleton"><i class="fas fa-heart"></i></span></a>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
<div class="media-right">
|
|
<button aria-label="delete" class="delete is-skeleton"></button>
|
|
</div>
|
|
</article>
|
|
{% endcapture %}
|
|
|
|
{% capture media_skeleton_bis %}
|
|
|
|
<article class="media">
|
|
<figure class="media-left">
|
|
<p class="image is-64x64 is-skeleton">
|
|
<img src="https://placehold.co/128x128" alt="Placeholder image">
|
|
</p>
|
|
</figure>
|
|
<div class="media-content">
|
|
<div class="field">
|
|
<p class="control">
|
|
<textarea class="textarea is-skeleton" placeholder="Add a comment..."></textarea>
|
|
</p>
|
|
</div>
|
|
<nav class="level">
|
|
<div class="level-left">
|
|
<div class="level-item">
|
|
<a class="button is-info is-skeleton">Submit</a>
|
|
</div>
|
|
</div>
|
|
<div class="level-right">
|
|
<div class="level-item">
|
|
<label class="checkbox is-skeleton"> <input type="checkbox"> Press enter to submit </label>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
</article>
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=media_skeleton %}
|
|
{% include docs/elements/snippet.html content=media_skeleton_bis %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Notification" %}
|
|
|
|
{% capture notification_skeleton %}
|
|
<div class="notification is-skeleton">
|
|
Curabitur blandit tempus porttitor. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
|
|
</div>
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=notification_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Tag" %}
|
|
|
|
{% capture tag_skeleton %}
|
|
<span class="tag is-skeleton">Tag</span>{% for color in site.data.colors.justColors %}
|
|
<span class="tag is-{{ color }} is-skeleton">{{ color | capitalize }}</span>{% endfor %}
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=tag_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Title and Subtitle" %}
|
|
|
|
The `.title` and `.subtitle` elements have both an `is-skeleton` and `has-skeleton` variant:
|
|
|
|
* `is-skeleton` will turn the whole block into a loading skeleton
|
|
* `has-skeleton` will turn only a small part of its content into a loading skeleton, to simulate loading only the inner text rather than the whole block
|
|
|
|
{% include docs/elements/snippet.html content=title_is_skeleton %}
|
|
{% include docs/elements/snippet.html content=title_has_skeleton %}
|
|
{% include docs/elements/snippet.html content=subtitle_is_skeleton %}
|
|
{% include docs/elements/snippet.html content=subtitle_has_skeleton %}
|
|
{% include docs/elements/snippet.html content=title_and_subtitle_is_skeleton %}
|
|
{% include docs/elements/snippet.html content=title_and_subtitle_has_skeleton %}
|
|
|
|
{% include docs/elements/anchor-bis.html name="Form Controls" %}
|
|
|
|
{% capture input_skeleton %}
|
|
<input class="input is-skeleton">
|
|
{% endcapture %}
|
|
|
|
{% capture textarea_skeleton %}
|
|
<textarea class="textarea is-skeleton"></textarea>
|
|
{% endcapture %}
|
|
|
|
{% include docs/elements/snippet.html content=input_skeleton %}
|
|
{% include docs/elements/snippet.html content=textarea_skeleton %}
|
|
|
|
<div class="skeleton-toggler display-flex align-items-center gap-2">
|
|
<button id="js-toggle-skeleton" class="button">
|
|
<div id="js-timer" class="timer is-active">
|
|
<div class="timer-mask"></div>
|
|
</div>
|
|
<span class="mr-2">Toggle Skeleton Animations</span>
|
|
<span class="tag is-success" style="margin-right: -0.5rem;">Active</span>
|
|
</button>
|
|
</div>
|
|
|
|
<style type="text/css">
|
|
.timer {
|
|
--duration: 2;
|
|
--size: 1.5;
|
|
--background: var(--bulma-border-weak);
|
|
--foreground: var(--bulma-danger);
|
|
animation-duration: calc(var(--duration) * 1s);
|
|
animation-iteration-count: infinite;
|
|
animation-timing-function: steps(1000, start);
|
|
background: linear-gradient(90deg, var(--foreground) 50%, var(--background) 50%);
|
|
border-radius: 100%;
|
|
height: calc(var(--size) * 1em);
|
|
margin: 0 0.5rem 0 -0.5rem;
|
|
mask: radial-gradient(transparent 0%, transparent 29%, #000 30%, #000 100%);
|
|
position: relative;
|
|
width: calc(var(--size) * 1em);
|
|
}
|
|
|
|
.timer.is-active {
|
|
--foreground: var(--bulma-success);
|
|
animation-name: anim-timer;
|
|
}
|
|
|
|
.timer.is-active .timer-mask {
|
|
animation-name: anim-timer-mask;
|
|
}
|
|
|
|
.timer-mask {
|
|
animation-duration: calc(var(--duration) * 1s);
|
|
animation-iteration-count: infinite;
|
|
animation-timing-function: steps(500, start);
|
|
border-radius: 100% 0 0 100% / 50% 0 0 50%;
|
|
height: 100%;
|
|
left: 0;
|
|
position: absolute;
|
|
top: 0;
|
|
transform-origin: 100% 50%;
|
|
width: 50%;
|
|
}
|
|
|
|
@keyframes anim-timer {
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
@keyframes anim-timer-mask {
|
|
0% {
|
|
background: var(--background);
|
|
transform: rotate(0deg);
|
|
}
|
|
50% {
|
|
background: var(--background);
|
|
transform: rotate(-180deg);
|
|
}
|
|
50.01% {
|
|
background: var(--foreground);
|
|
transform: rotate(0deg);
|
|
}
|
|
100% {
|
|
background: var(--foreground);
|
|
transform: rotate(-180deg);
|
|
}
|
|
}
|
|
|
|
</style>
|
|
|
|
<script type="text/javascript">
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const hasSkeletons = document.querySelectorAll('.has-skeleton');
|
|
const isSkeletons = document.querySelectorAll('.is-skeleton');
|
|
const timer = document.getElementById('js-timer');
|
|
const toggleSkeleton = document.getElementById('js-toggle-skeleton');
|
|
const toggleSkeletonTag = toggleSkeleton.querySelector('.tag');
|
|
|
|
let skeletonInterval = setInterval(toggleSkeletons, 2000);
|
|
|
|
function toggleSkeletonInterval() {
|
|
if (skeletonInterval) {
|
|
clearInterval(skeletonInterval);
|
|
skeletonInterval = null;
|
|
toggleSkeletonTag.className = "tag is-danger is-light";
|
|
toggleSkeletonTag.textContent = "Inactive";
|
|
timer.classList.remove("is-active");
|
|
return;
|
|
} else {
|
|
skeletonInterval = setInterval(toggleSkeletons, 2000);
|
|
toggleSkeletonTag.className = "tag is-success";
|
|
toggleSkeletonTag.textContent = "Active";
|
|
timer.classList.add("is-active");
|
|
}
|
|
}
|
|
|
|
function toggleSkeletons() {
|
|
hasSkeletons.forEach((el) => {
|
|
el.classList.toggle("has-skeleton");
|
|
});
|
|
|
|
isSkeletons.forEach((el) => {
|
|
el.classList.toggle("is-skeleton");
|
|
});
|
|
}
|
|
|
|
toggleSkeleton.addEventListener("click", () => {
|
|
toggleSkeletonInterval();
|
|
});
|
|
});
|
|
</script>
|