【脱JS】CSSだけで作る!スクロールで消える全画面KV(グラデーションマスク編)

最新のCSS「Scroll-driven Animations」を駆使して、JavaScriptを一切使わずに、スクロール量に合わせてKV(メインビジュアル)を滑らかに消していく演出を紹介します。
例えば、KVの背後に印象的な模様やコンテンツを配置しており、スクロールに合わせてそれらをドラマチックに見せたい時に便利な方法です。

  1. スクロールで消える全画面KVの実装方法
  2. JavaScript 完全対応版

スクロールで消える全画面KVの実装方法

スクロール量と連動させるために animation-timeline を使い、さらに mask-size を大きめに確保することで、グラデーションの端が残らない「完全な消去」を実現するコードを紹介します。

まずはベースのHTML。

<div class="kv-outer">
<div class="kv-material">
<div class="kv-text">KEY VISUAL</div>
</div>
</div>
<main class="main-content">
<div class="content-inner">
<h2>FIXED MASK</h2>
<p>初期状態ではマスクは見えません。</p>
<p>スクロールすると、2倍速で下から消えます。</p>
</div>
</main>

次にCSS。


body, html {
margin: 0;
padding: 0;
background-color: #007bff; /* コンテンツ:青 */
background-image: repeating-linear-gradient(45deg, transparent, transparent 20px, rgba(255,255,255,0.1) 20px, rgba(255,255,255,0.1) 40px);
}
.kv-outer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
z-index: 1;
}
.kv-material {
width: 100%;
height: 100%;
background-color: #ff4d4d; /* KV:赤 */
background-image: radial-gradient(rgba(0,0,0,0.2) 20%, transparent 20%);
background-size: 30px 30px;
display: flex;
justify-content: center;
align-items: center;
/* --- マスク設定の最終調整 --- */
mask-image: linear-gradient(to bottom,
black 0%,
black 45%, /* 45%までしっかり表示 */
transparent 55%, /* 55%から透明開始(ここの幅を狭めるとパキッとします) */
transparent 100% /* 最後まで完全に透明 */
);
mask-size: 100% 250%; /* 高さを200%から250%へ広げて、透明領域に余裕を持たせる */
mask-position: 0 0%; /* 初期状態は上端 */
mask-repeat: no-repeat;
/* スクロール連動 */
animation: mask-up-swipe linear forwards;
animation-timeline: scroll(root);
/* 50vhスクロールした時点で、2.5倍の高さがあるマスクを出し切る */
animation-range: 0vh 50vh;
/* [追加] 最新ブラウザ以外向けのフォールバック(不透明度だけ変える) */
animation: mask-up-swipe linear forwards;
animation-timeline: scroll(root);
animation-range: 0vh 50vh;
}
.kv-text {
color: white;
font-size: clamp(2rem, 10vw, 4rem);
font-weight: bold;
}
/* 下部コンテンツ */
.main-content {
position: relative;
z-index: 2;
margin-top: 100vh;
min-height: 150vh;
}
.content-inner {
padding: 10vh 50px;
color: white;
font-size: 1.5rem;
text-align: center;
}
/* アニメーション:
mask-positionを0から100%へ動かすことで、
下の透明エリアを競り上げます
*/
@keyframes mask-up-swipe {
from { mask-position: 0 0%; }
to { mask-position: 0 100%; }
}

JavaScript 完全対応版

紹介した方法は、最新の iPhone(iOS 18.0以降)や Android なら動きますが、少し前の iPhone だと動かない可能性があります。
全スマホユーザーに対応させる場合は、CSSの animation-timeline に頼らず、以下の数行の JavaScript を加えます。
CSS側の animation-timeline 関連を消して、こちらに差し替え。


window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const vh = window.innerHeight;
const kv = document.querySelector('.kv-material');
// 50vhスクロールする間に 0% から 100% まで動かす計算
let progress = (scrollY / (vh * 0.5)) * 100;
if (progress > 100) progress = 100;
// 直接 mask-position を操作する
kv.style.webkitMaskPosition = `0 ${progress}%`;
kv.style.maskPosition = `0 ${progress}%`;
});

JavaScript で対応するのは本末転倒のため、クライアントワークなどの場合は、先に要件定義を確認して対応してください。

まとめ

従来のJavaScriptによるイベントリスナーを使わないため、非常に動作が軽量で、コードの可読性も高く保つことができます。特に「スクロールの2倍の速さでマスクを動かす」ことで、ユーザーを待たせずスムーズにコンテンツへと誘導できるのがこのテクニックの大きなメリットです。

ぜひ、次世代のWEB演出として取り入れてみてください。