デュオトーン (mix-blend-mode)

モノクロ画像に2色のレイヤーを mix-blend-mode で重ね、雑誌風の2色グラフィックを生成。配色プリセットをワンクリックで切り替えられます。

#css#mix-blend-mode#duotone#js

ライブデモ

使用例(お題: アイドルグループ 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で提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。