デュオトーン (mix-blend-mode)
モノクロ画像に2色のレイヤーを mix-blend-mode で重ね、雑誌風の2色グラフィックを生成。配色プリセットをワンクリックで切り替えられます。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura:新曲MVのデュオトーン・キービジュアル -->
<section class="sk-duo">
<span class="sk-petal sk-petal--1">❀</span>
<span class="sk-petal sk-petal--2">❀</span>
<!-- デュオトーンに加工されるMVスチル -->
<figure class="sk-duo__stage" data-tone="sakura">
<img class="sk-duo__img" src="https://picsum.photos/640/480?random=31&grayscale" alt="新曲MVスチル">
<span class="sk-duo__layer sk-duo__layer--shadow"></span>
<span class="sk-duo__layer sk-duo__layer--light"></span>
<figcaption class="sk-duo__cap">NEW SINGLE</figcaption>
</figure>
<!-- 楽曲情報+配色プリセット -->
<div class="sk-duo__info">
<span class="sk-duo__tag">7th SINGLE</span>
<h2 class="sk-duo__title">春風メトロノーム</h2>
<p class="sk-duo__lead">2026.04.09 Release<br>ジャケット配色を選べます。</p>
<div class="sk-duo__sw" role="group" aria-label="配色プリセット">
<button class="sk-sw" data-tone="sakura" style="--a:#ffd1e0;--b:#7a3b5e" aria-label="サクラ"></button>
<button class="sk-sw" data-tone="mint" style="--a:#bdf5e6;--b:#2f6e8c" aria-label="ミント"></button>
<button class="sk-sw" data-tone="lavender" style="--a:#e4d1ff;--b:#5b3b8c" aria-label="ラベンダー"></button>
</div>
</div>
</section>
CSS
/* Sakura:MVデュオトーン・キービジュアル */
:root {
--pink: #ffd1e0;
--gray: #eef0f2;
--ink: #4a3b44;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
display: flex;
align-items: center;
gap: 30px;
padding: 0 32px;
font-family: "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
background: linear-gradient(160deg, #fff 0%, var(--pink) 100%);
color: var(--ink);
overflow: hidden;
}
/* 舞い散る花びら */
.sk-petal {
position: absolute;
color: rgba(255,150,185,0.5);
font-size: 20px;
pointer-events: none;
}
.sk-petal--1 { top: 26px; right: 40px; font-size: 26px; }
.sk-petal--2 { bottom: 30px; left: 44%; font-size: 16px; }
/* デュオトーン本体 */
.sk-duo__stage {
--a: #ffd1e0;
--b: #7a3b5e;
position: relative;
flex: 0 0 320px;
width: 320px;
height: 300px;
margin: 0;
border-radius: 16px;
overflow: hidden;
isolation: isolate;
box-shadow: 0 18px 44px rgba(122,59,94,0.3);
}
.sk-duo__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
filter: contrast(1.15) brightness(1.05);
}
.sk-duo__layer { position: absolute; inset: 0; }
.sk-duo__layer--shadow { background: var(--b); mix-blend-mode: lighten; }
.sk-duo__layer--light { background: var(--a); mix-blend-mode: multiply; }
.sk-duo__cap {
position: absolute;
left: 16px;
bottom: 14px;
z-index: 2;
font-size: 12px;
letter-spacing: 0.3em;
font-weight: 800;
color: #fff;
mix-blend-mode: difference;
}
/* 楽曲情報 */
.sk-duo__info { flex: 1; }
.sk-duo__tag { font-size: 10px; letter-spacing: 0.3em; color: #d8729a; }
.sk-duo__title {
margin: 10px 0 12px;
font-size: 27px;
font-weight: 800;
font-family: "Hiragino Mincho ProN", "Yu Mincho", serif;
color: #5a2e44;
}
.sk-duo__lead { margin: 0 0 20px; font-size: 13px; line-height: 1.9; color: #7a5e6c; }
.sk-duo__sw { display: flex; gap: 12px; }
.sk-sw {
width: 32px;
height: 32px;
border-radius: 50%;
border: 2px solid rgba(255,255,255,0.7);
cursor: pointer;
background: linear-gradient(135deg, var(--a) 0 50%, var(--b) 50% 100%);
box-shadow: 0 4px 12px rgba(122,59,94,0.25);
transition: transform 0.2s ease, border-color 0.2s ease;
}
.sk-sw:hover,
.sk-sw:focus-visible { transform: scale(1.15); border-color: #fff; outline: none; }
.sk-sw[aria-pressed="true"] { border-color: #d8729a; transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) {
.sk-sw { transition: none; }
}
JavaScript
// 配色プリセットを切り替えてデュオトーンの2色を差し替える
(() => {
const stage = document.querySelector(".sk-duo__stage");
const swatches = Array.from(document.querySelectorAll(".sk-sw"));
if (!stage || !swatches.length) return;
const apply = (btn) => {
// スウォッチの --a / --b を本体へコピー
const cs = getComputedStyle(btn);
stage.style.setProperty("--a", cs.getPropertyValue("--a").trim());
stage.style.setProperty("--b", cs.getPropertyValue("--b").trim());
stage.dataset.tone = btn.dataset.tone || "";
// 選択状態を更新
swatches.forEach((s) => s.setAttribute("aria-pressed", String(s === btn)));
};
swatches.forEach((btn) => btn.addEventListener("click", () => apply(btn)));
apply(swatches[0]); // 初期プリセット
})();
コード
HTML
<!-- mix-blend-mode を重ねたデュオトーン表現 -->
<div class="stage">
<figure class="duo" data-tone="sunset">
<img class="duo__img" src="https://picsum.photos/id/1025/800/600?grayscale" alt="デュオトーン画像">
<!-- 2枚のカラーレイヤーが multiply / screen で色を載せる -->
<span class="duo__layer duo__layer--shadow"></span>
<span class="duo__layer duo__layer--light"></span>
<figcaption class="duo__cap">DUOTONE</figcaption>
</figure>
<!-- 配色プリセット切替 -->
<div class="swatches" role="group" aria-label="配色プリセット">
<button class="swatch" data-tone="sunset" style="--a:#ff5e7e;--b:#3a1c71" aria-label="サンセット"></button>
<button class="swatch" data-tone="ocean" style="--a:#00f0c0;--b:#0b2a5b" aria-label="オーシャン"></button>
<button class="swatch" data-tone="violet" style="--a:#f5a623;--b:#5b21b6" aria-label="バイオレット"></button>
</div>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #0e0f17;
font-family: "Segoe UI", system-ui, sans-serif;
}
.stage { display: grid; gap: 18px; justify-items: center; padding: 24px; }
/* デュオトーン本体: 2色を CSS 変数で持つ */
.duo {
--a: #ff5e7e; /* ハイライト色 */
--b: #3a1c71; /* シャドウ色 */
position: relative;
width: min(62vw, 360px);
aspect-ratio: 4 / 3;
margin: 0;
border-radius: 14px;
overflow: hidden;
isolation: isolate; /* blend をこの枠内に閉じ込める */
box-shadow: 0 18px 45px -15px rgba(0, 0, 0, .7);
}
.duo__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
filter: contrast(1.15) brightness(1.05);
}
/* カラーレイヤー */
.duo__layer {
position: absolute;
inset: 0;
}
/* 暗部に色を載せる */
.duo__layer--shadow {
background: var(--b);
mix-blend-mode: lighten;
}
/* 明部に色を載せる */
.duo__layer--light {
background: var(--a);
mix-blend-mode: multiply;
}
/* キャプション */
.duo__cap {
position: absolute;
left: 14px;
bottom: 12px;
z-index: 2;
font-size: 12px;
letter-spacing: .35em;
font-weight: 800;
color: #fff;
mix-blend-mode: difference;
}
/* スウォッチ */
.swatches { display: flex; gap: 10px; }
.swatch {
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, .25);
cursor: pointer;
background: linear-gradient(135deg, var(--a) 0 50%, var(--b) 50% 100%);
transition: transform .2s ease, border-color .2s ease;
}
.swatch:hover,
.swatch:focus-visible { transform: scale(1.15); border-color: #fff; outline: none; }
.swatch[aria-pressed="true"] { border-color: #fff; transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) {
.swatch { transition: none; }
}
JavaScript
// スウォッチ選択でデュオトーンの2色(--a/--b)を切り替える
const duo = document.querySelector(".duo");
const swatches = document.querySelectorAll(".swatch");
if (duo && swatches.length) {
const apply = (btn) => {
// スウォッチの style から色を読み取り、画像枠へ反映
const a = btn.style.getPropertyValue("--a");
const b = btn.style.getPropertyValue("--b");
duo.style.setProperty("--a", a);
duo.style.setProperty("--b", b);
swatches.forEach((s) => s.setAttribute("aria-pressed", String(s === btn)));
};
swatches.forEach((btn) => btn.addEventListener("click", () => apply(btn)));
// 初期選択
apply(swatches[0]);
}
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「デュオトーン (mix-blend-mode)」の効果を追加してください。
# 追加してほしい効果
デュオトーン (mix-blend-mode)(画像エフェクト)
モノクロ画像に2色のレイヤーを mix-blend-mode で重ね、雑誌風の2色グラフィックを生成。配色プリセットをワンクリックで切り替えられます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- mix-blend-mode を重ねたデュオトーン表現 -->
<div class="stage">
<figure class="duo" data-tone="sunset">
<img class="duo__img" src="https://picsum.photos/id/1025/800/600?grayscale" alt="デュオトーン画像">
<!-- 2枚のカラーレイヤーが multiply / screen で色を載せる -->
<span class="duo__layer duo__layer--shadow"></span>
<span class="duo__layer duo__layer--light"></span>
<figcaption class="duo__cap">DUOTONE</figcaption>
</figure>
<!-- 配色プリセット切替 -->
<div class="swatches" role="group" aria-label="配色プリセット">
<button class="swatch" data-tone="sunset" style="--a:#ff5e7e;--b:#3a1c71" aria-label="サンセット"></button>
<button class="swatch" data-tone="ocean" style="--a:#00f0c0;--b:#0b2a5b" aria-label="オーシャン"></button>
<button class="swatch" data-tone="violet" style="--a:#f5a623;--b:#5b21b6" aria-label="バイオレット"></button>
</div>
</div>
【CSS】
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #0e0f17;
font-family: "Segoe UI", system-ui, sans-serif;
}
.stage { display: grid; gap: 18px; justify-items: center; padding: 24px; }
/* デュオトーン本体: 2色を CSS 変数で持つ */
.duo {
--a: #ff5e7e; /* ハイライト色 */
--b: #3a1c71; /* シャドウ色 */
position: relative;
width: min(62vw, 360px);
aspect-ratio: 4 / 3;
margin: 0;
border-radius: 14px;
overflow: hidden;
isolation: isolate; /* blend をこの枠内に閉じ込める */
box-shadow: 0 18px 45px -15px rgba(0, 0, 0, .7);
}
.duo__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
filter: contrast(1.15) brightness(1.05);
}
/* カラーレイヤー */
.duo__layer {
position: absolute;
inset: 0;
}
/* 暗部に色を載せる */
.duo__layer--shadow {
background: var(--b);
mix-blend-mode: lighten;
}
/* 明部に色を載せる */
.duo__layer--light {
background: var(--a);
mix-blend-mode: multiply;
}
/* キャプション */
.duo__cap {
position: absolute;
left: 14px;
bottom: 12px;
z-index: 2;
font-size: 12px;
letter-spacing: .35em;
font-weight: 800;
color: #fff;
mix-blend-mode: difference;
}
/* スウォッチ */
.swatches { display: flex; gap: 10px; }
.swatch {
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, .25);
cursor: pointer;
background: linear-gradient(135deg, var(--a) 0 50%, var(--b) 50% 100%);
transition: transform .2s ease, border-color .2s ease;
}
.swatch:hover,
.swatch:focus-visible { transform: scale(1.15); border-color: #fff; outline: none; }
.swatch[aria-pressed="true"] { border-color: #fff; transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) {
.swatch { transition: none; }
}
【JavaScript】
// スウォッチ選択でデュオトーンの2色(--a/--b)を切り替える
const duo = document.querySelector(".duo");
const swatches = document.querySelectorAll(".swatch");
if (duo && swatches.length) {
const apply = (btn) => {
// スウォッチの style から色を読み取り、画像枠へ反映
const a = btn.style.getPropertyValue("--a");
const b = btn.style.getPropertyValue("--b");
duo.style.setProperty("--a", a);
duo.style.setProperty("--b", b);
swatches.forEach((s) => s.setAttribute("aria-pressed", String(s === btn)));
};
swatches.forEach((btn) => btn.addEventListener("click", () => apply(btn)));
// 初期選択
apply(swatches[0]);
}
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。