よくカードUIで見かけるスケルトンローディングを、JavaScriptのsetTimeout()を使って作ってみました。
スケルトンローディングは、ページのローディング時に各要素をローディング中であることが分かるようにするもので、個人的にも進捗が分かるUIは好きです。
そんなスケルトンローディングの作り方について解説します。
setTimeout()
JavaScriptの setTimeout()
は、一定時間後に一度だけ特定の処理をおこなうメソッドです。
setTimeout(関数, 第二引数時間の指定)
第二引数には遅延させたい時間をミリ秒で指定します。ミリ秒なので1秒送らせたかったら「1000」と記述します。
スケルトンローディングのサンプル
早速スケルトンローディングのサンプルです。
ページのロード時に、カード内の画像とテキストに部分をキラキラ調のオーバーレイのレイヤーが表示され、4秒程度たつと、その下の画像とテキストがフェードインして表示されます。
ページロード時にローディングが入るので、ここに到達した時にはローディングが終わっている可能性があります。
その場合は、ボタンの「ページのリロード」を選択して再描画させてみてください。
サンプルのコード
サンプルのコードはHTML・JavaScript・CSSの3つです。順に解説します。
HTML
HTMLは「横並びのカード」と「縦並びのカード」の2種類を、それぞれ ul
のリストタグを親コンテナにして、作っています。
スケルトンローディングは、a
タグのclassに「card」と一緒に「is-loading」を記述して、img
タグやp
タグの中の要素をスケルトンにするようにします。
<div class="cards">
<!-- インナー1 -->
<ul id="cardBlock">
<li class="card is-loading">
<a href="">
<div class="image">
<img src="https://dubdesign.net/wp-content/uploads/2022/02/java_loadinganime-1024x587.jpg" alt="カードの写真">
</div>
<div class="textContent">
<p class="textTitle">タイトル名タイトル名タイトル名タイトル名タイトル名</p>
<p class="textDesc">テキストテキストテキストテキストテキストテキストテキスト</p>
</div>
</a>
</li>
<li class="card is-loading">
<a href="">
<div class="image">
<img src="https://dubdesign.net/wp-content/uploads/2022/02/java_loadinganime-1024x587.jpg" alt="カードの写真">
</div>
<div class="textContent">
<p class="textTitle">タイトル名</p>
<p class="textDesc">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
</div>
</a>
</li>
</ul>
<!-- インナー1 -->
<!-- インナー2 -->
<ul id="cardBlockVertical">
<li class="card is-loading vertical">
<a href="">
<div class="image">
<img src="https://dubdesign.net/wp-content/uploads/2022/02/java_loadinganime-1024x587.jpg" alt="カードの写真">
</div>
<div class="textContent">
<p class="textTitle">タイトル名タイトル名タイトル名</p>
<p class="textDesc">テキストテキストテキストテキストテキストテキストテキスト</p>
</div>
</a>
</li>
<li class="card is-loading vertical">
<a href="">
<div class="image">
<img src="https://dubdesign.net/wp-content/uploads/2022/02/java_loadinganime-1024x587.jpg" alt="カードの写真">
</div>
<div class="textContent">
<p class="textTitle">タイトル名</p>
<p class="textDesc">テキストテキストテキストテキストテキストテキストテキスト</p>
</div>
</a>
</ul>
<!-- インナー2 -->
</div>
JavaScript
JavaScriptは setTimeout()
で、「card」のclassについている「is-loading」を4秒後に削除します。
setTimeout(() => {
document.querySelectorAll(".card").forEach((skel) => {
skel.classList.remove('is-loading');
});
}, 4000);
時間を指定する第二引数では、4000ミリ秒で指定します。ので、タイミングを早くしたり・遅くしたりする場合は、最後の行の「4000」の箇所を書き換えればOKです。
CSS
CSSは大きく分けて、「横並びのカード」と「縦並びのカード」。そして、ローディング中のアニメーションの3つです。
/* インナー1 */
ul#cardBlock {
margin: 15px 0;
list-style: none;
padding: 0;
border: 0;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 20px;
}
li.card {
width: 48%;
position: relative;
}
li.card a {
border-radius: 2px;
background: #fff;
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 2px 3px 0 rgb(0 0 0 / 22%);
cursor: pointer;
transition: 0.2s ease-in-out;
display: flex;
flex-direction: column;
text-decoration: none;
height: 100%;
}
li.card a:hover {
box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%);
transform: translateY(-4px);
}
li.card .image {
position: relative;
}
li.card a p {
color: #313131;
margin: 0;
font-size: 1.2rem;
line-height: 1;
position: relative;
}
.card a .textContent {
padding: 18px 20px;
flex-grow: 1;
}
.textContent p.textTitle {
margin-bottom: 8px;
font-weight: 600;
display: inline-block;
line-height: 1.5;
}
.textContent .textDesc {
font-size: 1rem;
color: #707070;
line-height: 1.5;
}
/* インナー2 */
ul#cardBlockVertical {
margin: 15px 0;
padding: 0;
list-style: none;
border: none;
gap: 15px;
display: flex;
flex-direction: column;
}
li.card.vertical {
width: 100%;
}
li.card.vertical a {
flex-direction: row;
padding: 10px;
align-items: center;
}
li.card.vertical a .image {
width: 45%;
}
li.card.vertical .textContent {
padding: 0;
padding-left: 20px;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
ul#cardBlock li,li.card.vertical a {
width: 100%;
flex-direction: column;
}
li.card.vertical a {
padding: 0;
}
li.card.vertical a .image {
width: 100%;
}
li.card.vertical .textContent {
padding: 18px 20px;
}
}
/* 共通アニメーション */
/* ローディング */
.card.is-loading .image:before, .card.is-loading p:before {
content: "";
background: #eee;
background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%);
border-radius: 5px;
background-size: 200% 100%;
animation: 1.5s shine linear infinite, 4s fadeout ease-in;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
@keyframes shine {
to {
background-position-x: -200%;
}
}
@keyframes fadeout{
0%{
opacity:1;
}
95%{
opacity:1;
}
100%{
opacity:0;
}
}
ローディング中に表示するスケルトンのオーバーレイを :before
の擬似要素で作ります。そして、それを光らせるアニメーションと、ローディング完了後に要素をフェードインさせるよう @keyframes
で指定して、「.is-loading」がついた時にそれらがアニメーションするようにプロパティで記述します。
オーバーレイをかける要素は、inline
にするとキレイです。