gazou-compressor.jp

アートディレクション実務:フォーカルクロップとbreakpoint別の画角設計(Next.js)

1枚の画像を全デバイスに流用すると、スマホでは被写体が小さく、PCではスカスカ。必要なのはアートディレクションです。 “焦点”を記述してクロップ/画角を切り替え、見せたいものを確実に見せる設計にします。

先に結論
  • 焦点(x,y,zoom)をJSONで管理し、ビルドで自動クロップ。
  • 画角が変わるなら picture、フレーム内で寄せるだけなら object-position
  • ヒーローは priority+fetchPriority を忘れずに。

要点(TL;DR)

1. データの持ち方(焦点メタ)

// content/focal.json(焦点メタデータの例)
{
  "hero.jpg": { "x": 0.42, "y": 0.38, "zoom": 1.15 },  // 0–1で正規化座標
  "team.jpg": { "x": 0.5, "y": 0.35, "zoom": 1.0 }
}

2. ビルドで自動クロップ

// scripts/focal-crop.ts — 焦点に基づく自動クロップ
// 依存: npm i -D sharp tsx
import fs from "node:fs/promises";
import path from "node:path";
import sharp from "sharp";
import focal from "../content/focal.json";

const IN = "input";
const OUT = "output";
const targets = [
  { w: 1600, h: 900, suffix: "_16x9" },
  { w: 1200, h: 1200, suffix: "_1x1" },
  { w: 800, h: 1200, suffix: "_2x3" },
];

async function main() {
  await fs.mkdir(OUT, { recursive: true });
  const files = (await fs.readdir(IN)).filter(f => /\.(jpe?g|png)$/i.test(f));

  for (const f of files) {
    const src = path.join(IN, f);
    const meta = (focal as any)[f] ?? { x: 0.5, y: 0.5, zoom: 1.0 };
    const img = sharp(src).rotate().toColourspace("srgb");
    const { width, height } = await img.metadata();
    if (!width || !height) continue;

    for (const t of targets) {
      // 焦点中心から目的アスペクトで切り出し
      const cropW = Math.min(width, Math.round(width / meta.zoom));
      const cropH = Math.min(height, Math.round((cropW * t.h) / t.w));
      const cx = Math.round(meta.x * width);
      const cy = Math.round(meta.y * height);
      const left = Math.max(0, Math.min(width - cropW, cx - Math.round(cropW / 2)));
      const top = Math.max(0, Math.min(height - cropH, cy - Math.round(cropH / 2)));

      await img
        .extract({ left, top, width: cropW, height: cropH })
        .resize(t.w, t.h)
        .jpeg({ quality: 82, mozjpeg: true, progressive: true })
        .toFile(path.join(OUT, path.parse(f).name + t.suffix + ".jpg"));
    }
  }
}
main().catch(console.error);

3. 表示:object-position と picture

// components/FocalImage.tsx — next/imageで焦点表示
import Image from "next/image";

export default function FocalImage(props: { src: string; alt: string; focal?: { x: number; y: number } }) {
  const { src, alt, focal = { x: 0.5, y: 0.5 } } = props;
  const pos = `${Math.round(focal.x * 100)}% ${Math.round(focal.y * 100)}%`;
  return (
    <div className="relative aspect-[16/9] overflow-hidden rounded-xl">
      <Image
        src={src}
        alt={alt}
        fill
        sizes="(min-width: 1024px) 1200px, 100vw"
        style={{ objectFit: "cover", objectPosition: pos }}
        priority
        fetchPriority="high"
      />
    </div>
  );
}
<!-- pictureでアートディレクション(枠外情報が重要なとき)-->
<picture>
  <source media="(min-width: 1024px)" srcset="/img/hero_16x9.jpg" />
  <source media="(max-width: 1023px)" srcset="/img/hero_2x3.jpg" />
  <img src="/img/hero_1x1.jpg" width="1200" height="1200" alt="Hero" />
</picture>

4. 応用と使いどころ

5. 公開前チェック

6. まとめ

アートディレクションは焦点メタ+自動クロップで運用化できます。見せたいものを確実に見せ、体験とCTRを底上げしましょう。

公開:2025-09-03

gazou-compressor.jp 編集部

画像圧縮・変換・背景除去などの実践テクニックと、Webで“速く・軽く・崩さない”ためのノウハウを発信しています。

関連記事