【CSS アニメーション】@keyframesとanimationでアニメGIFより軽いガラポン抽選画面の作り方

Pocket

スマートフォン向けのブラウザに「リッチなアニメGIF」を掲載する場合、20枚程度のパラパラアニメでつくっても数百KBの容量になってしまい、多くの利用者に見えない負担をさせています。

今回はそういったアニメーションの画像を載せる場合でも

  • 『キレイで』
  • 『なめらかな』
  • 『追加プラグインがいらない』
  • 『容量が軽い』
  • 『消費電力の少ない』

スタイルシート(CSS)だけで実装できるアニメーションの作り方を紹介します。

アニメーションのサンプル

とりあえずサンプルの『カラポン抽選』を回してみましょう→こちら


目次


ブラウザでアニメーションは品質が良い

ブラウザで表示させるWebページのアニメーションは、アニメGIF画像と比較して色数の制約も少なく、部品単位で画像を組み込む場合は、アニメGIFファイルとは違い、ファイル全体の色数制限(256色以内)もないため高品質です。

また三角形や星型、四角形などシンプルな図形であれば、わざわざ部品画像を組み込む必要もなくスタイルで描画したベクトル図形が使用できます。

ベクトル図形については座標データと色番号/グラデーションの設定がスタイルで設定できるので、容量も少なくデバイス解像度にも最適化されて出力された高品質な表示が可能となります。


高フレームレートが可能

アニメーションフレームを増やしていくとヌルヌルとした滑らかな表現に近づいていきますが、アニメGIF画像でその状態を再現すると数百KBの容量が必要になります。

CSSによるアニメーションでは静止画状態の一枚画像部品やベクトル画像を用意すれば、フレーム数による容量の肥大化もなく(50~100KB程度)スクリプトで動きが付けられます。


追加プラグインがいらない

動きの制御についてはJavaScriptは長けておりますが、CSSでもブラウザでの実装対応が進み遜色ない表現が出来るようになってきました。

なにより、JavaScriptは利用者がブラウザでの使用を「オフ」にできるため、ページ表示が機能しない状況が発生します。

CSSはHTMLと同じく標準実装されており、ブラウザ依存の差異はまだまだありますが、機能がオフなる状況はなく問題なく使用できます。


【ソース】HTML

今回のHTMLのマークアップについては、ヘッダーとフッターをテンプレートに含めています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no">
  <link rel="stylesheet" href="style.css">
  <title>リッチアニメーション_HTML</title>
</head>
<body>

<div class="wrapper">

<header class="test_header">
	<img class="pic_test_header" src="img/pic_test_header.png">
</header>

<h1 class="top_h1_txt">当たるキャンペーン!</h1>

<h2 class="top_h2_txt">『赤玉』が出たらアタリ!</h2>


<div class="garapon">

<p class="center4">
	<img class="pic_atari_bg" src="img/atari_bg.png"></img>
</p>

<p class="center3">
	<img class="pic_tama_02" src="img/tama_02.png"></img>
</p>

<p class="center2">
	<img class="pic_test02" src="img/gara_02.png"></img>
</p>

<p class="center1">
	<img class="pic_test01" src="img/gara_01.png"></img>
</p>

<a href="css_anime_test.html" class="btn_01" ontouchstart="">賞品を受けとる</a>

</div>

<div class="footer_space"></div>
<footer class="test_footer">
	<img class="pic_test_footer" src="img/pic_test_footer.png">
</footer>

</div>

</body>
</html>


【ソース】CSS

CSSについて、今回のサンプルはスマートフォン向けにつくっています。

※PCでの表示はスマートフォン風になります

@charset "utf-8";
/* CSS Document */

html {
	font-size:62.5%;/*10pt基準*/
	}

body {
	margin: 0px;/*ページ全体周りの余白がなくなる*/
	font-family: 'Meiryo',"ヒラギノ角ゴ Pro W3","MS Pゴシック","Osaka", sans-serif;
	font-size: 15px; font-size: 1.5rem;
	color:#666666;
	-webkit-tap-highlight-color: rgba(0,0,0,0);/*フォーカスを消す*/
	background: #ffffff;
	/*line-height: 1.2;/*文字行間設定*/
	height: 100%;
	-webkit-touch-callout:none; // リンク長押しのポップアップを無効化
	-webkit-user-select:none; // テキスト長押しの選択ボックスを無効化
	}

.clear { clear:both; }/*レイアウト崩れを防ぐために適切にクリアーしておく。「both」は左右両側の回り込み(float : left ; float : right ;)を解除する*/

.wrapper{
	width: 100%;
	min-height: 100vh;
	margin: 0 auto;
	}

.garapon{
	position: relative;
	width: 375px;
	height: 375px;
	margin: 0 auto 0 auto;
	}

