HTML

A way to turn specific regions of an image into links, letting one picture lead to multiple destinations.

map 要素

概要

<map> は、画像内の特定の領域だけをリンクにできます。たとえば「日本地図の北海道だけ詳細へ」「製品写真の各パーツを個別ページへ」など、1枚の画像を複数のリンク先に分割できます。

構成は「<img usemap> で画像にイメージマップを関連付け、<map> 内の複数の <area> でクリック領域を定義する」という形です。

関連付け(usemap と map の name/id)

現在の仕様では、<map>name でも id でも識別できます。

互換性を最大化したい場合は、両方に同じ値を指定しておくと安全です(既存コードや古い実装との整合を取りやすい)。

<img>usemap には、先頭に # を付けて、対応する name/id の値をそのまま書きます(例:usemap="#shapes")。

実装例

形状を選択してください:

4つの形状をクリックすると各説明ページへ移動します(赤いボックス、緑の円、青の三角形、黄色の星) 赤色のボックス 緑色の円 青色の三角形 黄色の星

HTML

<p>形状を選択してください:</p>
	<!-- 実画像。パスは環境に合わせて変更してください -->
	<img src="imgs/map01.jpg"
		width="595" height="156"
		alt="4つの形状をクリックすると各説明ページへ移動します(赤いボックス、緑の円、青の三角形、黄色の星)"
		usemap="#shapes">

<!-- map は name と id を両方付ける -->
<map name="shapes" id="shapes">
	<!-- 1) 穴領域:非リンク。重なり時に「穴」が優先されてクリック不可にできるよう、最初に定義 -->
	<!-- href を付けない(obsolete な nohref は使わない)/ alt も不要 -->
	<area shape="rect" coords="47,48,101,96">

	<!-- 2) 各リンク領域:href を付ける要素には alt を必ず付与 -->
	<area shape="rect"   coords="11,12,139,133" href="map/red.html"    alt="赤色のボックス">
	<area shape="circle" coords="221,76,65"     href="map/green.html"  alt="緑色の円">
	<area shape="poly"   coords="365,19,294,134,435,135" href="map/blue.html"   alt="青色の三角形">
	<area shape="poly"   coords="505,13,486,61,434,78,486,96,506,141,526,97,577,78,526,61"
						href="map/yellow.html" alt="黄色の星">
</map>

ポイント解説

穴(非リンク)を最初に定義
イメージマップは重なりがある場合、通常は先に定義された領域が優先されます。穴を最初に置くことで、内側はクリック不可になり、外側矩形のリンクと競合しません。
alt の付与
リンクになる <area> には必ず alt を付け、スクリーンリーダー利用者にリンク先の意味を伝えます。href が無い <area> はリンクではないため alt は不要です。
画像の alt
画像自体の alt は「何ができるのか(リンク目的)」も伝える文にします。

<area> の形と座標の書き方

shape="rect"(長方形)
coords="left,top,right,bottom"
左上と右下の座標(x,y)を 整数 で4つ記述。
shape="circle"(円)
coords="centerX,centerY,radius"
半径も 整数 指定。
shape="poly"(多角形)
coords="x1,y1,x2,y2,..."
最低3点(6数値)。閉じる点は不要(自動で閉じる)。

shape を省略すると rect と同義。

shape="default" は「他のどのエリアにも当たらない残り全部」。最後に置くのがセオリー。

座標系は CSS ピクセル(画像の表示サイズ基準)。小数は避け、整数で記述するとトラブルが少ないです。

usemap と name の仕様・落とし穴

アクセシビリティ設計

テキストの冗長だが確実な代替例:

HTML

<figure>
	<img src="floor.png" alt="フロア図: A〜Cエリア" usemap="#floorMap">
	<figcaption>
		<p>各エリアの詳細:</p>
		<ul>
			<li><a href="/area-a">Aエリア</a></li>
			<li><a href="/area-b">Bエリア</a></li>
			<li><a href="/area-c">Cエリア</a></li>
		</ul>
	</figcaption>
</figure>

レスポンシブ対応の選択肢

座標は表示サイズ基準なので、画像が縮尺すると座標も比例させる必要があります。主な対応は4通り。

A. 画像サイズを固定(最も簡単)

B. CSSで伸縮 + JSで座標スケール(実務でよく使う)

画像の実表示幅 / 元画像の実幅 の比率で coords を計算し直します。

形状を選択してください:

4つの形状をクリックすると各説明ページへ移動します(赤いボックス、緑の円、青の三角形、黄色の星)
赤色のボックス 緑色の円 青色の三角形 黄色の星

HTML

