スケルトン

Framework7には、改善された知覚パフォーマンスのためのUIであるSkeleton Elementsライブラリ(別名UIスケルトン、スケルトンスクリーン、ゴーストエレメント)が付属しています。

Skeleton ElementsライブラリはすでにFramework7に統合されており、個別にインストールする必要はありません。完全なAPIドキュメントと詳細な例については、公式のSkeleton Elementsドキュメントを参照してください。

スケルトンブロック

スケルトンブロックは、任意の必要なサイズにできる、灰色の背景色を持つ通常のブロック要素です。

スケルトンブロック要素を作成するには、skeleton-blockクラスを持つdiv要素を作成するだけで、固定幅を設定するのがおすすめです。

...
<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>
...

スケルトンテキスト

スケルトンテキストはより興味深いものです。Framework7には、すべての文字を小さな灰色の長方形としてレンダリングする特別な組み込みスケルトンフォントが付属しています。skeleton-textクラスを任意の要素に適用すると、テキストが灰色のブロック/線に変換されます。skeleton-blockに対する利点は、このような「スケルトンテキスト」が完全にレスポンシブであり、そのサイズが実際のテキストサイズを反映することです。

スケルトンテキストフォントは、次の文字セット(「スペース」を含む)をサポートしています

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>
...

スケルトンエフェクト

スケルトン要素は、フェード、ウェーブ、パルスの3つのアニメーション効果もサポートしています。

特別なスケルトンアニメーション効果を有効にするには、スケルトン要素、またはスケルトン要素を含む親要素に次のクラスの1つを追加する必要があります。

CSS変数

以下は、関連するCSS変数(CSSカスタムプロパティ)のリストです。

: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);
}

skeleton.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Skeleton Elements</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block block-strong-ios block-outline-ios">
        <p>Skeleton (or Ghost) elements designed to improve perceived performance and make app feels faster.</p>
        <p>Framework7 comes with two types of such elements: Skeleton Block and Skeleton Text. Skeleton block is a gray
          box that can be used as placeholder for any element. Skeleton text uses special built-in skeleton font to
          render each character of such text as gray rectangle. Skeleton text allows to make such elements responsive
          and feel more natural.</p>
        <p>It can be used in any places and with any elements.</p>
      </div>

      <div class="block-title">Skeleton List</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">Title</div>
              </div>
              <div class="item-subtitle">Subtitle</div>
              <div class="item-text">
                Placeholder text line 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">Title</div>
              </div>
              <div class="item-subtitle">Subtitle</div>
              <div class="item-text">
                Placeholder text line 1<br />
                Text line 2
              </div>
            </div>
          </li>
        </ul>
      </div>

      <div class="block-title">Skeleton Card</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">Loading Effects</div>
      <div class="block block-strong-ios block-outline-ios">
        <p>It supports few loading effects:</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>