Share on

脱JavaScript!CSSスクロールアニメーションを用いた魅力的なデザインの実装方法

脱JavaScript!CSSスクロールアニメーションを用いた魅力的なデザインの実装方法

魅力的なサイトにはアニメーションが効果的に使われています。

コンテンツ内容が充実していても、単調な見せ方ではユーザーの記憶に残りにくいものです。
しかし魅力的なサイトを作るためには制作の深い知識が必要なため、実装は簡単にできません。

そんな悩みにお応えして、今回はWeb制作に必須のCSSと、スクロールアニメーションを用いて魅力的なデザインの実装を試みます。

スクロールアニメーションとは

デバイスを選ばず使えるUXのひとつに「スクロール」があります。
画面を上下に動かす、またはスワイプすることによって発生するものです。

このスクロールに対して、既存のWeb アニメーション API (WAAPI)とCSS アニメーション APIが連携して、スクロールアニメーションの操作を可能とした新しいAPIが生まれました。
それが「Scroll-driven Animations」と「animation-timeline」です。

Scroll-driven Animationsとanimation-timelineについて

Scroll-driven Animationsは、スクロール量に合わせてアニメーションが実装できるAPIです。JavaScriptでも使用できます。

animation-timelineは、アニメーションのタイムラインを指定できるCSS アニメーション APIです。

対応ブラウザについて

「Scroll-driven Animations」と「animation-timeline」は、現在Chrome115、Microsoft Edge115で表示を確認することができます。
Scroll-driven Animations はWorking DraftのAPIのため、限られたブラウザでのみ検証が可能です。

参照

そのためモダンブラウザへの対応はCSSの対応と並行して、従来通りのJavaScriptを使用した実装が望まれるのが現状です。

以上を踏まえて、Chromeから提示されているサンプルをもとに、実際のWEBデザインで使用できそうなデザインを検討していきましょう。

参照

実用的なアニメーションを考えよう

ここからは実装例を見ていきます。

1.インジケーター

