Google っぽいプリローダーを CSS だけで作る

Lea Verou 氏の Blog に、CSS のみで、Google の Web アプリケーションで使われているようなプリローダーを作るっていう記事がアップされていましたので紹介。簡単なソース解説も。

Lea Verou 氏の Blog に、CSS のみで、Google の Web アプリケーションで使われているようなプリローダー (画面ロード中に表示されるインジケーター) を作るっていう記事がアップされていましたので紹介。

CSS だけで再現しているため、サイズの調整などにも柔軟に対応できます。

基本的には元記事のソースコードを見ればわかると思いますので、簡単にだけ紹介しますが、プリローダーの HTML に関しては、下記のような感じでシンプル。

<div class="progress">Loading...</div>

元記事ではサイズバリエーションのため、下記のような class を追加したものも併記されています。

<div class="small progress">Loading...</div>
<div class="large progress">Loading...</div>

CSS のソースは下記のような感じ。

/**
 * Flexible Google-style progress indicator
 */
@keyframes progress {
  50% { border-width: .5em 0; }
  to { border-width: .5em 0 0 0; }
}
@keyframes rotate {
  to { transform: rotate(-270deg); }
}
.progress {
  display: inline-block;
  font-size: 50px; /* Size of the progress indicator */
  width: 1em;
  height: 1em;
  border: solid white;
  border-top-color: #ddd;
  border-width: 0 0 .5em 0;
  border-radius: 50%;
  box-sizing: border-box;
  margin: .1em .2em;
  background: linear-gradient(white 50%, #ddd 50%);
  background-origin: border-box;
  transform: rotate(90deg);
  animation: rotate 1s steps(4) infinite,
             progress .25s linear infinite alternate;
  text-indent: 99em;
  overflow: hidden;
}
.progress.small { font-size: 16px; }
.progress.large { font-size: 100px; }

ただし、実際に現状の最新ブラウザで動作させるには、いくつかベンダプレフィックス付きの記述を加える必要があります。それを足すと下記のような感じ。

/**
 * Flexible Google-style progress indicator
 */
@-webkit-keyframes progress {
  50% { border-width: .5em 0; }
  to { border-width: .5em 0 0 0; }
} /*for Chrome*/
@-webkit-keyframes rotate {
  to { -webkit-transform: rotate(-270deg); }
} /*for Chrome*/
@keyframes progress {
  50% { border-width: .5em 0; }
  to { border-width: .5em 0 0 0; }
}
@keyframes rotate {
  to { transform: rotate(-270deg); }
}
.progress {
  display: inline-block;
  font-size: 50px; /* Size of the progress indicator */
  width: 1em;
  height: 1em;
  border: solid white;
  border-top-color: #ddd;
  border-width: 0 0 .5em 0;
  border-radius: 50%;
  -moz-box-sizing: border-box; /*for Firefox*/
  box-sizing: border-box;
  margin: .1em .2em;
  background: linear-gradient(white 50%, #ddd 50%);
  background-origin: border-box;
  -webkit-transform: rotate(90deg); /*for Chrome*/
  transform: rotate(90deg);
  -webkit-animation: rotate 1s steps(4) infinite,
             progress .25s linear infinite alternate; /*for Chrome*/
  animation: rotate 1s steps(4) infinite,
             progress .25s linear infinite alternate;
  text-indent: 99em;
  overflow: hidden;
}
.progress.small { font-size: 16px; }
.progress.large { font-size: 100px; }

font-size プロパティに指定した値が、プリローダーのサイズになります。width、height プロパティで 1em が指定されていますので、font-size: 50px; と指定すれば、50px 四方サイズのプリローダーができあがるというわけ。

ちょっとした解説

簡単に各ソースコードを解説してみます。まず、text-indent: 99em;overflow: hidden; はお決まりのやつですね。さらに、border-radius プロパティで要素を円形にしています。

つまり、下記までの指定で

.progress {
  display: inline-block;
  font-size: 50px;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  text-indent: 99em;
  overflow: hidden;
}

50px 四方の円形の要素ができているわけ (この状態だと背景色が transparent 値なので見えないと思うけど)。

次に、border 関連の指定と、background 系の指定が加わることで半月状になるやつの基礎となります。そこだけ抜き出すと下記のような感じですね。

.progress {
  border: solid white;
  border-top-color: #ddd;
  border-width: 0 0 .5em 0;
  background: linear-gradient(white 50%, #ddd 50%);
  background-origin: border-box;
}

また、box-sizing: border-box; も加わりますが、これは初期値の content-box のままだと、 border-width の変化によって、円が楕円形になってしまいますので、必要な指定です。これで下記のような指定まできました (margin プロパティの値は実際の動作には関係ないので適当に変えて大丈夫です)。

.progress {
  display: inline-block;
  font-size: 50px;
  width: 1em;
  height: 1em;
  border: solid white;
  border-top-color: #ddd;
  border-width: 0 0 .5em 0;
  border-radius: 50%;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  margin: .1em .2em;
  background: linear-gradient(white 50%, #ddd 50%);
  background-origin: border-box;
  text-indent: 99em;
  overflow: hidden;
}

でも、ここまで指定してもまだ 「白い丸」 が表示されるだけです。実際には、

  • 上辺だけ #ddd が指定されてるけど、border-width: 0; で見えなくなってるボーダーがあり
  • 下辺だけ white (#fff) が指定された .5em (つまり要素の半分の幅) のボーダーがあり
  • 背景色が、上半分 white (#fff)、下半分 #ddd になっている
  • 円形の要素

ができあがっているというわけですが、見た目上は 「白い丸」 になりますね。

次に、transform プロパティが出てきますが、これで要素を 90度回転させて、さらに、animation 関連の記述が加わります。

.progress {
  transform: rotate(90deg);
  animation: rotate 1s steps(4) infinite,
             progress .25s linear infinite alternate;
}

上記、animation プロパティの指定で、rotate、progress という 2つの animation-name を定義し、それぞれに各プロパティの値を指定しています。ショートハンドで書かれているので、わかりやすく分解すると下記のような指定がそれぞれされていることになります (省略されているプロパティの初期値含む)。

.progress {
  animation-name: rotate;
  animation-duration: 1s;
  animation-timing-function: steps(4);
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-direction: normal;
  animation-play-state: running;
  animation-fill-mode: none;
}
.progress {
  animation-name: progress;
  animation-duration: .25s;
  animation-timing-function: linear;
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-play-state: running;
  animation-fill-mode: none;
}

最後に、@keyframes 規則を使用して、アニメーションさせます。

@keyframes progress {
  50% { border-width: .5em 0; }
  to { border-width: .5em 0 0 0; }
}
@keyframes rotate {
  to { transform: rotate(-270deg); }
}

border プロパティに指定されているボーダーカラーを変えてみたり、アニメーションのスピード (animation-duration プロパティの値) などを変えて動かしてみると、どういう風に動いているのかがわかりやすくなるので、実際にソースコードを手元でいじってみるといいと思いますよ。

一応、こちらで試したサンプルを下記に置いてあります。

参考リンク

記事をここまで御覧頂きありがとうございます。
この記事が気に入ったらサポートしてみませんか?