<!-- 実装例(レスポンシブ対応:CSSで伸縮 + JSで座標スケール) -->
<div class="responsive-image-map">
	<p>形状を選択してください:</p>

	<figure class="mapWrap">
		<!-- 画像はCSSで可変。width/height属性は“元画像の実寸”を明示(比率保持のヒント) -->
		<img
		id="shapesImg"
		src="imgs/map01.jpg"
		width="595" height="156"
		alt="4つの形状をクリックすると各説明ページへ移動します(赤いボックス、緑の円、青の三角形、黄色の星)"
		usemap="#shapesMapB"
		decoding="async"
		loading="lazy">
	</figure>

	<!-- map は name と id を両方付ける(互換性のため) -->
	<map name="shapesMapB" id="shapesMapB">
		<!-- 1) 穴領域(非リンク)。クリック不可の穴を先に定義 -->
		<!-- 元座標は data-raw-coords に保存しておき、JSで coords にスケールを書き戻す -->
		<area shape="rect" data-raw-coords="47,48,101,96">

		<!-- 2) 各リンク領域(href のある area には alt を付ける) -->
		<area shape="rect"   data-raw-coords="11,12,139,133" href="map/red.html"    alt="赤色のボックス">
		<area shape="circle" data-raw-coords="221,76,65"     href="map/green.html"  alt="緑色の円">
		<area shape="poly"   data-raw-coords="365,19,294,134,435,135" href="map/blue.html"   alt="青色の三角形">
		<area shape="poly"   data-raw-coords="505,13,486,61,434,78,486,96,506,141,526,97,577,78,526,61"
			href="map/yellow.html" alt="黄色の星">
	</map>
</div>

<script>
	<!-- JavaScript code here -->
</script>

CSS

/* 画像をコンテナ幅で伸縮(縦横比保持) */
.mapWrap { max-width: 100%; }
.mapWrap > img {
	display: block;
	max-width: 100%;
	height: auto;
}
/* タッチでも狙いやすいようにフォーカス可視化(お好みで) */
area[href]:focus {
	outline: 2px solid currentColor; /* UA依存だが最低限 */
}

JavaScript

(function () {
	const img = document.getElementById('shapesImg');
	const map = document.getElementById('shapesMapB');

	// 元座標(raw)を coords に反映させるユーティリティ
	function applyScaledCoords() {
		// naturalWidth/Height が読めることを前提(画像読み込み後)
		const baseW = img.naturalWidth || parseInt(img.getAttribute('width'), 10);
		const baseH = img.naturalHeight || parseInt(img.getAttribute('height'), 10);

		// 表示サイズ(CSSピクセル)。通常は等倍比率だが念のためX/Yを別々に
		const dispW = img.clientWidth;
		const dispH = img.clientHeight;

		const scaleX = dispW / baseW;
		const scaleY = dispH / baseH;

		map.querySelectorAll('area').forEach(area => {
			const raw = area.getAttribute('data-raw-coords');
			if (!raw) return;

			const nums = raw.split(',').map(n => parseFloat(n.trim()));
			const shape = (area.getAttribute('shape') || 'rect').toLowerCase();

			let scaled = [];
			if (shape === 'circle') {
				// [cx, cy, r]
				const cx = Math.round(nums[0] * scaleX);
				const cy = Math.round(nums[1] * scaleY);
				// 半径は等方スケール。歪み回避のため min を採用
				const r  = Math.round(nums[2] * Math.min(scaleX, scaleY));
				scaled = [cx, cy, r];
			} else {
				// rect/poly/default: 各点(x,y)を順にスケール
				for (let i = 0; i < nums.length; i += 2) {
					const x = Math.round(nums[i]     * scaleX);
					const y = Math.round(nums[i + 1] * scaleY);
					scaled.push(x, y);
				}
			}
			area.coords = scaled.join(',');
		});
	}

	// 画像の読み込み完了後に初回適用
	function ready(fn) {
		if (img.complete && img.naturalWidth) { fn(); }
		else { img.addEventListener('load', fn, { once: true }); }
	}

	// リサイズに追随(高頻度イベントは rAF で間引き)
	let ticking = false;
	function onResize() {
		if (!ticking) {
			window.requestAnimationFrame(() => {
				applyScaledCoords();
				ticking = false;
			});
			ticking = true;
		}
	}

	// CSSによる画像サイズ変化を確実に捕捉(コンテナの幅変化含む)
	const ro = new ResizeObserver(onResize);

	ready(() => {
		applyScaledCoords();
		ro.observe(img);
		window.addEventListener('orientationchange', onResize);
	});

	// ページ非表示→再表示やDPR変化(ズーム)にも念のため対応
	document.addEventListener('visibilitychange', () => {
		if (!document.hidden) onResize();
	});
})();

実装メモ(要点)

C. srcset/sizes + スクリプト

D. SVGに移行(構造的に最も堅牢)