再生
/* スクロール方向キーフレーム */
@keyframes vertical {
  from {
    scale: 1 0;
  }
  to {
    scale: 1 1;
  }
}
/* 波キーフレーム */
@keyframes wave {
  from {
    transform:rotate(0deg);
  }
  to {
    transform:rotate(360deg);
  }

.drop {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 150px;
  height: 200px;
  background: rgba(255, 255, 153, 0.5);
  clip-path: path("M131.5,99.4c-0.1-30-25.5-54.3-56.8-54.2S18.3,69.8,18.5,99.8c0.1,17.7,8.9,33.4,22.6,43.3 c-0.7,1.8-0.9,3.9-0.4,6.1c0.7,3.1,2.6,5.3,4.9,6.5l7.1,30.1c0.6,2.6,2.9,4.4,5.5,4.4H61c2.2,5.7,7.7,9.8,14.3,9.8 s12.1-4.1,14.3-9.8h2.1c2.6,0,4.9-1.8,5.5-4.4l7.2-30.1c2.3-1.2,4.3-3.4,9-6.5c0.4-2.1,0.2-4.3-0.4-6.1 C122.7,133.1,131.6,117.2,131.5,99.4L131.5,99.4z M97.8,104.7c-11.5,20-10.9,30.1-10.9,30.2c0.5,1.7-0.6,3.6-2.5,4.3 c-1.9,0.6-4.1-0.4-4.7-2.4c-0.7-2.1-0.8-14.3,11.6-35.9c4.1-7.1,3.7-10.6,3.3-11.3c0,0-0.1-0.1-0.6-0.1c-1.7,0.1-5.1,2.3-7.3,7.7 c0,0.1-0.1,0.2-0.2,4c-1.4,2.5-6.5,10.8-12.9,10.8c-6.4,0-11.5-8.3-12.9-10.8c-0.1-0.1-0.1-0.3-0.2-0.4c-2.2-5.3-5.6-7.5-7.3-7.7 c-0.5,0-0.5,0-0.6,0.1c-0.5,0.7-0.8,4.2,3.3,11.3c12.4,21.5,12.3,33.8,11.6,35.9c-0.3,0.9-1,1.7-1.9,2.2c-0.5,0.2-1.1,0.4-1.7,0.4 c-0.4,0-0.8-0.1-1.2-0.2c-1.9-0.6-2.9-2.6-2.4-4.5c0,0,0.5-11-11-30c-4.7-8.1-5.8-14.9-3.1-19.1c1.6-2.5,4.4-3.8,7.5-3.5 c5.3,0.5,10.6,5.2,13.5,12.2c2,3.5,5.1,6.7,6.2,6.7c1.1,0,4.2-3.1,6.3-6.8c2.8-6.8,8.1-11.6,13.5-12c3.2-0.3,5.9,1,7.5,3.5 C103.6,89.8,102.5,96.6,97.8,104.7z M76.7,32.8c-3.4,0-6.2-2.8-6.2-6.2V6.2c0-3.4,2.8-6.2,6.2-6.2s6.2,2.8,6.2,6.2v24 C82.9,30,80.1,32.8,76.7,32.8L76.7,32.8z M27.7,49.4c-1.8,0-3.5-0.7-4.8-2.2L9.8,31.6C7.6,29,8,25.1,10.6,22.8s6.6-1.9,8.8,0.8 l13.1,15.6c2.2,2.6,1.9,6.6-0.8,8.8C30.5,49,29.1,49.4,27.7,49.4L27.7,49.4z M122.3,49.4c-1.4,0-2.8-0.5-4-1.4 c-2.6-2.2-3-6.1-0.8-8.8l13.1-15.6c2.2-2.6,6.1-3,8.8-0.8s3,1,0.8,8.8l-13.1,15.6C125.9,48.7,124.1,49.4,122.3,49.4L122.3,49.4z");
}
.drop_inner {
  display: block;
  width: 100%;
  height: 100%;
  background: rgba(255, 215, 49, 1);
  transform-origin: bottom;
  animation: vertical linear;
  animation-timeline: scroll();
}
.drop_inner::before,
.drop_inner::after {
  content: "";
  position: absolute;
  left: -50%;
  width: 250%;
  height: 250%;
  background-color:rgba(255, 215, 49, 1);
  animation: wave linear 6s infinite;
}
.drop_inner::before {
  top: -150%;
}
.drop_inner::after {
  top: -160%;
  border-radius: 30% 70% / 30% 50%;
  opacity: 0.5;
  animation-delay: 1.5s;
}

<div class="drop">
  <span class="drop_inner"></span>
</div>

ページをどこまでスクロールしたかを示す進行状況を電球で表現しました。
スクロールすると電球の中に光が満たされ光っているように見えます。
記事ページに使用すると、どこまで読めたかが視覚的にわかりやすいです。

実装例

  • お問い合わせページ等で残りの入力項目数を視覚的に知らせることができます。
  • 目次と併用することでをしおりのような役割を果たすことができます。

2.画像表示

再生
/* 画像出現 */
@keyframes reveal {
  from {
    opacity: 0;
    clip-path: inset(0 350% 0 0);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}
.wp-block-columns {
  text-align: center;
  margin: 20px 0;
}
.wp-block-columns img{
  view-timeline-name: --revealing-image;
  view-timeline-axis: block;
  animation: linear reveal both;
  animation-timeline: --revealing-image;
  animation-range: entry 25% cover 50%;
}
.wp-block-image img{
  width: 100%;
  height: auto;
}

<article>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <div class="wp-block-columns">
    <div class="wp-block-column">
      <figure class="wp-block-image size-large">
        <img decoding="async" width="1450" height="754" src="img/img.png">
      </figure>
    </div>
  </div>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>

スクロールポートに入った時に記事内の画像を表示させています。
CSSだけで実装ができるため、既存サイトへの反映も容易です。

実装例

  • CMSで実装された記事ページに対して表示の改修を行いたい場合に有効です。
  • loading属性やcontent-visibilityプロパティと並行して使用することで表示高速化の対応と合わせて描画の表示を制御することができます。

3.コンテンツ切り替え

再生
/* マスク */
@keyframes reveal-sky {
  from {
    clip-path: ellipse(0px 0px);
  }
  to {
    clip-path: ellipse(50% 50%);
  }
}
.btn {
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #ededed;
}
.btn__mask {
  width: 100%;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn__mask img{
  animation: reveal-sky linear both;
  animation-timeline: view();
  animation-range: contain 50% contain 100%;
}

<section class="btn">
  <div class="btn__mask">
    <img src="img/shuttle_btn_off.png" width="118" height="118">
  </div>
</section>

スクロールポートに出入りする時にアニメーションを使用しています。
マスク機能を使用してコンテンツの切り替わりを指定することもできます。

実装例

  • コンテンツの切り替わりを視覚的に表現することができます。
  • ページ全体のデザインを表現しやすくなります。

目を引くアニメーションを考えよう

もう一つ例を見てみます。

1.太陽の1日の動き

再生
/* 太陽 */
@keyframes elm {
  from {
    transform:rotate(1.0turn);
  }
  to {
    transform:rotate(0.5turn);
  }
}
@keyframes elmInner {
  0% {
    transform:rotate(1.0turn);
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  75% {
    opacity: 1;
  }
  100% {
    transform:rotate(1.5turn);
    opacity: 0;
  }
}
/* 背景 */
@keyframes gradation{
  0%{
      background-position: 0% 0%;
  }
  100%{
      background-position: 100% 100%;
  }
}
.bg{
  background-image: linear-gradient(to bottom, #080f1c, #115d89, #e4f5ff, #e4f5ff, #00dedc, #ce6009, #a57a4f,#115d89, #080f1c, #080f1c);
  animation: gradation linear;
  animation-timeline: scroll();
  width: 100%;
  height: 1000vh;
}
.town{
  width: 100%;
  position: fixed;
  z-index: 1;
  bottom: 0;
  left: 0;
  text-align: center;
}
.town img{
  width: 1000px;
  height: 100%;
}
.sun{
  position: fixed;
  bottom: 0;
  left: 25%;
  z-index: 0;
  animation:elm linear;
  animation-timeline: scroll();
  width: 50%;
  height: 100px;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
}
.sun img{
  animation:elmInner linear;
  animation-timeline: scroll();
}

<div class="bg">
  <div class="town">
    <img src="img/town.svg" alt="" width="300" height="104">
  </div>
  <div class="sun">
    <img src="img/sun.svg" alt="" width="400" height="200">
  </div>
</div>

太陽の動きをスクロールを使用して再現しました。
日周運動を感覚的に感じることができます。

2.アルバムカバーのリスト

再生
/* 画像 */
@keyframes rotate-cover {
	0% {
		transform: translateX(-100%) rotateY(-45deg);
	}
	35% {
		transform: translateX(0) rotateY(-45deg);
	}
	50% {
		transform: rotateY(0deg) translateZ(1em) scale(1.5);
	}
	65% {
		transform: translateX(0) rotateY(45deg);
	}
	100% {
		transform: translateX(100%) rotateY(45deg);
	}
}
:root {
	--cover-size: 15rem;
}
.cards, .cards * {
	box-sizing: border-box;
	margin: 0;
	padding: 0;
}
.cards {
	white-space: nowrap;
	--size: 6;
	width: calc(var(--cover-size) * var(--size));
	min-height: calc(var(--cover-size) * 2.5);
	margin: 0 auto;
	padding: calc(var(--cover-size) / 3 * 2) 0;
	position: relative;
}
.cards li {
	display: inline-block;
	width: var(--cover-size);
	height: var(--cover-size);
	view-timeline-name: --li-in-and-out-of-view;
	view-timeline-axis: inline;
	animation: linear adjust-z-index both;
	animation-timeline: --li-in-and-out-of-view;
	perspective: 40em;
	position: relative;
	z-index: 1;
	will-change: z-index;
	user-select: none;
}
.cards li:first-of-type {
	margin-left: calc(50% - (var(--cover-size) / 2));
}
.cards li:last-of-type {
	margin-right: calc(50% - (var(--cover-size) / 2));
}
.cards li > img {
	display: block;
	width: var(--cover-size);
	height: var(--cover-size);
	-webkit-box-reflect: below 0.5em linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.25));
	animation: linear rotate-cover both;
	animation-timeline: --li-in-and-out-of-view;
	transform: translateX(-100%) rotateY(-45deg);
	will-change: transform;
}

<ul class="cards">
	<li>
		<img src="img/img_character01.png" width="200" height="200">
	</li>
	<li>
		<img src="img/img_character02.png" width="200" height="200">
	</li>
	<li>
		<img src="img/img_character03.png" width="200" height="200">
	</li>
	<li>
		<img src="img/img_character04.png" width="200" height="200">
	</li>
	<li>
		<img src="img/img_character05.png" width="500" height="500">
	</li>
</ul>

スクロールは横の動きに対応しています。
デザインの凝ったスライドショーを実装することもできます。

実装懸念点

実装するにあたり、懸念点となりそうなのは、以下の3点です。

1.動作を促すアイテムを配置

上記のアニメーションを再生するにはスクロールをしないといけないため、動作を促すアイテムを配置するべきです。
例えば、矢印や「スクロール」というテキストを使用します。

2.複雑なアニメーションに不向き

CSSを使用しているため低い学習コストで習得ができ、使用するファイルも軽量で表示速度にも影響を与えませんが、複雑なアニメーションを表現するには不向きです。従来通りのJavaScriptでの実装も検討したほうが良い場面もあります。

3.長文コンテンツ

スクロールを使用するため長文コンテンツ(ゾンビスクロール)となります。反対にどうしても長文のコンテンツになる場合には、読ませるのにユーザーが集中力を失うことなく下部までスクロールさせることができるでしょう。

まとめ

今回はCSSで実装できる、スクロールアニメーションの実装方法をご紹介しました。

これからCSSで表現できるアニメーションも増えていくと思いますので、組み合わせて魅力的なWebデザインを作成していきたいですね。

クーシーブログ編集部

この記事を書いた人

クーシーブログ編集部

1999年に設立したweb制作会社。「ラスクル」「SUUMO」「スタディサプリ」など様々なサービスの立ち上げを支援。10,000ページ以上の大規模サイトの制作・運用や、年間約600件以上のプロジェクトに従事。クーシーブログ編集部では、数々のプロジェクトを成功に導いたメンバーが、Web制作・Webサービスに関するノウハウやハウツーを発信中。

お問い合わせはこちらから

Web制作デザイン、丸ごとお任せ

お問い合わせする

Share on

お問い合わせはこちら

CATEGORY LIST