はじめに
前回の記事ではモデリングで作ったサイトにレスポンシブデザインを実装する方法を解説しました。スマートフォンでも崩れずに表示できるようになったら、次はサイトに動きをつけましょう。今回はCSSアニメーションを使ってサイトを魅力的に演出する方法を解説します。ページを開いたときにフワッと要素が現れる・スクロールに合わせて要素がスライドインする・ボタンにホバーしたときに色が変わるなど、実際のサイトでよく見かける動きをCSSとJavaScriptで実装する方法を一から解説します。
1. CSSアニメーションの基礎
1.1 transitionとanimationの違い
CSSで動きをつける方法は主に2種類あります。
| 種類 | 特徴 | 向いている用途 |
|---|---|---|
transition | 状態が変わったときに滑らかに変化する | ホバー・クリック時の変化 |
animation(@keyframes) | 自動的に繰り返し動く | ローディング・常時アニメーション |
1.2 transitionの基本構文
.button {
background-color: #1A5FC0;
color: white;
padding: 12px 32px;
border-radius: 6px;
border: none;
cursor: pointer;
/* transitionの書き方 */
transition: プロパティ 時間 イージング 遅延;
/* 実際の記述例 */
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #0D3A7A; /* ホバー時に色が0.3秒かけて変わる */
}
transitionの各値の意味:
| 値 | 説明 | 例 |
|---|---|---|
| プロパティ | 変化させるCSSプロパティ | background-color・transform・all |
| 時間 | 変化にかかる秒数 | 0.3s・0.5s |
| イージング | 変化の加速パターン | ease・ease-in-out・linear |
| 遅延 | 変化が始まるまでの待ち時間 | 0s・0.2s |
1.3 @keyframesとanimationの基本構文
/* @keyframesでアニメーションの動きを定義 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* animationプロパティで要素に適用 */
.hero-title {
animation: fadeIn 0.8s ease forwards;
}
animationの各値の意味:
| 値 | 説明 | 例 |
|---|---|---|
| アニメーション名 | @keyframes で定義した名前 | fadeIn |
| 時間 | アニメーションの時間 | 0.8s |
| イージング | 変化の加速パターン | ease・ease-out |
forwards | アニメーション終了後に最後の状態を維持する | forwards |
infinite | 無限に繰り返す | infinite |
2. ホバーアニメーション
2.1 ボタンのホバーアニメーション
/* 基本的なボタンホバー */
.btn {
display: inline-block;
padding: 14px 40px;
background-color: #1A5FC0;
color: white;
border-radius: 6px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
}
.btn:hover {
background-color: #0D3A7A;
transform: translateY(-2px); /* 2px上に浮く */
box-shadow: 0 8px 24px rgba(26, 95, 192, 0.4); /* 影が現れる */
}
.btn:active {
transform: translateY(0); /* クリック時に元の位置に戻る */
box-shadow: none;
}
2.2 カードのホバーアニメーション
.card {
padding: 32px;
background: #fff;
border-radius: 12px;
border: 1px solid #e0e0e0;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-6px); /* 6px上に浮く */
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12);
}
2.3 画像のズームホバー
.works-item {
overflow: hidden; /* はみ出た部分を隠す */
border-radius: 8px;
}
.works-item img {
width: 100%;
transition: transform 0.4s ease;
}
.works-item:hover img {
transform: scale(1.05); /* ホバーで1.05倍に拡大 */
}
2.4 ナビゲーションリンクのアンダーラインアニメーション
.nav-link {
position: relative;
text-decoration: none;
color: #333;
padding-bottom: 4px;
}
/* 疑似要素でアンダーラインを作る */
.nav-link::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0; /* 初期状態は幅0(非表示) */
height: 2px;
background-color: #1A5FC0;
transition: width 0.3s ease;
}
/* ホバー時にアンダーラインが伸びる */
.nav-link:hover::after {
width: 100%;
}
3. ページ読み込み時のアニメーション
3.1 ヒーローセクションのフェードイン
ページを開いたときにタイトルや画像がフワッと現れるアニメーションです。
/* フェードインの定義 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ヒーロータイトル */
.hero-title {
animation: fadeInUp 0.8s ease forwards;
}
/* サブタイトルは少し遅らせて登場 */
.hero-subtitle {
animation: fadeInUp 0.8s ease 0.2s forwards;
opacity: 0; /* アニメーション開始前は非表示 */
}
/* ボタンはさらに遅らせて登場 */
.hero-btn {
animation: fadeInUp 0.8s ease 0.4s forwards;
opacity: 0;
}
💡 animation-delay で時間差登場を演出しましょう: タイトル→サブタイトル→ボタンと順番にフワッと現れることで、洗練された印象を与えられます。遅延時間は 0.1s〜0.3s 程度の差をつけるのがちょうどいいです。
3.2 左右からスライドイン
/* 左からスライドイン */
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-40px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 右からスライドイン */
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(40px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.hero-text {
animation: slideInLeft 0.8s ease forwards;
}
.hero-image {
animation: slideInRight 0.8s ease forwards;
}
4. スクロールアニメーション
4.1 Intersection Observer APIとは
スクロールして要素が画面内に入ったタイミングでアニメーションを発動させるにはIntersection Observer APIを使います。スクロールイベントを使うより軽量でパフォーマンスが良いのが特徴です。
4.2 スクロールでフワッと現れる実装
HTML:
<section class="about">
<div class="fade-in">
<h2>About</h2>
<p>自己紹介のテキストが入ります。</p>
</div>
</section>
<div class="works-grid">
<div class="works-item fade-in">作品1</div>
<div class="works-item fade-in">作品2</div>
<div class="works-item fade-in">作品3</div>
</div>
CSS:
/* アニメーション前の初期状態 */
.fade-in {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.7s ease, transform 0.7s ease;
}
/* JavaScriptでこのクラスを付与したときにアニメーション */
.fade-in.is-visible {
opacity: 1;
transform: translateY(0);
}
JavaScript:
// Intersection Observerの設定
const observer = new IntersectionObserver( ( entries ) => {
entries.forEach( entry => {
if ( entry.isIntersecting ) {
// 画面内に入ったらis-visibleクラスを追加
entry.target.classList.add( 'is-visible' );
// 一度表示したら監視を解除(パフォーマンス向上)
observer.unobserve( entry.target );
}
} );
}, {
threshold: 0.1, // 要素の10%が見えたらトリガー
rootMargin: '0px 0px -50px 0px' // 下から50px手前でトリガー
} );
// fade-inクラスを持つ全要素を監視対象にする
document.querySelectorAll( '.fade-in' ).forEach( el => {
observer.observe( el );
} );
4.3 時間差でカードを順番に表示する
.works-item {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.works-item.is-visible {
opacity: 1;
transform: translateY(0);
}
/* 各カードに時間差をつける */
.works-item:nth-child(1) { transition-delay: 0s; }
.works-item:nth-child(2) { transition-delay: 0.1s; }
.works-item:nth-child(3) { transition-delay: 0.2s; }
.works-item:nth-child(4) { transition-delay: 0.3s; }
5. よく使うアニメーションパターン集
5.1 ローディングスピナー
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid #e0e0e0;
border-top-color: #1A5FC0;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
5.2 パルス(脈打つ)アニメーション
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.badge {
animation: pulse 2s ease-in-out infinite;
}
5.3 フローティング(浮いているように見せる)
@keyframes floating {
0% { transform: translateY(0); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0); }
}
.hero-image {
animation: floating 3s ease-in-out infinite;
}
5.4 テキストのタイピングアニメーション
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink {
50% { border-color: transparent; }
}
.typing-text {
display: inline-block;
overflow: hidden;
white-space: nowrap;
border-right: 2px solid #1A5FC0; /* カーソル */
width: 0;
animation:
typing 2s steps(20) 0.5s forwards,
blink 0.8s step-end infinite;
}
6. アニメーション実装の注意点
6.1 アニメーションが苦手なユーザーへの配慮
視覚的な動きが苦手なユーザー(前庭覚過敏など)のために、OSの設定でアニメーションを減らす設定にしている場合はアニメーションを無効化します。
/* OS設定でアニメーション軽減が有効な場合 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
6.2 パフォーマンスを意識したプロパティ選び
アニメーションさせるプロパティによってパフォーマンスに大きな差があります。
| プロパティ | パフォーマンス | 推奨度 |
|---|---|---|
transform(移動・拡大・回転) | 🟢 高速 | ✅ 積極的に使う |
opacity(透明度) | 🟢 高速 | ✅ 積極的に使う |
background-color・color | 🟡 中程度 | ⚠️ 多用しない |
width・height・top・left | 🔴 低速 | ❌ なるべく使わない |
💡 translateY で動かしましょう: 要素を上下に動かしたい場合は top ではなく transform: translateY() を使います。top はレイアウトの再計算が発生するため重く、transform はGPUで処理されるため高速です。
6.3 アニメーション時間の目安
| 用途 | 推奨時間 |
|---|---|
| ホバー・クリックの反応 | 0.2〜0.3秒 |
| フェードイン・スライドイン | 0.5〜0.8秒 |
| ページ全体の演出 | 0.8〜1.2秒 |
| ローディング・ループアニメーション | 1.0〜2.0秒 |
⚠️ アニメーションは控えめが正解です: 動きが多すぎるとユーザーが疲れてコンテンツに集中できなくなります。「なくてもいい動き」は思い切って削る判断も重要です。
7. 実装チェックリスト
✓ ホバーアニメーションに transition を設定しているか
✓ transform と opacity を優先してアニメーションさせているか
✓ スクロールアニメーションにIntersection Observer APIを使っているか
✓ animation-delay で時間差登場を演出しているか
✓ prefers-reduced-motion でアニメーション軽減設定に対応しているか
✓ アニメーション時間が長すぎず短すぎないか(ホバーは0.3秒以内)
✓ 動きが多すぎてコンテンツが見づらくなっていないか
✓ スマートフォンでもアニメーションが正常に動作しているか
まとめ
今回はCSSアニメーションを使ってサイトに動きをつける方法を解説しました。ポイントをまとめると:
- ホバーの変化には
transition・自動的に動く演出には@keyframesとanimationを使い分ける transformとopacityを使うとGPUで処理されるため高速でなめらかなアニメーションになる- スクロールアニメーションはIntersection Observer APIで実装するとパフォーマンスが良い
- CSSで初期状態(非表示)を定義してJavaScriptでクラスを付与することでスクロールアニメーションが実現できる
animation-delayで時間差をつけると要素が順番に登場する洗練された演出になるprefers-reduced-motionでアニメーションが苦手なユーザーへの配慮を忘れずに
次の記事では、フォームの実装方法を解説します。お問い合わせフォームのHTMLの書き方・CSSでのスタイリング・JavaScriptでのバリデーション(入力チェック)まで一から解説します。お楽しみに!
コメント