ページを下へ読み進めると、見出しや写真が、少し下からふわっと浮かび上がるように出てくる。最近のホームページでよく見かける動きです。CSSの移り変わり(transition)と、要素が画面に入ったことを知らせる短いJavaScriptを組み合わせると、10行ほどで作れます。
区切りの見出しや写真など、「ここから新しい話」と伝えたい場所にだけ使う。本文の段落・ボタン・お知らせのような、すぐ読んでほしいものには使わない。
使うのは、少しずらして薄くしておく transform と opacity(不透明度:濃さ)、なめらかに戻す transition、そして画面に入ったかを見張る IntersectionObserver(インターセクション・オブザーバー)です。後半では、JavaScriptを使わない新しい書き方も紹介します。
完成見本:スクロールすると、ふわっと出てくる
下の枠は、小さな画面(iframe:ページの中に置いた、もう1つのページ)です。中身を自動でスクロールさせています。見出し・写真・カードが、画面に入ってきたところで、ふわっと出てくるのを見てください。下まで行くと、少し止まってから一番上に戻り、もう一度くり返します。
※ 自動でスクロールする仕掛けは、記事で見せるためだけのものです。コピペ用のコードには入っていません。
※ 「動きを減らす」設定をオンにしている方には、自動でスクロールせず、最初から表示しています。理由は後半の「見る人への配慮」で説明します。
コピペ用のコード
まず、1〜4の見本に共通のCSSとJavaScriptです。この2つを入れたうえで、見本ごとのCSSを足します。HTMLは使いたい場所に、CSSはサイトのCSSファイルや、WordPressならテーマの「追加CSS」などに入れます。JavaScriptは、ページの一番下(</body> の直前)に置きます。クラス名の頭の kd-fx は、サイトのほかのデザインと名前がぶつからないようにするための目印です。
1〜4に共通のCSSとJavaScript
/* 1〜4に共通:JavaScriptが動いたときだけ、最初に隠しておく */
.kd-fx-on .kd-fx {
opacity: 0;
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
transition-delay: var(--kd-fx-delay, 0s);
}
/* 画面に入ったら、元の位置・元の濃さに戻す */
.kd-fx-on .kd-fx.is-visible {
opacity: 1;
transform: none;
}
/* 動きを減らす設定の人には、動かさずに濃さだけ変える */
@media (prefers-reduced-motion: reduce) {
.kd-fx-on .kd-fx {
transform: none;
transition: opacity 0.3s ease-out;
transition-delay: 0s;
}
}
/* 印刷するときは、全部見せる */
@media print {
.kd-fx-on .kd-fx {
opacity: 1;
transform: none;
}
}if ('IntersectionObserver' in window) {
document.documentElement.classList.add('kd-fx-on');
const kdFxObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target);
}
});
}, { rootMargin: '0px 0px -10% 0px' });
document.querySelectorAll('.kd-fx').forEach((el) => kdFxObserver.observe(el));
}出したい要素に、kd-fx と、動きの種類のクラス(kd-fx-up など)を付けます。
1. 下からふわっと
いちばん基本の形です。少し下の位置から、薄い状態で上がってきて、元の位置で止まります。見出しや文章のまとまりに使います。
<div class="kd-fx kd-fx-up">
<h3>私たちについて</h3>
<p>小さなお店のホームページを、言葉から一緒に考えます。</p>
</div>.kd-fx-on .kd-fx-up {
transform: translateY(24px);
}2. 横からすっと
左から右へ、すっと入ってきます。写真と文章を横に並べた区切りなど、「流れ」を感じさせたい場所に向いています。
<div class="kd-fx kd-fx-left kd-fx-row">
<div class="kd-fx-photo"></div>
<p>写真と文章のまとまりが、左から入ってきます。</p>
</div>.kd-fx-on .kd-fx-left {
transform: translateX(-40px);
}3. 少し大きくなって出る
少し小さい状態から、元の大きさに戻りながら出てきます。写真やバナーのように、四角い大きなものに合います。
<div class="kd-fx kd-fx-zoom kd-fx-banner">季節のおすすめ</div>.kd-fx-on .kd-fx-zoom {
transform: scale(0.92);
}4. カードが順番に出る
横に並んだカードが、左から少しずつ遅れて出てきます。遅らせる時間(transition-delay)を、2枚目と3枚目にだけ付けています。
<div class="kd-fx-cards">
<div class="kd-fx">WEB</div>
<div class="kd-fx">DESIGN</div>
<div class="kd-fx">SNS</div>
</div>.kd-fx-on .kd-fx-cards > .kd-fx {
transform: translateY(24px);
}
.kd-fx-cards > .kd-fx:nth-child(2) {
--kd-fx-delay: 0.15s;
}
.kd-fx-cards > .kd-fx:nth-child(3) {
--kd-fx-delay: 0.3s;
}5. CSSだけで(新しい書き方)
JavaScriptを使わずに、CSSだけでスクロールに合わせて動かす新しい書き方です。対応していないブラウザでは、動かずにそのまま表示されます(対応状況は後半で)。 この見本だけは、上の共通のCSSとJavaScriptは使わず、下のCSSだけで動きます。
<div class="kd-fx-css">
<h3>私たちについて</h3>
<p>小さなお店のホームページを、言葉から一緒に考えます。</p>
</div>/* 5. CSSだけ:画面に入ってくる間に、アニメーションを進める */
@keyframes kd-fx-in {
from {
opacity: 0;
transform: translateY(24px);
}
}
@supports (animation-timeline: view()) {
.kd-fx-css {
animation: kd-fx-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 80%;
}
}
@media (prefers-reduced-motion: reduce) {
.kd-fx-css {
animation: none;
}
}仕組み:「隠しておく → 画面に入ったら戻す」の2段階
CSS:最初の状態と、戻ったあとの状態
共通のCSSでは、kd-fx の付いた要素を、最初は opacity: 0(透明)にしておきます。見本ごとのCSSで、少しずらした位置も決めます。1なら translateY(24px)(下へ24px)、2なら translateX(-40px)(左へ40px)、3なら scale(0.92)(92%の大きさ)です。
画面に入ると、JavaScriptが is-visible というクラスを付けます。このクラスが付いた要素は、opacity: 1 と transform: none(ずらしをなくす)で元に戻ります。transition を指定してあるので、一瞬で切り替わらず、0.6秒かけてなめらかに戻ります。これが「ふわっと」の正体です。
JavaScript:画面に入ったかを見張る
IntersectionObserver は、ブラウザに最初から入っている「要素が画面に入ったかを見張る係」です。見張ってほしい要素を observe() で渡しておくと、画面に入ったときと出たときに知らせてくれます。スクロールのたびに位置を計算する書き方より、ブラウザに任せられる分、処理が軽く済みます。
| コードの部分 | 意味 |
|---|---|
if ('IntersectionObserver' in window) | このしくみが使えるブラウザのときだけ動かす |
classList.add('kd-fx-on') | ページ全体に「JavaScriptが動いた」という目印を付ける。この目印があるときだけ、CSSで要素を隠す |
entry.isIntersecting | 要素が画面に入っているかどうか |
classList.add('is-visible') | 画面に入った要素に、元に戻すためのクラスを付ける |
observer.unobserve() | 一度出したら見張るのをやめる。上へ戻っても、もう一度は動かない |
rootMargin: '0px 0px -10% 0px' | 画面の下から10%の位置を「入った」の線にする。少し入りこんでから動くので、動きが見えやすい |
「JavaScriptが動いたときだけ隠す」理由
CSSだけで最初から opacity: 0 にしておくと、JavaScriptが読み込めなかったときや、エラーで止まったときに、中身が透明のまま、ずっと見えなくなります。共通のCSSが .kd-fx-on .kd-fx と書いてあるのは、JavaScriptが動いて目印が付いたときにだけ隠すためです。動かなかったときは、ふつうに表示されます。
5. CSSだけの書き方
5の見本は、animation-timeline: view() を使っています。ふつうのアニメーションは「時間」で進みますが、これは「要素が画面の中にどれだけ入ってきたか」で進みます。animation-range: entry 0% entry 80% は、要素が画面の下から入りはじめてから、入りきる手前までの区間で、アニメーションを最後まで進める、という意味です。上へスクロールすると、逆に薄くなって戻ります。
animation は一括でまとめて書く指定なので、あとに書かないと animation-timeline が初期値に戻ってしまいます。見本でも、animation を先、animation-timeline をあとに書いています。
数値を変えるとどうなるか
1(下からふわっと)の値だけを変えて並べました。どれも中が自動でスクロールしています。
ずらす距離
translateY(8px)translateY(24px)translateY(80px)8px だと、動いたことにほとんど気づかず、「濃さが変わった」だけに見えます。80px だと、大きく持ち上がるので目立ちますが、文章が動いている間は読みにくく、落ち着きのない印象になります。見本の 24px 前後が、「出てきた」と分かる、ちょうどいい距離です。
戻るまでの時間
0.3秒だと、きびきびしていますが、スクロールが速いと動きがほとんど見えません。1.5秒だと、ゆったりしますが、読みたいところがなかなか出てこず、待たされている感じになります。見本は0.6秒。読み進める速さをじゃましない長さです。
| 変えるところ | 小さくすると | 大きくすると |
|---|---|---|
| ずらす距離(translateY) | 控えめ。濃さの変化だけに見える | 目立つが、落ち着かない |
| 時間(transition) | きびきび。速いスクロールでは見えない | ゆったり。待たされる感じになる |
| 遅らせる時間(4の –kd-fx-delay) | ほぼ同時に出る | 順番は分かるが、最後のカードが遅れる |
| rootMargin の -10% | 画面に入った直後に動く | もっと上まで来てから動く |
スマホと、見る人への配慮
動きを減らす設定の人には、動かさない
画面の動きで気分が悪くなる人や、動きが気になって集中しにくい人がいます。そうした人は、スマホやパソコンで「動きを減らす」設定をオンにしていることがあります。iPhoneなら「設定 > アクセシビリティ > 動作 > 視差効果を減らす」、Windows 11なら「設定 > アクセシビリティ > 視覚効果 > アニメーション効果」です。
この設定は、CSSの @media (prefers-reduced-motion: reduce) で読み取れます。見本では、この設定の人には位置をずらさず、濃さだけを0.3秒で変えています。5のCSSだけの見本では、アニメーションそのものを止めています。W3Cのアクセシビリティの基準(WCAG 2.2)にも、スクロールなどの操作をきっかけに起きる動きを、止められるようにする項目があります。
横から出すときは、はみ出しに注意
2の見本は左から入ってきます。これを右から(translateX(40px))にすると、隠れている間、要素が画面の右へはみ出し、スマホで横にスクロールできてしまうことがあります。右から出したいときは、外側の箱に overflow-x: clip(はみ出した分を切る)を付けて、スマホの幅で横に動かないかを確かめます。
印刷するとき
まだスクロールしていない部分は、透明のままです。そのまま印刷すると、そこが空白になります。見本の共通のCSSには、印刷のときは全部表示する指定(@media print)を入れています。
CSSだけの書き方は、対応しているブラウザがまだ限られる
5の animation-timeline は、MDNの対応表(2026年10月17日に確認)では、Chrome と Edge は115から、Safari は26から対応しています。Firefox は、10月27日に公開予定の159から対応と載っていて、MDNでは「Baseline」(主要なブラウザでそろって使える目印)にはまだなっていません。見本では @supports(対応しているときだけ使う書き方)で包んでいるので、対応していないブラウザでは動かずに、最初から表示されます。動きがなくても困らない場所に使う、と決めておけば、今から使えます。
やりすぎ注意
全部の要素に付けると、スクロールするたびに何かが動き、読む人は「出てくるのを待つ」ことになります。1画面の中で動くのは1か所か2か所、と決めておくと、動きが「ここが区切り」という合図として働きます。

