
AOSやGSAPなどのライブラリを入れなくても、スクロールで要素がふわっと出てくるアニメーションは作れます。本記事では、CSSと十数行のJavaScriptだけで動くスクロールリビールを、クラス名を付けるだけで使える形にまとめて20パターン紹介します。
使い方はシンプルです。
- 共通のCSSとJSを1回だけ読み込む
- 動かしたい要素に
revealとバリエーション用のクラスを付ける
以前公開したボタンデザイン集24選と同じく、すべてコピー&ペーストで使えます。
記事内のプレビューは表示後の見た目です(枠とカードで示します)。実際のスクロール動作はセットアップ後に確認してください。
はじめに:仕組みの全体像
やることは2つだけです。
- CSS: 初期状態(見えない)と、表示後の状態(見える)を定義する
- JS:
IntersectionObserverで画面に入ったらis-inviewクラスを付ける
クラス名の設計は次のとおりです。
| クラス | 役割 |
|---|---|
reveal | 必須。リビール対象の目印 |
reveal--up など | 動きのバリエーション |
reveal--delay-1 など | 遅延 |
reveal--slow / reveal--fast | 速度 |
reveal--repeat | 画面外に出たら再度隠す |
is-inview | JSが自動付与。手動で書かない |
transform と opacity(必要なら filter / clip-path)だけを動かすので、体感も軽く、ライブラリ不要です。
0. セットアップ(これだけコピペ)
サイトに1回入れれば、あとはHTMLにクラスを足すだけで動きます。
HTML(読み込み例)
<link rel="stylesheet" href="/css/reveal.css" />
<!-- 本文のどこかに -->
<section class="reveal reveal--up">
<h2>見出しが下からふわっと出る</h2>
</section>
<script src="/js/reveal.js" defer></script>
CSS(reveal.css 全文)
/* ===== Scroll Reveal - base ===== */
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0;
transition-property: opacity, transform, filter, clip-path;
transition-duration: 0.7s;
transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
transition-delay: 0s;
will-change: opacity, transform;
}
.reveal.is-inview {
opacity: 1;
transform: none;
filter: none;
clip-path: none;
}
/* directions */
.reveal--fade { transform: none; }
.reveal--up { transform: translateY(32px); }
.reveal--down { transform: translateY(-32px); }
.reveal--left { transform: translateX(-40px); }
.reveal--right { transform: translateX(40px); }
/* scale / blur / rotate */
.reveal--scale { transform: scale(0.88); }
.reveal--zoomout { transform: scale(1.12); }
.reveal--blur { filter: blur(12px); transform: translateY(12px); }
.reveal--rotate { transform: rotate(-8deg) translateY(24px); }
.reveal--flip {
transform: perspective(800px) rotateX(72deg);
transform-origin: center bottom;
}
/* clip / mask style */
.reveal--clip-up {
opacity: 1;
clip-path: inset(100% 0 0 0);
}
.reveal--clip-left {
opacity: 1;
clip-path: inset(0 100% 0 0);
}
.reveal--circle {
opacity: 1;
clip-path: circle(0% at 50% 50%);
}
.reveal--clip-up.is-inview,
.reveal--clip-left.is-inview,
.reveal--circle.is-inview {
clip-path: inset(0);
}
.reveal--circle.is-inview {
clip-path: circle(75% at 50% 50%);
}
/* image helpers */
.reveal--wipe {
opacity: 1;
clip-path: inset(0 100% 0 0);
}
.reveal--wipe.is-inview {
clip-path: inset(0);
}
.reveal--kenburns > img {
transform: scale(1.15);
transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal--kenburns.is-inview > img {
transform: scale(1);
}
/* text underline draw */
.reveal--underline {
opacity: 1;
display: inline;
background-image: linear-gradient(currentColor, currentColor);
background-repeat: no-repeat;
background-position: left bottom;
background-size: 0% 2px;
transition: background-size 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal--underline.is-inview {
background-size: 100% 2px;
}
/* stagger: children animate in sequence */
.reveal--stagger > * {
opacity: 0;
transform: translateY(20px);
transition:
opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal--stagger.is-inview > *:nth-child(1) { transition-delay: 0.05s; }
.reveal--stagger.is-inview > *:nth-child(2) { transition-delay: 0.12s; }
.reveal--stagger.is-inview > *:nth-child(3) { transition-delay: 0.19s; }
.reveal--stagger.is-inview > *:nth-child(4) { transition-delay: 0.26s; }
.reveal--stagger.is-inview > *:nth-child(5) { transition-delay: 0.33s; }
.reveal--stagger.is-inview > *:nth-child(6) { transition-delay: 0.40s; }
.reveal--stagger.is-inview > * {
opacity: 1;
transform: none;
}
/* line-by-line text */
.reveal--lines > * {
opacity: 0;
transform: translateY(1em);
transition:
opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal--lines.is-inview > *:nth-child(1) { transition-delay: 0.05s; }
.reveal--lines.is-inview > *:nth-child(2) { transition-delay: 0.15s; }
.reveal--lines.is-inview > *:nth-child(3) { transition-delay: 0.25s; }
.reveal--lines.is-inview > *:nth-child(4) { transition-delay: 0.35s; }
.reveal--lines.is-inview > * {
opacity: 1;
transform: none;
}
/* delays */
.reveal--delay-1 { transition-delay: 0.1s; }
.reveal--delay-2 { transition-delay: 0.2s; }
.reveal--delay-3 { transition-delay: 0.35s; }
.reveal--delay-4 { transition-delay: 0.5s; }
/* speed */
.reveal--fast { transition-duration: 0.4s; }
.reveal--slow { transition-duration: 1.1s; }
}
/* reduced motion: always show content */
@media (prefers-reduced-motion: reduce) {
.reveal,
.reveal--stagger > *,
.reveal--lines > *,
.reveal--kenburns > img {
opacity: 1 !important;
transform: none !important;
filter: none !important;
clip-path: none !important;
transition: none !important;
}
}
JavaScript(reveal.js 全文)
(() => {
const targets = document.querySelectorAll(".reveal");
if (!targets.length) return;
// 動きを抑えたいユーザーは最初から表示
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduce) {
targets.forEach((el) => el.classList.add("is-inview"));
return;
}
const io = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const el = entry.target;
const repeat = el.classList.contains("reveal--repeat");
if (entry.isIntersecting) {
el.classList.add("is-inview");
if (!repeat) io.unobserve(el);
} else if (repeat) {
el.classList.remove("is-inview");
}
}
},
{
threshold: 0.15,
// 画面下端より少し手前で発火(早すぎ/遅すぎを緩和)
rootMargin: "0px 0px -8% 0px",
}
);
targets.forEach((el) => io.observe(el));
})();
これ以降の各パターンは、追加で書くCSSはほぼ不要です。HTMLのクラスを変えるだけです。
1. 基本リビール(5パターン)
セクション見出しやカードの登場に一番よく使う定番です。
1-1. フェードイン
使用シーン: テキストブロック、軽い登場演出
HTML:
<div class="reveal reveal--fade">
コンテンツ
</div>
1-2. 下からスライドアップ
使用シーン: 見出し、CTA、カード一覧の定番
HTML:
<section class="reveal reveal--up">
<h2>セクション見出し</h2>
</section>
1-3. 上からスライドダウン
使用シーン: 通知バー、上部からの登場演出
HTML:
<div class="reveal reveal--down">上から降りてくる</div>
1-4. 左からスライドイン
使用シーン: 2カラム左カラム、タイムライン
HTML:
<article class="reveal reveal--left">左から登場</article>
1-5. 右からスライドイン
使用シーン: 2カラム右カラム、交互レイアウト
HTML:
<article class="reveal reveal--right">右から登場</article>
左右交互にする例:
<div class="feature reveal reveal--left">特徴A</div>
<div class="feature reveal reveal--right">特徴B</div>
<div class="feature reveal reveal--left">特徴C</div>
2. スケール・ブラー・回転(5パターン)
少し個性を出したいときに。やりすぎると重いので、ページ内では1〜2種類に絞るのがおすすめです。
2-1. スケールイン
使用シーン: カード、モーダル風の注目要素
HTML:
<div class="reveal reveal--scale">拡大しながら出現</div>
2-2. ズームアウト(奥から手前)
使用シーン: ヒーロー直下のキャッチ、写真ギャラリー
HTML:
<div class="reveal reveal--zoomout">奥から寄ってくる</div>
2-3. ブラー解除
使用シーン: 写真、引用、フォーカスを当てたい文言
HTML:
<blockquote class="reveal reveal--blur">
ぼやけからシャープに
</blockquote>
2-4. 回転しながら登場
使用シーン: アイコン、バッジ、遊びのあるLP
HTML:
<div class="reveal reveal--rotate">少し傾いて登場</div>
2-5. フリップ(X軸)
使用シーン: カードめくり感、実績数字の強調
HTML:
<div class="reveal reveal--flip">
<strong>120+</strong> projects
</div>
3. クリップ/マスク系(3パターン)
clip-path を使うと、「覆いが取れる」系の演出になります。写真や大きな見出し向きです。
3-1. 下からクリップリビール
使用シーン: 大きな見出し、フル幅ビジュアル
HTML:
<h2 class="reveal reveal--clip-up">切り取られるように表示</h2>
3-2. 左からクリップリビール
使用シーン: 横長バナー、サービス紹介
HTML:
<div class="reveal reveal--clip-left">横方向に開く</div>
3-3. 円形リビール
使用シーン: 円形画像、アバター、ロゴ
HTML:
<img
class="reveal reveal--circle"
src="/images/avatar.jpg"
alt="メンバー写真"
width="160"
height="160"
style="border-radius: 999px; display: block;"
/>
4. スタッガー(順番に出す)
4-1. 子要素を順番にリビール
使用シーン: カードグリッド、特徴リスト、料金プラン
HTML:
<ul class="reveal reveal--stagger" style="display:grid; gap:12px; list-style:none; padding:0;">
<li>カード1</li>
<li>カード2</li>
<li>カード3</li>
<li>カード4</li>
</ul>
親に reveal reveal--stagger を付け、子は普通の要素でOKです。7個以上並べる場合は、CSSの nth-child 遅延を増やしてください。
.reveal--stagger.is-inview > *:nth-child(7) { transition-delay: 0.47s; }
.reveal--stagger.is-inview > *:nth-child(8) { transition-delay: 0.54s; }
5. テキスト系(2パターン)
5-1. 行ごとにリビール
使用シーン: キャッチコピー、リード文
HTML:
<h1 class="reveal reveal--lines">
<span style="display:block;">速く、軽く、</span>
<span style="display:block;">ライブラリ不要。</span>
</h1>
行は span か p で分けてください。親の reveal--lines が順番制御します。
5-2. 下線ドロー
使用シーン: キーワード強調、リンク風見出し
HTML:
<p>
大事なのは
<span class="reveal reveal--underline">スクロール体験</span>
です。
</p>
6. 画像系(2パターン)
6-1. ワイプリビール
使用シーン: 実績写真、Before/After、ヒーロー下のビジュアル
HTML:
<figure class="reveal reveal--wipe" style="overflow:hidden; margin:0;">
<img src="/images/work.jpg" alt="制作実績" style="display:block; width:100%; height:auto;" />
</figure>
6-2. ケンバーンズ風ズーム
使用シーン: ヒーロー画像、ストーリー写真
HTML:
<figure class="reveal reveal--kenburns" style="overflow:hidden; margin:0;">
<img src="/images/hero.jpg" alt="" style="display:block; width:100%; height:auto;" />
</figure>
親が is-inview になると、中の img がゆっくりズームアウトします。
7. 便利モディファイア(3パターン)
バリエーションクラスと組み合わせて使います。
7-1. 遅延付き
使用シーン: 同じ行の複数要素をずらして出す
HTML:
<div class="reveal reveal--up">すぐ出る</div>
<div class="reveal reveal--up reveal--delay-2">少し遅れて出る</div>
<div class="reveal reveal--up reveal--delay-3">さらに遅れて出る</div>
7-2. 速度変更
使用シーン: 短いUIは速く、大きなビジュアルはゆっくり
HTML:
<div class="reveal reveal--up reveal--fast">サクッと</div>
<div class="reveal reveal--up reveal--slow">ゆったり</div>
7-3. 繰り返し(画面外に出たら再隐藏)
使用シーン: デモページ、スクロール体験を何度も見せたいLP
HTML:
<section class="reveal reveal--up reveal--repeat">
画面に入るたび再生
</section>
通常は一度きり(unobserve)の方がパフォーマンスもUXも良いです。繰り返しは必要な場所だけに使ってください。
実践レシピ:よくある組み合わせ
カードグリッド
<div class="cards reveal reveal--stagger">
<article>カード1</article>
<article>カード2</article>
<article>カード3</article>
</div>
左右交互の特徴紹介
<section class="reveal reveal--left">左テキスト + 右画像</section>
<section class="reveal reveal--right reveal--delay-1">右テキスト + 左画像</section>
見出し → 本文 → CTA
<h2 class="reveal reveal--up">見出し</h2>
<p class="reveal reveal--up reveal--delay-1">説明文</p>
<a class="reveal reveal--up reveal--delay-2" href="/contact">お問い合わせ</a>
付録A:CSSだけで動かす(モダンブラウザ)
Chrome / Edge / 新しいSafariでは、JSなしの Scroll-Driven Animations も使えます。Firefoxは未対応なので、本記事の本命は IntersectionObserver 方式です。対応ブラウザ向けのおまけとして置きます。
@media (prefers-reduced-motion: no-preference) {
@supports ((animation-timeline: view()) and (animation-range: entry)) {
@keyframes reveal-up {
from {
opacity: 0;
transform: translateY(32px);
}
}
.reveal-css {
animation: reveal-up ease both;
animation-timeline: view();
animation-range: entry 0% entry 40%;
}
}
}
<section class="reveal-css">CSSだけで下から出現</section>
ポイント:
animationのあとにanimation-timeline/animation-rangeを書く(短縮記法で上書きされないように)- 装飾目的なら、未対応ブラウザでは何も動かさず最初から表示、でもよい(プログレッシブエンハンスメント)
付録B:つまずきポイント
動かないとき
.revealが付いているかreveal.jsが読まれているか(defer推奨)- 親に
overflow: hiddenがありすぎて、発火前にクリップされていないか prefers-reduced-motion: reduceの環境では最初から表示される(仕様どおり)
チラつき・ガタつきを減らす
- 動かすのは
opacity/transform/filter/clip-pathに限定 - 同時に大量の
.revealを画面内に置かない - 画像は
width/heightかアスペクト比を指定してレイアウトシフトを防ぐ
WordPress / ノーコードでも使えるか
使えます。テーマやカスタムHTMLブロックにCSS/JSを足し、要素にクラスを付けるだけです。React / Next.js の場合は、クライアント側で同じObserverを一度初期化すればOKです。
"use client";
import { useEffect } from "react";
export function RevealInit() {
useEffect(() => {
// reveal.js と同じ処理をここに置くか、スクリプトを読み込む
}, []);
return null;
}
まとめ
本記事では、ライブラリなしで使えるスクロールリビールを20パターン紹介しました。
覚えることは3つだけ
- 共通CSS + 十数行JSを1回入れる
- 動かしたい要素に
reveal+ バリエーションクラスを付ける - 遅延・速度・繰り返しはモディファイアで足す
選び方の目安
| 目的 | おすすめ |
|---|---|
| 無難に上品 | reveal--up / reveal--fade |
| カード一覧 | reveal--stagger |
| 写真を印象的に | reveal--wipe / reveal--kenburns |
| 見出しを強く | reveal--clip-up / reveal--lines |
| 遊びを出す | reveal--blur / reveal--flip |
ボタンの見た目を整えたい場合は、あわせて【コピペOK】HTMLとCSSで作る実用的なボタンデザイン集24選もどうぞ。UI部品とスクロール演出をセットで入れると、LPの完成度が一気に上がります。

西村 力也
代表取締役
2002年からWeb制作・システム開発に従事。React、Next.js、TypeScriptを中心としたモダンなフロントエンド開発の専門家。AI検索最適化(AIO)の先駆者として、ChatGPT、Perplexity等のAI検索エンジン対応を推進。三重県津市を拠点に、東海地方の企業様のデジタル変革を支援しています。
関連記事

ジオターゲティング広告とは?地域密着型ビジネスの集客を変える最新マーケティング手法
ジオターゲティング広告とは何かをわかりやすく解説。位置情報を活用した集客手法の仕組みやメリット、学習塾・不動産・飲食店・クリニックの成功事例を紹介します。...

非エンジニアでも業務アプリを作れる時代へ — AI内製化研修「NaiseiLAB」をリリース
株式会社エクサソリューションズは、法人向けAI業務アプリ内製化研修サービス「NaiseiLAB(内製ラボ)」を正式リリースいたしました。...

ホームページ制作、実は何度も打ち合わせするんです|三重県の企業が知っておきたい制作の裏側
「ホームページってすぐできるんじゃないの?」という誤解三重県で事業をされている経営者の方から、よくこんな声を聞きます。...