mix-blend-mode テキスト
difference ブレンドで背景色を反転して切り抜く大型タイポ。マウス追従の光スポットで色が躍動します。LP のキービジュアルに。
ライブデモ
使用例(お題: SaaS FlowDesk)
この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- FlowDesk:プロダクトLPのキービジュアル(difference 大型タイポ) -->
<section class="fd-blend">
<!-- ナビ -->
<nav class="fd-blend__nav">
<span class="fd-blend__logo">▰ FlowDesk</span>
<a class="fd-blend__login" href="#">ログイン</a>
</nav>
<!-- 動く背景(製品写真+ブランドグラデ) -->
<div class="fd-blend__bg"></div>
<!-- マウス追従の光スポット -->
<div class="fd-blend__spot" aria-hidden="true"></div>
<!-- difference で背景を反転して切り抜く大型コピー -->
<h1 class="fd-blend__text">WORK<br>IN FLOW</h1>
<p class="fd-blend__sub">チームの仕事を、ひとつの流れに。</p>
<a class="fd-blend__cta" href="#">無料で試す →</a>
</section>
CSS
/* FlowDesk:difference 大型タイポのキービジュアル */
:root {
--navy: #0f1b34;
--blue: #4f7cff;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
overflow: hidden;
}
.fd-blend {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
background: var(--navy);
isolation: isolate;
}
/* ナビ */
.fd-blend__nav {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 4;
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 30px;
}
.fd-blend__logo { font-size: 16px; font-weight: 800; letter-spacing: 0.04em; color: #fff; }
.fd-blend__login {
font-size: 12px;
color: #fff;
text-decoration: none;
opacity: 0.85;
}
.fd-blend__login:hover { opacity: 1; }
/* 背景:製品写真にブランドグラデを重ねて動かす */
.fd-blend__bg {
position: absolute;
inset: -10%;
background:
linear-gradient(120deg, rgba(15,27,52,0.85), rgba(79,124,255,0.6)),
url("https://picsum.photos/900/600?random=71") center/cover no-repeat;
animation: fdDrift 16s ease-in-out infinite alternate;
}
@keyframes fdDrift {
0% { transform: scale(1.1) translate(-2%, -1%); }
100% { transform: scale(1.18) translate(2%, 1%); }
}
/* マウス追従スポット(white でテキストの difference を躍動させる) */
.fd-blend__spot {
position: absolute;
width: 320px;
height: 320px;
left: var(--mx, 50%);
top: var(--my, 45%);
transform: translate(-50%, -50%);
z-index: 2;
border-radius: 50%;
background: radial-gradient(circle, rgba(120,170,255,0.95), rgba(120,170,255,0) 65%);
pointer-events: none;
mix-blend-mode: screen;
}
/* difference で背景を反転して切り抜く大型タイポ */
.fd-blend__text {
position: absolute;
left: 30px;
top: 78px;
z-index: 3;
margin: 0;
font-size: 92px;
line-height: 0.92;
font-weight: 900;
letter-spacing: -0.02em;
color: #fff;
mix-blend-mode: difference;
pointer-events: none;
}
.fd-blend__sub {
position: absolute;
left: 32px;
bottom: 64px;
z-index: 3;
margin: 0;
font-size: 14px;
color: rgba(255,255,255,0.92);
}
.fd-blend__cta {
position: absolute;
left: 32px;
bottom: 26px;
z-index: 3;
display: inline-block;
padding: 11px 22px;
border-radius: 10px;
background: var(--blue);
color: #fff;
font-size: 13px;
font-weight: 700;
text-decoration: none;
box-shadow: 0 10px 24px rgba(79,124,255,0.5);
transition: transform 0.2s ease;
}
.fd-blend__cta:hover { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
.fd-blend__bg { animation: none; }
.fd-blend__cta { transition: none; }
}
JavaScript
// マウス位置を --mx/--my に渡し、光のスポットを追従させる
const blend = document.querySelector(".fd-blend");
if (blend) {
const move = (clientX, clientY) => {
const r = blend.getBoundingClientRect();
if (!r.width || !r.height) return;
blend.style.setProperty("--mx", `${clientX - r.left}px`);
blend.style.setProperty("--my", `${clientY - r.top}px`);
};
blend.addEventListener("pointermove", (e) => move(e.clientX, e.clientY));
// タッチ環境では円を自動巡回(操作なしでも動きを見せる)
if (!window.matchMedia("(pointer: fine)").matches) {
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
let t = 0;
setInterval(() => {
t += 0.04;
const r = blend.getBoundingClientRect();
const x = r.width / 2 + Math.cos(t) * r.width * 0.3;
const y = r.height / 2 + Math.sin(t * 1.3) * r.height * 0.3;
blend.style.setProperty("--mx", `${x}px`);
blend.style.setProperty("--my", `${y}px`);
}, 40);
}
}
}
コード
HTML
<!-- mix-blend-mode で背景を反転表示する追従テキスト -->
<div class="blend">
<!-- 動く背景(CSSグラデのみ) -->
<div class="blend__bg"></div>
<!-- マウスに追従する光の円 -->
<div class="blend__spot" aria-hidden="true"></div>
<!-- difference で背景色を反転して切り抜くテキスト -->
<h1 class="blend__text">BLEND<br>MODE</h1>
</div>
CSS
* { box-sizing: border-box; }
body { margin: 0; }
.blend {
position: relative;
width: 100%;
height: 360px;
overflow: hidden;
background: #0d0d12;
font-family: "Arial Black", "Segoe UI", system-ui, sans-serif;
isolation: isolate; /* blend をこの枠に閉じ込める */
}
/* グラデ背景がゆっくり流れる */
.blend__bg {
position: absolute;
inset: -20%;
background: linear-gradient(115deg, #ff006e, #fb5607, #ffbe0b, #3a86ff, #8338ec);
background-size: 300% 300%;
animation: flow 12s ease infinite;
filter: saturate(1.1);
}
@keyframes flow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* マウス追従スポット(明るい円) */
.blend__spot {
position: absolute;
left: var(--mx, 50%);
top: var(--my, 50%);
width: 260px;
height: 260px;
transform: translate(-50%, -50%);
border-radius: 50%;
background: radial-gradient(circle, #fff, rgba(255, 255, 255, 0) 70%);
mix-blend-mode: overlay;
pointer-events: none;
transition: transform .12s ease-out;
}
/* difference で背景を反転表示する文字 */
.blend__text {
position: absolute;
inset: 0;
margin: 0;
display: grid;
place-content: center;
text-align: center;
line-height: .92;
font-size: clamp(56px, 16vw, 130px);
font-weight: 900;
letter-spacing: -.02em;
color: #fff;
mix-blend-mode: difference; /* ここが肝 */
pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
.blend__bg { animation: none; }
.blend__spot { transition: none; }
}
JavaScript
// マウス位置を --mx/--my に渡し、光のスポットを追従させる
const blend = document.querySelector(".blend");
if (blend) {
const move = (clientX, clientY) => {
const r = blend.getBoundingClientRect();
blend.style.setProperty("--mx", `${clientX - r.left}px`);
blend.style.setProperty("--my", `${clientY - r.top}px`);
};
blend.addEventListener("pointermove", (e) => move(e.clientX, e.clientY));
// タッチ環境では自動で円を巡回させる(操作なしでも動きを見せる)
if (!window.matchMedia("(pointer: fine)").matches) {
let t = 0;
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
setInterval(() => {
t += 0.04;
const r = blend.getBoundingClientRect();
const x = r.width / 2 + Math.cos(t) * r.width * 0.3;
const y = r.height / 2 + Math.sin(t * 1.3) * r.height * 0.3;
blend.style.setProperty("--mx", `${x}px`);
blend.style.setProperty("--my", `${y}px`);
}, 40);
}
}
}
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「mix-blend-mode テキスト」の効果を追加してください。
# 追加してほしい効果
mix-blend-mode テキスト(画像エフェクト)
difference ブレンドで背景色を反転して切り抜く大型タイポ。マウス追従の光スポットで色が躍動します。LP のキービジュアルに。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- mix-blend-mode で背景を反転表示する追従テキスト -->
<div class="blend">
<!-- 動く背景(CSSグラデのみ) -->
<div class="blend__bg"></div>
<!-- マウスに追従する光の円 -->
<div class="blend__spot" aria-hidden="true"></div>
<!-- difference で背景色を反転して切り抜くテキスト -->
<h1 class="blend__text">BLEND<br>MODE</h1>
</div>
【CSS】
* { box-sizing: border-box; }
body { margin: 0; }
.blend {
position: relative;
width: 100%;
height: 360px;
overflow: hidden;
background: #0d0d12;
font-family: "Arial Black", "Segoe UI", system-ui, sans-serif;
isolation: isolate; /* blend をこの枠に閉じ込める */
}
/* グラデ背景がゆっくり流れる */
.blend__bg {
position: absolute;
inset: -20%;
background: linear-gradient(115deg, #ff006e, #fb5607, #ffbe0b, #3a86ff, #8338ec);
background-size: 300% 300%;
animation: flow 12s ease infinite;
filter: saturate(1.1);
}
@keyframes flow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* マウス追従スポット(明るい円) */
.blend__spot {
position: absolute;
left: var(--mx, 50%);
top: var(--my, 50%);
width: 260px;
height: 260px;
transform: translate(-50%, -50%);
border-radius: 50%;
background: radial-gradient(circle, #fff, rgba(255, 255, 255, 0) 70%);
mix-blend-mode: overlay;
pointer-events: none;
transition: transform .12s ease-out;
}
/* difference で背景を反転表示する文字 */
.blend__text {
position: absolute;
inset: 0;
margin: 0;
display: grid;
place-content: center;
text-align: center;
line-height: .92;
font-size: clamp(56px, 16vw, 130px);
font-weight: 900;
letter-spacing: -.02em;
color: #fff;
mix-blend-mode: difference; /* ここが肝 */
pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
.blend__bg { animation: none; }
.blend__spot { transition: none; }
}
【JavaScript】
// マウス位置を --mx/--my に渡し、光のスポットを追従させる
const blend = document.querySelector(".blend");
if (blend) {
const move = (clientX, clientY) => {
const r = blend.getBoundingClientRect();
blend.style.setProperty("--mx", `${clientX - r.left}px`);
blend.style.setProperty("--my", `${clientY - r.top}px`);
};
blend.addEventListener("pointermove", (e) => move(e.clientX, e.clientY));
// タッチ環境では自動で円を巡回させる(操作なしでも動きを見せる)
if (!window.matchMedia("(pointer: fine)").matches) {
let t = 0;
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
setInterval(() => {
t += 0.04;
const r = blend.getBoundingClientRect();
const x = r.width / 2 + Math.cos(t) * r.width * 0.3;
const y = r.height / 2 + Math.sin(t * 1.3) * r.height * 0.3;
blend.style.setProperty("--mx", `${x}px`);
blend.style.setProperty("--my", `${y}px`);
}, 40);
}
}
}
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。