ふわっと出る動きは、見せたいものに目を向けてもらう合図だと考えています。
合図が多すぎると、どれも合図に見えなくなります。
AIに頼むなら
この動きは、Claudeなどの生成AIに頼んでもすぐ作ってもらえます。そのときは、どこに使うか・動きの大きさ・配慮まで、まとめて伝えると、手直しが少なく済みます。
スクロールで、区切りの見出しと写真だけを「下から24px・0.6秒」でふわっと表示したい。
IntersectionObserver で、一度出たら見張りをやめる形に。JavaScriptが動かないときは最初から表示。
動きを減らす設定(prefers-reduced-motion)の人には、位置を動かさないで。AIが出したコードは、そのまま使う前に、次の3つを確かめます。
- JavaScriptが止まったとき、中身が見えるか。CSSだけで最初から
opacity: 0にしていないかを見ます。ブラウザの設定でJavaScriptを止めて開くと確かめられます - 動きを減らす設定で、動きが止まるか。Chromeなら開発者ツールの「レンダリング」で、この設定をオンにしたときの見え方を試せます
- 全部の要素に付いていないか。「すべての section に付けました」という答えが返ってくることがあります。見出しと写真だけに絞ります。スマホの幅で、横にスクロールできてしまわないかも見ます
KAKERUならこう使う/使わない
最後に、作り手としての判断です。
使う場面
- 区切りの見出し(h2)と、その下の写真。「ここから新しい話」という合図として、区切りの頭にだけ付けます
- 実績やサービスのカードを並べた一覧。4の「順番に出る」で、並んでいることを自然に伝えられます。遅らせる時間は合計0.3秒ほどに収めます
- ページの下のほうにある、最後の案内。「お問い合わせはこちら」の手前の見出しなど、読み終えた人の目を向けたい場所に1つだけ
使わない場面
- 本文の段落。読んでいる途中の文章が動くと、目で追うのがつらくなります。文章は最初から見えていてほしいものです
- ボタン・入力欄・お知らせ。押したい・読みたいときに、まだ透明だと困ります。営業時間や休業のお知らせのような大事な情報には付けません
- ページを開いてすぐ見える一番上(ファーストビュー)。開いた瞬間に中身が見えないと、表示が遅いページに見えます。ここは最初から表示しておきます