.test_header { /*固定ヘッダー*/
	width: 100%;
	border-bottom: 0.0px solid #efefef;
	position: -webkit-sticky; /* safari対応 */
	position: sticky; top: 0px; /* 上端から0pxのところで固定 */
	overflow: hidden; /*子ボックスを親ボックスに内包。hidden:範囲外は隠す*/
	background: linear-gradient(to top, rgba(255,255,255,1),  #fff 100%);
	margin: 0 auto 0  0;
	filter:alpha(opacity=100);
	filter: drop-shadow(0px 5px 5px rgba(0,0,0,0.05));
	-moz-opacity: 1;
	opacity: 1;
	}

.pic_test_header {
	width: 100%;
	}

.pic_test_footer {
	width: 100%;
	}

.test_footer { /*固定フッター*/
	width: 100%;
	border-bottom: 0.0px solid #efefef;
	position: -webkit-sticky; /* safari対応 */
	position: sticky; top: 100vh;
	overflow: hidden; /*子ボックスを親ボックスに内包。hidden:範囲外は隠す*/
	background: linear-gradient(to top, rgba(255,255,255,1),  #fff 100%);
	margin: 0 auto 0  0;
	filter:alpha(opacity=100);
	filter: drop-shadow(0px -5px 5px rgba(0,0,0,0.05));
	-moz-opacity: 1;
	opacity: 1;
	}

.footer_space { /*フッター空間*/
	width:100%;
	position: sticky; top: 100vh;
	height:30.17px;
	}

.top_h1_txt{
	padding: 2.2rem 0 0 0;
	text-align:center;
	width: 90%;
	margin: 0 auto;
	}

.top_h2_txt{
	padding: 0.5rem 0 0.0rem 0;
	text-align:center;
	width: 90%;
	margin: 0 auto;
	}

.center1{
	position: absolute;
	width: 375px;
	height: 375px;
	margin: 0 auto 0 auto;
	}

.center2{
	position: absolute;
	width: 375px;
	height: 375px;
	margin: 0 auto 0 auto;
	}

.center3{
	position: absolute;
	width: 375px;
	height: 375px;
	margin: 0 auto 0 auto;
	}

.center4{
	position: absolute;
	overflow: hidden;
	width: 375px;
	height: 375px;
	margin: 0 auto 0 auto;
	}


.pic_tama_02 {
	position: relative;
	z-index: -19;
	top:162px;
	left:245px;
	width: 24px;
	height: auto;
	opacity: 0;
	animation: translate 1.5s ;
	animation-delay: 1.8s;
	animation-fill-mode: forwards;
	}

@keyframes translate {

	0% {
	opacity: 1;
	transform: translateX(0px) translateY(0px);
	animation-timing-function: ease-out;
	}

	3% {
	opacity: 1;
	transform: translateX(13px) translateY(12px);
	animation-timing-function: ease-in;
	}

	17% {
	opacity: 1;
	transform: translateX(40px) translateY(90px);
	animation-timing-function: ease-out;
	}

	27% {
	opacity: 1;
	transform: translateX(42px) translateY(65px);
	animation-timing-function: ease-in;
	}

	47% {
	opacity: 1;
	transform: translateX(44px) translateY(90px);
	animation-timing-function: ease-out;
	}

	57% {
	opacity: 1;
	transform: translateX(42px) translateY(80px);
	animation-timing-function: ease-in;
	}

	65% {
	opacity: 1;
	transform: translateX(44px) translateY(90px);
	animation-timing-function: ease-out;
	}

	74% {
	opacity: 1;
	transform: translateX(39px) translateY(90px);

	}

	83% {
	opacity: 1;
	transform: translateX(42px) translateY(90px);
	animation-timing-function: ease-out;
	}

	99.9%,to {
	opacity: 1;
	transform: translateX(39px) translateY(90px);
	}


	}

.pic_atari_bg {
	width:200%;
	position: absolute;
	z-index: -21;
	top:-50%;
	left:-50%;
	opacity: 0;
	animation: rotation_bg 20s linear ;
	animation-delay: 0s;
	animation-fill-mode: forwards;
	/*animation-iteration-count: infinite;*/
	}

@keyframes rotation_bg {
	0% {
	opacity: 0;
	transform: scale(1) rotate(0deg);
	}

	15% {
	opacity: 0;
	transform: scale(1) rotate(0deg);
	}

	16% {
	opacity: 1;
	transform: scale(1) rotate(0deg);
	}


	99.9%,to {
	opacity: 1;
	transform: scale(1) rotate(2160deg);
	}

	}

.pic_test01 {
	position: relative;
	z-index: -10;
	left:41.5px;
	width: 252px;
	height: auto;
	animation-delay: 0s;
	animation: rotation 2s ease 0s 1 alternate none running;
	animation-fill-mode: forwards;
	}

@keyframes rotation {
	0% {
	transform: scale(1) rotate(0deg);
	}

	99.9%,to {
	transform: scale(1) rotate(1080deg);
	}

	}

.pic_test02 {
	position: relative;
	z-index: -11;
	left:17.5px;
	width: 300px;
	margin: 0 0 0 24px;
	height: auto;
	}

.btn_01{
	visibility:hidden;
	opacity: 0;
	text-decoration: none;
	position: absolute;
	z-index: 5;
	width: 50%;
	top: 314px;
	left: 25%;
	font-size: 20px; font-size: 2.0rem;
	color: #fff;
	text-align:center;
	padding: 12px 0 0px 0;
	height: 44px;
	border-radius: 4px;
	margin: 0 auto;
	background: #ff9900;
	animation: delay 3.5s;
	animation-delay: 3.5s;
	animation-fill-mode: forwards;
	}

@keyframes delay {

	0% {
	visibility:hidden;
	opacity: 0;
	}

	99.9%,to {
	visibility:visible;
	opacity: 1;
	}

	}

.btn_01:hover{
	background: #ffcc00;
	}

@media screen and (min-width:800px){/*PC用レスポンシブ設定*/

.wrapper{
	width: 375px;
	margin: 0px auto 0px auto;
	border-radius: 0px;
	border:solid 2px #666666; 
	}


実装につかった主なスタイル

▼position: relative;/absolute;▼

	position: relative;

	position: absolute;

『兄弟要素』を、『親要素』を基準に重ねていくために必須です。
「relative」(相対)「absolute」(絶対)座標の活用と、
「relative」(親)「absolute」(子)の設定としても利用できます。

▼z-index▼

	z-index: 数値;

「position:」と併用して使うことで要素の重ね合わせを調整できます。

「-数値」でより奥に。

「数値」でより手前に。

注意点として、同じ親子関係上の要素でしか適応できません。

▼overflow: hidden;▼

	overflow: hidden;

親要素に設定することで、子要素の”はみ出した”画像などの部分を非表示に出来ます。

今回のサンプルでは、最背面で回転する集中線画像のトリミング表示に使用してます。

▼visibility:hidden;/visible;▼

	visibility:visible;

要素を 表示/非表示 出来ます。

「display:none;」も要素を非表示に出来ますが、
こちらは要素自体が「無いモノ」として扱われるためレイアウトが上に詰まります。
対して
「visibility:hidden;」の場合は、見えなくなるだけで設置した空間は維持するのでレイアウトが変わりません。

▼animation:▼

.●●●{
	animation: delay 3.5s;/*設定秒数遅れて表示*/
	animation-delay: 3.5s;/*設定秒数遅れて表示*/
	animation: rotation 2s ease;/*要素の回転時間*/
	animation-fill-mode: forwards;/*最終フレームのコマで停止*/
	}

@keyframes delay {

	0% {
	opacity: 0;/*透明0*/
	}

	99.9%,to {
	opacity: 1;/*透明100*/
	}

	}

</form>

今回のサンプルでメインとなるアニメーション設定をおこなうスタイルです。

「@keyframes」以下で0~100%(※ブラウザ依存回避目的で99.9%に設定してます)の間を自由にフレームを増やすことが出来ます。

100%が全体量です。

似た機能として「transition」がありますが、こちらはブラウザ依存によりアニメーションが自動開始できない為、今回の使用していません。

擬似クラス「:hover」による「カーソルON」状態をトリガーに、アニメーションをスタートさせることは出来ます。

要素の回転は複数手段があります。

transform: rotate(360deg);


※「deg」は角度

animation: rotation 2s;


※「●s」は秒数(小数点設定可能)


【間違えポイント】スタイルが効かない組み合わせ

便利なCSSは、Web検索するだけでも組み込みたい機能のスタイルが見つけられ、都度調べるだけで実装できますが、なかなか問題なく組み込める状況も多くありません。

主にHTMLタグ要素の理解不足(インライン/ブロック等)と、タグの入れ子状態の認識不足からくるマークアップ構造の適切化が影響します。

自身が作業進める場合は、狙った効果がでていないときはマークアップ構造を図で書き出し、親子兄弟構造(position: absolute;/relative;)と並べて問題点を見つけています。

そういったルールを理解していくには、コーディングを数こなしていくことで備わりますが、さすがに全てのスクリプトを覚えていられないので、いつでも引き出せる『コンポーネント別CSSの事例集』をためていくことが有効です。


今回のサンプルについて

今回の「ガラポン抽選アニメ」に使用した画像は「部品単位」であるため、フォルダ内の画像を差し替えることで、ビジュアルを簡単に変更できます。

そういった点からも、アニメGIF画像での運用よりもCSSアニメーションの方がカスタマイズ性に優れております。

カスタマイズしたサンプル

画像を差し替えたカスタマイズサンプルの確認→こちら


さいごに

iOSでは動作が違ったりブラウザ側のバグも存在しており、まだまだWebデザイナー泣かせではありますが、CSSによるWebアニメーションについてはブラウザスピードもあがりデザイナーにとっては表現力が広がり挑戦し甲斐があるのではないでしょうか。

次回も情報設計に関係した話題をお届け致します。
デジマースのネモトでした。

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です