ユーザーに優しいローディング画面「スケルトンスクリーン」

はじめまして。アドベントカレンダー初参戦のフロントエンド1年生です。（1月で2年生👏）
以前ふと耳にした言葉「スケルトンスクリーン」がずっと気になっていたので、これを機に皆さまにも共有できたらと思います。

# スケルトンスクリーンとは
スケルトンスクリーンはご存知ですか？
名前を聞いたことがない方も、きっとどこかで見たことがあると思います。
↓この人です。
![skeleton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927323/266584f0-5b9b-7946-fbd4-a94b31ef9623.png)

ページやコンテンツの読み込み中、真っ白なページが長く続くとユーザーは不安になります。
その不安を解消するため、プログレスバーやぐるぐる回るスピナーを表示して「今、読み込んでますよ」とユーザーに伝える手法が定番でした。
そしてここ数年で新たに見かけるようになったのがスケルトンスクリーンです。

>スケルトンスクリーンは、画像やCSS、JavaScriptを読み込んでいる間にワイヤーフレームのようなボックスを表示し、UXを向上させるために使われる。ユーザにとってはプログレスバーやスピナーと違いどんなページが表示されるか予想できるため、ロード時間が長くても心理的に短く感じられる。
（引用：https://kuroeveryday.blogspot.com/2017/05/load-with-skeleton-screens-and-shimmer-effect.html）

確かに、どこにどんな形で表示されるのかわかるので、
ただ真ん中でスピナーが1つグルグル表示されているよりは、ストレスも軽減されますね！！
YouTubeやSlackやQiitaなど、さまざまなサイトで見かけるようになりましたが、
なんだか実装難しそう・・・
ということで、調べながらですが挑戦してみました。

# 実装
手順は3つ！
1. コンテンツを用意
2. loadingクラスでスケルトンスクリーン作成
3. 画像の読み込みが終わったタイミングで、loadingクラスを非表示にする

今回の題材は、お正月も近いので干支にしました。
<img width="400" alt="contents" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927323/92e43c92-adbf-cb17-2745-19425b434d76.png">

コンテンツが用意できたらHTMLとCSSでこの子のスケルトンスクリーンを作成します。

```html:index.html
<ul class="list">
  <li class="item">
    <div class="item__img">
      <!-- 画像部分のスケルトンスクリーン -->
      <div class="loading" data-js="loading">
        <span class="loading__img"></span>
      </div>
      <img class="img"
      src="/images/nezumi.png"
      />
    </div>
    <div class="item__text">
      <!-- テキスト部分のスケルトンスクリーン -->
      <div class="loading" data-js="loading">
        <span class="loading__line"></span>
        <span class="loading__line"></span>
        <span class="loading__line"></span>
      </div>
      <dl class="text">
        <dt class="text__title">ねずみ（子）</dt>
        <dd class="text__description">すぐに子ねずみが増え成長することから、子孫繁栄の意味があります。</dd>
      </dl>
    </div>
  </li>
</ul>
```
```css:style.css
.loading {
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  background: #fff;
  overflow: hidden;
  z-index: 50;
}

/* キラキラエフェクトのアニメーション */
@keyframes skeleton-animation {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

.loading::before {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.2),
    transparent
  );
  animation: skeleton-animation 1.2s linear infinite;
}

/* 画像部分のスケルトンスクリーン */
.loading__img {
  display: block;
  width: 100%;
  height: 100%;
  background-color: #e2e2e2;
  border-radius: 50%;
}

/* テキスト部分のスケルトンスクリーン */
.loading__line {
  display: block;
  margin-top: 10px;
  height: 20px;
  background-color: #e2e2e2;
}

/* スケルトンスクリーンを非表示にするクラス */
.loading--hidden {
  display: none;
}
```
![skeleton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927323/7a988ea1-2090-c611-57ed-0311c5f0bcad.png)
こんな感じに、コンテンツの画像・テキストをシルバーのスクリーンで覆うイメージです。

そして最後にJSです。
画像の読み込みが終わったら```data-js='loading'```の要素のクラスに```loading--hidden```を追加して非表示にしてあげるだけです。

```javascript:main.js
// ローディングの要素取得
const loadingItem = document.querySelectorAll("[data-js=loading]");

// loading非表示クラスを追加
const hideLoading = (list, className) => {
  list.forEach((element) => {
    element.classList.add(className);
  });
};

window.onload = () => {
  hideLoading(loadingItem, "loading--hidden");
};
```
![skeleton.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927323/8e137b09-362d-dd6e-41b9-1d979ee7cc4b.gif)
このように、ローディング中の数秒間だけスケルトンスクリーンが表示されるようになりました！

# 完成
ねずみだけだと寂しいので、仲間を増やして完成です。
とてもとてもいい感じな気がします。
※コードはこちら：[GitHub](https://github.com/nbx-yamazaki/skeleton-screen)

![skeleton2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927323/24face04-96f7-a418-7d7a-f57e1b53ce6c.gif)

# おわりに
スケルトンスクリーンの実装は思ったよりも難しくはなく、案外シンプルに実装できました。
しかし、

- 読み込みが早い場合はコンテンツ表示時に一瞬ちらつくな…
- コンテンツの文字数が増えたらはみ出しそうだな…
- スクロールに合わせて画像を読み込み開始にしたらさらに良いかも…

など、いろいろ改善の余地はありそうです。
また、従来のスピナーやプログレスバーとの効果的な使い分けについても、もう少し探っていけたらと思います。

ストレスフリーなローディング画面を目指して！！！！

# 参考

- [ロード中に表示するシマー効果付きスケルトンスクリーンを実装する](https://kuroeveryday.blogspot.com/2017/05/load-with-skeleton-screens-and-shimmer-effect.html)
- [CSSでスケルトンスクリーンを表現する](https://tech.arc-one.jp/skeleton-screen/)
- [【UX】読み込み中に表示させるスケルトンスクリーンの必要性と解釈](https://ws-design.net/skeleton_screen/)
- [干支の画像](https://www.irasutoya.com/2014/10/blog-post_8.html)、[干支の由来](https://www.eto12.com/junishi08.html)