「動きがあるとおしゃれに見えるから」で全部に付けるのは、いちばん避けたい使い方です。
動かす場所を選ぶこと自体が、デザインの判断です。
まとめ
- 最初は薄く・少しずらしておき、画面に入ったらクラスを付けて、transition でなめらかに戻す
- 画面に入ったかは IntersectionObserver に見張ってもらう。一度出したら unobserve でやめる
- JavaScriptが動いたときだけ隠す。動かなかったときに中身が消えないようにする
- 動きを減らす設定の人には、位置を動かさない。右から出すならはみ出しに注意
- CSSだけの animation-timeline: view() もある。対応していないブラウザでは動かずに表示される
- 使うのは区切りの見出しや写真だけ。本文・ボタン・ファーストビューには使わない
まずは「下からふわっと」のコードと共通のCSS・JavaScriptをコピーして、区切りの見出しを1つだけ動かしてみてください。1か所だけ動くと、そこが区切りだと自然に伝わるのが分かります。
参考にした資料
いずれも2026年10月17日に確認しました。ブラウザの対応状況は変わることがあります。最新の情報は各ページでご確認ください。
- MDN「交差オブザーバー API」(Intersection Observer API)
https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API
※要素が画面に入ったかを見張るしくみ、threshold・rootMargin・isIntersecting・unobserve の意味。2019年3月から主要なブラウザで使えること(英語版で確認) - MDN「IntersectionObserver: IntersectionObserver() コンストラクター」
https://developer.mozilla.org/ja/docs/Web/API/IntersectionObserver/IntersectionObserver
※rootMargin にマイナスの値を書くと、判定する範囲が狭くなること - MDN「transition」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Properties/transition
※値が変わったときに、あいだをなめらかにつなぐ指定 - MDN「transition-delay」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Properties/transition-delay
※変化を始めるまでの待ち時間 - MDN「animation-timeline」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Properties/animation-timeline
※view() で、要素が見えている割合に合わせてアニメーションを進めること。対応状況(英語版の対応表で確認) - MDN「animation-range」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Properties/animation-range
※entry などで、アニメーションを進める区間を決めること - MDN「@supports」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/At-rules/@supports
※ブラウザが対応しているときだけ中の指定を使う書き方 - MDN「prefers-reduced-motion」
https://developer.mozilla.org/ja/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion
※動きを減らす設定を読み取る書き方 - W3C「Understanding SC 2.3.3: Animation from Interactions」
https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html
※操作(スクロールなど)をきっかけに起きる動きを、止められるようにするという基準 - Apple サポート「iPhone、iPad、iPod touch で画面の視差効果を減らす」
https://support.apple.com/ja-jp/111781
※iPhoneの「視差効果を減らす」の場所
ふだんの制作の話や、作ったものの裏側は Instagram と X でも出しています。




















連載「WEBの技術」の12回目です。
今回の動きは、入れるだけで「今っぽい」見た目になります。だからこそ、どこに入れて、どこに入れないかの判断がいちばん大事な回です。