HTMLの<img>タグは、Webサイトに画像を表示する基本であり、視覚的な魅力と情報伝達を担う重要な要素です。
本記事では、必須属性の書き方、スマホ対応のサイズ調整、CSSによる装飾、表示速度の改善やエラー対策を解説します。
HTMLにおけるimgタグの使い方と必須属性
Webサイトに写真やイラストを表示するには、HTMLの<img>タグを使用します。
このタグは「空要素(エンプティ要素)」と呼ばれ、終了タグ(</img>)が存在しないのが特徴です。
<img>タグの基本的な記法シンプルですが、画像を表示させる「src属性」、画像の説明を記述する「alt属性」の2つが必須属性として定められます。
ここでは、属性の書き方と実務で直面する「画像が表示されない」「SEOに悪影響を与える」といったトラブルの回避方法を解説します。
src属性で画像のパス・URLを指定するalt属性の意味とSEOへの影響title属性とキャプションの使い方
src属性で画像のパス・URLを指定する
<img>タグの中で重要なのが「どこにある画像を表示するかを指定するsrc属性」です。
指定方法には大きく分けて2種類あります。
- 絶対パス
https://...から始まるインターネット上のURLを指定する方法です。
外部サイトの画像を参照する場合などに使います。 - 相対パス
今編集しているHTMLファイルを基準に、画像ファイルがどのフォルダ階層にあるか(例:./images/photo.jpg)を指定する方法です。
実務ではこちらが主流です。
最初にぶつかる壁が「指定したはずの画像が表示されない」という現象です。
原因の多くがパス(場所の指定)のミスです。
- 拡張子の間違い
.jpgなのに.pngと書いている。 - 大文字・小文字の混同
パソコン上では表示されても、サーバーにアップロードするとPhoto.jpgとphoto.jpgは別のファイルとして厳密に区別されるため表示されません。
実務ではファイル名はすべて小文字で統一するのがよいです。 - 階層の間違い
一つ上のフォルダに戻る../の書き忘れや過剰記述。
※src属性で指定された画像が正しく読み込まれ、表示されています。
※パス(ファイル名や階層)を間違えると、ブラウザは画像を見つけられず「壊れたアイコン(リンク切れ)」と「alt属性のテキスト」を表示します。
HTMLコード表示
<div class="himg1-wrapper">
<input type="radio" name="himg1-state" id="himg1-good" class="himg1-radio" checked>
<input type="radio" name="himg1-state" id="himg1-bad" class="himg1-radio">
<div class="himg1-controls">
<label for="himg1-good" class="himg1-btn">⭕️ 正しいパス (画像表示)</label>
<label for="himg1-bad" class="himg1-btn">❌ パス間違い (リンク切れ)</label>
</div>
<div class="himg1-demo-area">
<div class="himg1-box target-good-himg1">
<div class="himg1-code">
<img src="https://placehold.co/300x200/0d6efd/fff?text=Success" alt="成功画像">
</div>
<div class="himg1-render">
<img src="https://placehold.co/300x200/0d6efd/fff?text=Success" alt="成功画像" class="himg1-img-preview">
</div>
<p class="himg1-note himg1-note-ok">※src属性で指定された画像が正しく読み込まれ、表示されています。</p>
</div>
<div class="himg1-box target-bad-himg1">
<div class="himg1-code himg1-code-bad">
<img src="images/wrong-path.jpg" alt="失敗画像">
</div>
<div class="himg1-render">
<img src="https://placehold.co/invalid-url-force-error" alt="失敗画像(パス間違い)" class="himg1-img-preview">
</div>
<p class="himg1-note">※パス(ファイル名や階層)を間違えると、ブラウザは画像を見つけられず「壊れたアイコン(リンク切れ)」と「alt属性のテキスト」を表示します。</p>
</div>
</div>
</div>CSSコード表示
.himg1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.himg1-radio {
display: none;
}
.himg1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.himg1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#himg1-good:checked ~ .himg1-controls [for="himg1-good"] {
background-color: #198754;
color: white;
}
#himg1-bad:checked ~ .himg1-controls [for="himg1-bad"] {
background-color: #dc3545;
color: white;
}
.himg1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.himg1-box {
width: 100%;
max-width: 400px;
text-align: center;
}
.himg1-code {
background-color: #d1e7dd;
color: #0f5132;
padding: 10px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
border-left: 4px solid #198754;
margin-bottom: 15px;
text-align: left;
word-break: break-all;
}
.himg1-code-bad {
background-color: #f8d7da;
color: #842029;
border-left-color: #dc3545;
}
.himg1-render {
background-color: #f1f3f5;
padding: 20px;
border: 1px solid #ccc;
border-radius: 4px;
min-height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
.himg1-img-preview {
max-width: 100%;
height: auto;
border: 1px solid #dee2e6;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.himg1-note {
font-size: 13px;
color: #dc3545;
font-weight: bold;
line-height: 1.5;
margin: 15px 0 0 0;
text-align: left;
}
.himg1-note-ok {
color: #198754;
}
/* 切り替え */
.target-bad-himg1 { display: none; }
#himg1-good:checked ~ .himg1-demo-area .target-good-himg1 { display: block; }
#himg1-good:checked ~ .himg1-demo-area .target-bad-himg1 { display: none; }
#himg1-bad:checked ~ .himg1-demo-area .target-good-himg1 { display: none; }
#himg1-bad:checked ~ .himg1-demo-area .target-bad-himg1 { display: block; }alt属性の意味とSEOへの影響
<img>タグにもう一つ必ず指定するのがalt属性です。
画像が表示されなかった時に代替されて表示するテキスト、及び視覚障害者が利用する音声読み上げソフト(スクリーンリーダー)が読み上げるテキストとして機能します。
また、Googleの検索エンジンは画像そのものの内容を人間のように理解できません。
そのため、alt属性に書かれたテキストを読んで「この画像は何の画像なのか」を判断し、画像検索の結果に反映させます。
つまり、alt属性を正しく書くことはSEO(検索エンジン最適化)において重要です。
※ロゴや写真など、コンテンツとして意味を持つ画像には、その内容を正確に表すテキストをalt属性に記述します。
※見栄えを良くするためだけの意味を持たない画像(アイコンや区切り線)は、読み上げソフトに無視させるためにalt属性の中身を「空(””)」にします。属性自体を消してはいけません。
HTMLコード表示
<div class="himg2-wrapper">
<input type="radio" name="himg2-state" id="himg2-meaning" class="himg2-radio" checked>
<input type="radio" name="himg2-state" id="himg2-deco" class="himg2-radio">
<div class="himg2-controls">
<label for="himg2-meaning" class="himg2-btn">意味のある画像 (altにテキスト)</label>
<label for="himg2-deco" class="himg2-btn">装飾用の画像 (altは空にする)</label>
</div>
<div class="himg2-demo-area">
<div class="himg2-box target-meaning-himg2">
<div class="himg2-img-container">
<img src="https://placehold.co/400x200/20c997/fff?text=Company+Logo" alt="株式会社〇〇のロゴ" class="himg2-img">
</div>
<div class="himg2-code">
<img src="logo.png" <span class="himg2-hl">alt="株式会社〇〇のロゴ"</span>>
</div>
<p class="himg2-note">※ロゴや写真など、コンテンツとして意味を持つ画像には、その内容を正確に表すテキストをalt属性に記述します。</p>
</div>
<div class="himg2-box target-deco-himg2">
<div class="himg2-img-container">
<img src="https://placehold.co/400x50/f8f9fa/ccc?text=~~~~~~~~~~~~~~~~~~~~~~~~~~~" alt="" class="himg2-img">
</div>
<div class="himg2-code">
<img src="wave-line.png" <span class="himg2-hl">alt=""</span>>
</div>
<p class="himg2-note">※見栄えを良くするためだけの意味を持たない画像(アイコンや区切り線)は、読み上げソフトに無視させるためにalt属性の中身を「空("")」にします。属性自体を消してはいけません。</p>
</div>
</div>
</div>CSSコード表示
.himg2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.himg2-radio {
display: none;
}
.himg2-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.himg2-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#himg2-meaning:checked ~ .himg2-controls [for="himg2-meaning"] {
background-color: #20c997;
color: white;
}
#himg2-deco:checked ~ .himg2-controls [for="himg2-deco"] {
background-color: #6c757d;
color: white;
}
.himg2-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.himg2-box {
width: 100%;
max-width: 450px;
}
.himg2-img-container {
text-align: center;
margin-bottom: 15px;
background-color: #f1f3f5;
padding: 20px;
border-radius: 4px;
}
.himg2-img {
max-width: 100%;
height: auto;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.himg2-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 14px;
border-radius: 4px;
margin-bottom: 15px;
text-align: center;
}
.himg2-hl {
color: #e5c07b;
font-weight: bold;
}
.himg2-note {
font-size: 14px;
color: #333;
line-height: 1.6;
margin: 0;
}
/* 切り替え */
.target-deco-himg2 { display: none; }
#himg2-meaning:checked ~ .himg2-demo-area .target-meaning-himg2 { display: block; }
#himg2-meaning:checked ~ .himg2-demo-area .target-deco-himg2 { display: none; }
#himg2-deco:checked ~ .himg2-demo-area .target-meaning-himg2 { display: none; }
#himg2-deco:checked ~ .himg2-demo-area .target-deco-himg2 { display: block; }title属性とキャプションの使い方
<img>タグの補足的な機能としてtitle属性があります。
これを指定すると、パソコンで画像の上にマウスカーソルを乗せたとき(ホバー時)に、小さな吹き出し(ツールチップ)としてテキストが表示されます。
また、画像の下に「図1:〇〇のグラフ」といったキャプション(説明文)を添えたい場合、HTML5では<figure>(フィギュア)要素と<figcaption>(フィグキャプション)要素 を使うのが正しい文法です。
画像と説明文を一つのセットとしてマークアップすることで、検索エンジンに「このテキストはこの画像の説明である」と正確に伝えられます。
※画像の上にマウスカーソルを数秒間乗せたままにすると、title属性に設定したテキストが吹き出し(ツールチップ)で表示されます。
<img src=”chart.jpg” alt=”売上グラフ”>
<figcaption>図1: 売上推移</figcaption>
</figure>
※画像と説明文(キャプション)をfigureタグで囲むことで、SEOに強く、スマホ環境でも確実に見える正しい構造になります。
HTMLコード表示
<div class="himg3-wrapper">
<input type="radio" name="himg3-state" id="himg3-title" class="himg3-radio" checked>
<input type="radio" name="himg3-state" id="himg3-figure" class="himg3-radio">
<div class="himg3-controls">
<label for="himg3-title" class="himg3-btn">title属性 (ツールチップ)</label>
<label for="himg3-figure" class="himg3-btn">✨ figure要素 (正しいキャプション)</label>
</div>
<div class="himg3-demo-area">
<div class="himg3-box target-title-himg3">
<div class="himg3-img-container" title="クリックすると拡大表示されます(※スマホではこのツールチップは出ません)">
<img src="https://placehold.co/300x200/6f42c1/fff?text=Hover+Me!" alt="サンプル画像" class="himg3-img">
</div>
<div class="himg3-code">
<img src="..." alt="..." <span class="himg3-hl">title="クリックすると拡大..."</span>>
</div>
<p class="himg3-note">※画像の上にマウスカーソルを数秒間乗せたままにすると、title属性に設定したテキストが吹き出し(ツールチップ)で表示されます。</p>
</div>
<div class="himg3-box target-figure-himg3">
<figure class="himg3-figure-tag">
<img src="https://placehold.co/300x200/fd7e14/fff?text=Data+Chart" alt="2023年の売上推移グラフ" class="himg3-img">
<figcaption class="himg3-figcaption-tag">図1: 2023年度の売上推移チャート</figcaption>
</figure>
<div class="himg3-code">
<span class="himg3-hl-tag"><figure></span><br>
<img src="chart.jpg" alt="売上グラフ"><br>
<span class="himg3-hl-tag"><figcaption></span>図1: 売上推移<span class="himg3-hl-tag"></figcaption></span><br>
<span class="himg3-hl-tag"></figure></span>
</div>
<p class="himg3-note himg3-note-ok">※画像と説明文(キャプション)をfigureタグで囲むことで、SEOに強く、スマホ環境でも確実に見える正しい構造になります。</p>
</div>
</div>
</div>CSSコード表示
.himg3-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.himg3-radio {
display: none;
}
.himg3-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.himg3-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#himg3-title:checked ~ .himg3-controls [for="himg3-title"] {
background-color: #6f42c1;
color: white;
}
#himg3-figure:checked ~ .himg3-controls [for="himg3-figure"] {
background-color: #fd7e14;
color: white;
}
.himg3-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.himg3-box {
width: 100%;
max-width: 450px;
}
.himg3-img-container {
text-align: center;
margin-bottom: 15px;
cursor: help; /* ツールチップが出ることを暗示 */
}
.himg3-img {
max-width: 100%;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* figureタグのスタイリング */
.himg3-figure-tag {
margin: 0 0 15px 0;
padding: 15px;
background-color: #f1f3f5;
border-radius: 4px;
text-align: center;
}
.himg3-figcaption-tag {
margin-top: 10px;
font-size: 14px;
color: #555;
font-weight: bold;
}
.himg3-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
margin-bottom: 15px;
line-height: 1.5;
}
.himg3-hl {
color: #c678dd; /* title部分をハイライト */
}
.himg3-hl-tag {
color: #d19a66; /* figure部分をハイライト */
font-weight: bold;
}
.himg3-note {
font-size: 13px;
color: #dc3545;
line-height: 1.6;
margin: 0;
font-weight: bold;
}
.himg3-note-ok {
color: #198754;
}
/* 切り替え */
.target-figure-himg3 { display: none; }
#himg3-title:checked ~ .himg3-demo-area .target-title-himg3 { display: block; }
#himg3-title:checked ~ .himg3-demo-area .target-figure-himg3 { display: none; }
#himg3-figure:checked ~ .himg3-demo-area .target-title-himg3 { display: none; }
#himg3-figure:checked ~ .himg3-demo-area .target-figure-himg3 { display: block; }画像サイズ(幅・高さ)と比率の調整方法
Webサイトに配置する画像の大きさをコントロールすることはレイアウトを保つ基本です。
<img>タグで画像を読み込んだ直後は、元画像の本来のサイズ(原寸大)で表示されます。
しかし、実際のデザインに合わせて画像のサイズ変更したり、特定の枠の中に収めたり、適切なサイズ指定が必須となります。
ここでは、HTML属性やCSSを用いた画像の幅と高さの指定方法から、スマホ対応におけるレスポンシブ手法、画像が潰れるのを防ぐトリミングを解説します。
widthとheightの指定方法- レスポンシブ対応(
100%やmax-width) - 画像のトリミングと比率維持(
object-fit)
widthとheightの指定方法
画像の幅と高さを指定する方法は、HTMLタグに直接記述する属性(例:<img src="..." width="300" height="200">)とCSSのプロパティ(例:width: 300px;)の2種類があります。
Web制作では、デザイン・レイアウトの制御は「CSSで行う」のが基本です。
レイアウトを組む際、「枠には横幅300px、高さ300pxで画像を入れよう」と考え、CSSでwidth: 300px; height: 300px;と両方の数値を固定指定するミスが多いです。
もし読み込まれた画像が長方形だった場合、無理やり正方形の枠に押し込まれるため、画像が縦に伸びたり横に潰れたりします。
画像の正しい比率を保つには「幅(width)か高さ(height)のどちらか一方だけ指定し、もう一方はautoにする」ことです。
これにより、ブラウザが画像の比率を計算し、サイズを調整してくれます。
height: 200px;
※元の横長画像が無理やり200×200の正方形に押し込まれ、縦に伸びて(潰れて)不自然になっています。
height: auto;
※高さをauto(自動)にしたことで、幅200pxに合わせて本来の比率のまま美しく縮小されています。
HTMLコード表示
<div class="hisz1-wrapper">
<input type="radio" name="hisz1-state" id="hisz1-bad" class="hisz1-radio" checked>
<input type="radio" name="hisz1-state" id="hisz1-good" class="hisz1-radio">
<div class="hisz1-controls">
<label for="hisz1-bad" class="hisz1-btn">❌ 両方固定 (潰れる)</label>
<label for="hisz1-good" class="hisz1-btn">⭕️ 片方auto (比率維持)</label>
</div>
<div class="hisz1-demo-area">
<div class="hisz1-box target-bad-hisz1">
<div class="hisz1-code">
width: 200px;<br>
<span class="hisz1-hl-error">height: 200px;</span>
</div>
<div class="hisz1-img-container">
<img src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&h=200&q=80" alt="横長の猫の写真" class="hisz1-img-bad">
</div>
<p class="hisz1-note">※元の横長画像が無理やり200x200の正方形に押し込まれ、縦に伸びて(潰れて)不自然になっています。</p>
</div>
<div class="hisz1-box target-good-hisz1">
<div class="hisz1-code hisz1-code-ok">
width: 200px;<br>
<span class="hisz1-hl-ok">height: auto;</span>
</div>
<div class="hisz1-img-container">
<img src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&h=200&q=80" alt="横長の猫の写真" class="hisz1-img-good">
</div>
<p class="hisz1-note hisz1-note-ok">※高さをauto(自動)にしたことで、幅200pxに合わせて本来の比率のまま美しく縮小されています。</p>
</div>
</div>
</div>CSSコード表示
.hisz1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hisz1-radio {
display: none;
}
.hisz1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hisz1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hisz1-bad:checked ~ .hisz1-controls [for="hisz1-bad"] {
background-color: #dc3545;
color: white;
}
#hisz1-good:checked ~ .hisz1-controls [for="hisz1-good"] {
background-color: #198754;
color: white;
}
.hisz1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.hisz1-box {
width: 100%;
max-width: 350px;
text-align: center;
}
.hisz1-code {
background-color: #f8d7da;
color: #842029;
padding: 15px;
font-family: monospace;
font-size: 14px;
border-radius: 4px;
border-left: 4px solid #dc3545;
margin-bottom: 15px;
text-align: left;
line-height: 1.5;
}
.hisz1-code-ok {
background-color: #d1e7dd;
color: #0f5132;
border-left-color: #198754;
}
.hisz1-hl-error {
font-weight: bold;
text-decoration: underline;
}
.hisz1-hl-ok {
font-weight: bold;
}
.hisz1-img-container {
background-color: #f1f3f5;
padding: 20px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 15px;
display: flex;
justify-content: center;
align-items: center;
min-height: 220px;
}
/* ❌ NGスタイル(確実に潰す) */
.hisz1-img-bad {
width: 200px !important;
height: 200px !important;
/* テーマ側の調整を無効化し、アスペクト比を無視して枠に合わせる魔法 */
object-fit: fill !important;
}
/* ⭕️ OKスタイル(比率維持) */
.hisz1-img-good {
width: 200px !important;
height: auto !important;
/* 比率を維持する */
object-fit: contain !important;
}
.hisz1-note {
font-size: 13px;
color: #dc3545;
font-weight: bold;
line-height: 1.5;
margin: 0;
text-align: left;
}
.hisz1-note-ok {
color: #198754;
}
/* 切り替え */
.target-good-hisz1 {
display: none;
}
#hisz1-bad:checked ~ .hisz1-demo-area .target-bad-hisz1 {
display: block;
}
#hisz1-good:checked ~ .hisz1-demo-area .target-bad-hisz1 {
display: none;
}
#hisz1-good:checked ~ .hisz1-demo-area .target-good-hisz1 {
display: block;
}widthとheightの設定方法を詳しく知りたい人は「【html&css】width(横幅)とheight(高さ)の指定とボックスモデル」を一読ください。
レスポンシブ対応(100%やmax-width)
PCからスマートフォンまで、画面サイズに合わせて画像を拡大・縮小させることを「レスポンシブ対応」と呼びます。
画面幅に合わせて画像を親要素いっぱい(100%)に広げるには、width: 100%;を指定します。
「スマホ対応ならとりあえず100%にすればいい」と考え、小さなアイコン画像などにまでwidth: 100%;を指定してしまうケースがあります。
しかし、これを行うと画像が300pxしかないのに、PCの1000pxの画面で見た時に無理やり1000pxまで引き伸ばされて画像がぼやけます。(画質の劣化)
実務における画像レスポンシブは、width: 100%;ではなくmax-width: 100%;を使うことです。
これにheight: auto;を組み合わせることで、「画面が狭いときは枠に合わせて縮小、画面が広いときは画像の本来のサイズより大きくはならない」という挙動を実現できます。(※特定の高さ以上に大きくしたくない場合はmax-heightを併用することもあります。)
【width: 100%; の罠】
元々は横幅150pxしかない小さな画像ですが、「100%」と指定されたことで広い親枠に合わせて無理やり引き伸ばされ、画質が粗く(ぼやけて)しまっています。
HTMLコード表示
<div class="hres1-wrapper">
<input type="radio" name="hres1-state" id="hres1-bad" class="hres1-radio" checked>
<input type="radio" name="hres1-state" id="hres1-good" class="hres1-radio">
<div class="hres1-controls">
<label for="hres1-bad" class="hres1-btn">❌ width: 100% (無理やり広がる)</label>
<label for="hres1-good" class="hres1-btn">⭕️ max-width: 100% (サイズと画質を保つ)</label>
</div>
<div class="hres1-demo-area">
<div class="hres1-parent-box">
<div class="hres1-label">親の枠(PCなどの広い画面)</div>
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=150&q=80" alt="猫の画像" class="hres1-img target-bad-hres1">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=150&q=80" alt="猫の画像" class="hres1-img target-good-hres1">
</div>
</div>
<div class="hres1-explanation">
<p id="desc-bad" class="hres1-desc" style="color:#dc3545; font-weight:bold;">【width: 100%; の罠】<br>元々は横幅150pxしかない小さな画像ですが、「100%」と指定されたことで広い親枠に合わせて無理やり引き伸ばされ、画質が粗く(ぼやけて)しまっています。</p>
<p id="desc-good" class="hres1-desc" style="display:none; color:#198754; font-weight:bold;">【max-width: 100%; の正解】<br>「最大で100%」という指定のため、親枠がどれだけ広くても元のサイズ(150px)以上には拡大されません。画質を美しく保ったまま、スマホなどの狭い画面の時だけ縮小してくれます。</p>
</div>
</div>CSSコード表示
.hres1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hres1-radio {
display: none;
}
.hres1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hres1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hres1-bad:checked ~ .hres1-controls [for="hres1-bad"] {
background-color: #dc3545;
color: white;
}
#hres1-good:checked ~ .hres1-controls [for="hres1-good"] {
background-color: #198754;
color: white;
}
.hres1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
/* デモエリア全体を広く使う */
width: 100%;
box-sizing: border-box;
}
.hres1-parent-box {
width: 100%; /* 親は常に広さを保つ */
background-color: #e9ecef;
border: 2px solid #ccc;
padding: 20px;
box-sizing: border-box;
text-align: center;
}
.hres1-label {
font-size: 14px;
color: #666;
margin-bottom: 15px;
font-weight: bold;
}
/* 共通の画像スタイル */
.hres1-img {
display: block;
margin: 0 auto;
border: 3px solid #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: all 0.3s ease;
}
/* ❌ NGスタイル(テーマの干渉を防いで強制的に100%に引き伸ばす) */
.target-bad-hres1 {
width: 100% !important;
max-width: none !important;
height: auto !important;
}
/* ⭕️ OKスタイル(本来のサイズでストップさせる) */
.target-good-hres1 {
width: auto !important;
max-width: 100% !important;
height: auto !important;
}
/* 切り替え */
.target-good-hres1 {
display: none;
}
#hres1-bad:checked ~ .hres1-demo-area .target-bad-hres1 {
display: block;
}
#hres1-good:checked ~ .hres1-demo-area .target-bad-hres1 {
display: none;
}
#hres1-good:checked ~ .hres1-demo-area .target-good-hres1 {
display: block;
}
.hres1-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hres1-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
}
#hres1-bad:checked ~ .hres1-explanation #desc-bad {
display: block !important;
}
#hres1-good:checked ~ .hres1-explanation #desc-bad {
display: none !important;
}
#hres1-good:checked ~ .hres1-explanation #desc-good {
display: block !important;
}
#hres1-bad:checked ~ .hres1-explanation #desc-good {
display: none !important;
}min-widthとmax-widthの使い方を知りたい人は「【html&css】min-widthとmax-widthの使い方【レスポンシブ対応】」を一読ください。
画像のトリミングと比率維持(object-fit)
実務では「デザインの都合上どうしても300px×300pxの正方形の枠に統一して表示させたい」という要望が発生します。
「画像サイズや比率を無理やり固定しつつ画像の潰れを防ぐ」という難題を解決するCSSがobject-fitプロパティです。
object-fitを使えば、画像の中央部分を切り抜いたり、枠の中に画像全体を収めたりといった制御が可能になります。
object-fit: cover;(カバー)
指定した縦横の枠に隙間なく画像を広げます。
枠からはみ出した部分は自動的にトリミングされるため、サムネイル画像やカードデザインなどで枠を揃えたい時に活躍します。object-fit: contain;(コンテイン)
枠の中に画像全体が収まるように縮小します。
比率が合わない部分には余白が生まれます。
ECサイトの商品画像など「全体を欠けることなく見せたい」場合に使用します。
【対策なし】
横150px、縦300pxの縦長写真を、200×200の正方形の枠に指定したため、横に引き伸ばされて潰れて(太って)しまっています。
HTMLコード表示
<div class="hofit1-wrapper">
<input type="radio" name="hofit1-state" id="hofit1-bad" class="hofit1-radio" checked>
<input type="radio" name="hofit1-state" id="hofit1-cover" class="hofit1-radio">
<input type="radio" name="hofit1-state" id="hofit1-contain" class="hofit1-radio">
<div class="hofit1-controls">
<label for="hofit1-bad" class="hofit1-btn">❌ 対策なし (潰れる)</label>
<label for="hofit1-cover" class="hofit1-btn">✂️ object-fit: cover</label>
<label for="hofit1-contain" class="hofit1-btn">📦 object-fit: contain</label>
</div>
<div class="hofit1-demo-area">
<div class="hofit1-box">
<div class="hofit1-code-label">200x200 の枠</div>
<div class="hofit1-img-wrapper">
<img src="https://images.unsplash.com/photo-1592194996308-7b43878e84a6?ixlib=rb-4.0.3&auto=format&fit=crop&w=150&h=300&q=80" alt="縦長の猫の写真" class="hofit1-img target-img-hofit1">
</div>
</div>
</div>
<div class="hofit1-explanation">
<p id="desc-bad" class="hofit1-desc">【対策なし】<br>横150px、縦300pxの縦長写真を、200x200の正方形の枠に指定したため、横に引き伸ばされて潰れて(太って)しまっています。</p>
<p id="desc-cover" class="hofit1-desc" style="display:none; color:#dc3545; font-weight:bold;">【object-fit: cover;】<br>枠全体を隙間なく埋めつつ、比率を維持します。結果として、猫の体の上下の部分が自動的にトリミング(切り抜き)され、美しい正方形のサムネイルになります。</p>
<p id="desc-contain" class="hofit1-desc" style="display:none; color:#198754; font-weight:bold;">【object-fit: contain;】<br>画像の全体が必ず枠の中に収まるように縮小されます。比率が合わない左右の部分には余白が生まれます。</p>
</div>
</div>CSSコード表示
.hofit1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hofit1-radio {
display: none;
}
.hofit1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hofit1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hofit1-bad:checked ~ .hofit1-controls [for="hofit1-bad"] {
background-color: #6c757d;
color: white;
}
#hofit1-cover:checked ~ .hofit1-controls [for="hofit1-cover"] {
background-color: #dc3545;
color: white;
}
#hofit1-contain:checked ~ .hofit1-controls [for="hofit1-contain"] {
background-color: #198754;
color: white;
}
.hofit1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.hofit1-box {
text-align: center;
}
.hofit1-code-label {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.hofit1-img-wrapper {
border: 2px solid #333; /* 200x200の枠を見えやすくする */
background-color: #e9ecef; /* 余白を見えやすくする */
font-size: 0; /* inline-blockの隙間対策 */
line-height: 0; /* inline-blockの隙間対策 */
display: flex;
justify-content: center;
align-items: center;
}
/* 共通のサイズ指定(固定の正方形枠) */
.hofit1-img {
width: 200px !important;
height: 200px !important;
transition: all 0.3s ease;
border: 1px solid #ccc; /* 境界を分かりやすく */
}
/* ❌ 対策なし */
#hofit1-bad:checked ~ .hofit1-demo-area .target-img-hofit1 {
object-fit: fill !important; /* 初期値(無理やり潰す) */
}
/* ✂️ cover (トリミング) */
#hofit1-cover:checked ~ .hofit1-demo-area .target-img-hofit1 {
object-fit: cover !important;
object-position: center !important; /* 中央に合わせる */
}
/* 📦 contain (収める) */
#hofit1-contain:checked ~ .hofit1-demo-area .target-img-hofit1 {
object-fit: contain !important;
object-position: center !important; /* 中央に合わせる */
}
.hofit1-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hofit1-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
}
#hofit1-bad:checked ~ .hofit1-explanation #desc-bad { display: block !important; }
#hofit1-bad:checked ~ .hofit1-explanation #desc-cover,
#hofit1-bad:checked ~ .hofit1-explanation #desc-contain { display: none !important; }
#hofit1-cover:checked ~ .hofit1-explanation #desc-cover { display: block !important; }
#hofit1-cover:checked ~ .hofit1-explanation #desc-bad,
#hofit1-cover:checked ~ .hofit1-explanation #desc-contain { display: none !important; }
#hofit1-contain:checked ~ .hofit1-explanation #desc-contain { display: block !important; }
#hofit1-contain:checked ~ .hofit1-explanation #desc-bad,
#hofit1-contain:checked ~ .hofit1-explanation #desc-cover { display: none !important; }画像の配置・レイアウト(中央寄せ・回り込み・余白)
Webサイトを作る上で、テキストと並んで重要なのが画像の配置です。
つまずきやすい点として、「<img>タグはデフォルトでは文字と同じ『インライン要素』として扱われる」ということです。
この仕様を理解しないと「中央に寄せたいのに動かない」「画像の下に謎の隙間ができる」といったトラブルに悩まされます。
状況に応じて画像をブロックレベル要素に変更するなどが必要です。
- 画像を中央や右寄せに配置する
- テキストの回り込みや横並び
- 画像周りの余白の調整
画像を中央や右寄せに配置する
画像を画面中央や右側に配置するには、主に2つのアプローチがあります。
- 親要素に指示を出す
画像がインライン要素であることを利用し、画像を囲んでいる親の<div>に対してtext-align: center;やtext-align: right;を指定します。 - 画像自身に指示を出す
画像にdisplay: block;を指定して「箱」に変えた上でmargin: 0 auto;を指定して中央寄せにします。
margin: 0 auto;という中央寄せは「ブロックレベル要素」にしか効きません。
初期状態の<img>(インライン要素)にmargin: 0 auto;を書いても無視されます。
画像を中央に寄せたい場合は、 display: block;をセットで記述することを忘れないでください。
【初期状態】
画像はテキストと同じ扱い(インライン要素)なので、左から右へ配置されます。
HTMLコード表示
<div class="halign1-wrapper">
<input type="radio" name="halign1-state" id="halign1-left" class="halign1-radio" checked>
<input type="radio" name="halign1-state" id="halign1-textcenter" class="halign1-radio">
<input type="radio" name="halign1-state" id="halign1-blockcenter" class="halign1-radio">
<input type="radio" name="halign1-state" id="halign1-right" class="halign1-radio">
<div class="halign1-controls">
<label for="halign1-left" class="halign1-btn">左寄せ (初期)</label>
<label for="halign1-textcenter" class="halign1-btn">親に text-align: center</label>
<label for="halign1-blockcenter" class="halign1-btn">自身に block + margin: auto</label>
<label for="halign1-right" class="halign1-btn">親に text-align: right</label>
</div>
<div class="halign1-demo-area">
<div class="halign1-parent">
<div class="halign1-label">親要素の div</div>
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=150&q=80" alt="猫の画像" class="halign1-img">
</div>
</div>
<div class="halign1-explanation">
<p id="desc-left" class="halign1-desc">【初期状態】<br>画像はテキストと同じ扱い(インライン要素)なので、左から右へ配置されます。</p>
<p id="desc-textcenter" class="halign1-desc" style="display:none; color:#198754; font-weight:bold;">【text-align: center;】<br>画像を囲む親のdivに指定しています。画像は文字と同じ扱いなので、中央に揃います。</p>
<p id="desc-blockcenter" class="halign1-desc" style="display:none; color:#0d6efd; font-weight:bold;">【display: block; margin: 0 auto;】<br>画像「自身」に指定しています。画像をブロック(箱)に変更した上で、左右の余白を自動にして中央に配置しています。</p>
<p id="desc-right" class="halign1-desc" style="display:none; color:#fd7e14; font-weight:bold;">【text-align: right;】<br>親のdivに指定しています。文字の右揃えと同じ原理で、画像が右に寄ります。</p>
</div>
</div>CSSコード表示
.halign1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.halign1-radio {
display: none;
}
.halign1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.halign1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#halign1-left:checked ~ .halign1-controls [for="halign1-left"] { background-color: #6c757d; color: white; }
#halign1-textcenter:checked ~ .halign1-controls [for="halign1-textcenter"] { background-color: #198754; color: white; }
#halign1-blockcenter:checked ~ .halign1-controls [for="halign1-blockcenter"] { background-color: #0d6efd; color: white; }
#halign1-right:checked ~ .halign1-controls [for="halign1-right"] { background-color: #fd7e14; color: white; }
.halign1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
}
.halign1-parent {
background-color: #e9ecef;
border: 2px solid #ccc;
padding: 15px;
transition: all 0.3s ease;
}
.halign1-label {
font-size: 12px;
color: #666;
margin-bottom: 10px;
font-weight: bold;
}
.halign1-img {
width: 150px;
height: auto;
border: 3px solid #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: all 0.3s ease;
}
/* 左寄せ(デフォルト) */
#halign1-left:checked ~ .halign1-demo-area .halign1-parent { text-align: left; }
#halign1-left:checked ~ .halign1-demo-area .halign1-img { display: inline; margin: 0; }
/* 親に text-align: center; */
#halign1-textcenter:checked ~ .halign1-demo-area .halign1-parent { text-align: center; }
#halign1-textcenter:checked ~ .halign1-demo-area .halign1-img { display: inline; margin: 0; }
/* 画像自身に display: block; margin: 0 auto; */
#halign1-blockcenter:checked ~ .halign1-demo-area .halign1-parent { text-align: left; /* 親は左寄せのまま */ }
#halign1-blockcenter:checked ~ .halign1-demo-area .halign1-img { display: block !important; margin: 0 auto !important; }
/* 親に text-align: right; */
#halign1-right:checked ~ .halign1-demo-area .halign1-parent { text-align: right; }
#halign1-right:checked ~ .halign1-demo-area .halign1-img { display: inline; margin: 0; }
.halign1-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.halign1-desc { margin: 0; font-size: 14px; line-height: 1.6; }
#halign1-left:checked ~ .halign1-explanation #desc-left { display: block !important; }
#halign1-left:checked ~ .halign1-explanation #desc-textcenter, #halign1-left:checked ~ .halign1-explanation #desc-blockcenter, #halign1-left:checked ~ .halign1-explanation #desc-right { display: none !important; }
#halign1-textcenter:checked ~ .halign1-explanation #desc-textcenter { display: block !important; }
#halign1-textcenter:checked ~ .halign1-explanation #desc-left, #halign1-textcenter:checked ~ .halign1-explanation #desc-blockcenter, #halign1-textcenter:checked ~ .halign1-explanation #desc-right { display: none !important; }
#halign1-blockcenter:checked ~ .halign1-explanation #desc-blockcenter { display: block !important; }
#halign1-blockcenter:checked ~ .halign1-explanation #desc-left, #halign1-blockcenter:checked ~ .halign1-explanation #desc-textcenter, #halign1-blockcenter:checked ~ .halign1-explanation #desc-right { display: none !important; }
#halign1-right:checked ~ .halign1-explanation #desc-right { display: block !important; }
#halign1-right:checked ~ .halign1-explanation #desc-left, #halign1-right:checked ~ .halign1-explanation #desc-textcenter, #halign1-right:checked ~ .halign1-explanation #desc-blockcenter { display: none !important; }テキストの回り込みや横並び
ニュース記事やブログで見かける「画像の横にテキストが回り込む」レイアウトを作りたい場合は、CSSのfloat プロパティを使用します。
画像に対してfloat: left;やfloat: right;を指定します。
float を使って頻繁に起きるミスが「回り込みの解除忘れ」です。
float は画像の下にある本来回り込ませたくない要素まで横に回り込んでしまい、ページ全体のレイアウトが崩壊します。
実務では、回り込みを終わらせたい箇所でclear: both;というCSSを使って、floatの効果を断ち切る必要があります。
現在、横並びにはFlexboxを使うのが主流ですが、「文章の中に画像を浮かせて文字を回り込ませる」という用途ではfloatが使われます。
ここは画像に対する説明文です。floatプロパティを使うと、画像が浮き上がり、テキストがその周囲を回り込むように配置されます。ブログ記事などで非常によく使われるレイアウト手法です。
【回り込みなし】
画像はブロックとして扱われず、テキストはその下(または横のわずかなスペース)から始まります。次のセクションは安全に下へ配置されます。
HTMLコード表示
<div class="hflo1-wrapper">
<input type="radio" name="hflo1-state" id="hflo1-none" class="hflo1-radio" checked>
<input type="radio" name="hflo1-state" id="hflo1-float" class="hflo1-radio">
<input type="radio" name="hflo1-state" id="hflo1-clear" class="hflo1-radio">
<div class="hflo1-controls">
<label for="hflo1-none" class="hflo1-btn">回り込みなし</label>
<label for="hflo1-float" class="hflo1-btn">❌ float: left (解除忘れ)</label>
<label for="hflo1-clear" class="hflo1-btn">⭕️ float + clear: both (解除)</label>
</div>
<div class="hflo1-demo-area">
<div class="hflo1-content-box">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=100&q=80" alt="猫" class="hflo1-img">
<p class="hflo1-text">
ここは画像に対する説明文です。floatプロパティを使うと、画像が浮き上がり、テキストがその周囲を回り込むように配置されます。ブログ記事などで非常によく使われるレイアウト手法です。
</p>
<div class="hflo1-clearfix"></div>
</div>
<div class="hflo1-next-element">
次のセクション(本来は画像の下に配置したい)
</div>
</div>
<div class="hflo1-explanation">
<p id="desc-none" class="hflo1-desc">【回り込みなし】<br>画像はブロックとして扱われず、テキストはその下(または横のわずかなスペース)から始まります。次のセクションは安全に下へ配置されます。</p>
<p id="desc-float" class="hflo1-desc" style="display:none; color:#dc3545; font-weight:bold;">【解除忘れの罠】<br>画像が浮き上がりテキストが回り込みましたが、効果が続いているため、「次のセクション」まで無理やり画像の横に引きずり込まれてレイアウトが崩壊しています。</p>
<p id="desc-clear" class="hflo1-desc" style="display:none; color:#198754; font-weight:bold;">【clear: both; による解除】<br>テキストが回り込んだ後、見えないブロックで「clear: both;」を実行しました。floatの効果が断ち切られ、次のセクションが正しく画像の下に配置されています。</p>
</div>
</div>CSSコード表示
.hflo1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hflo1-radio {
display: none;
}
.hflo1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hflo1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hflo1-none:checked ~ .hflo1-controls [for="hflo1-none"] { background-color: #6c757d; color: white; }
#hflo1-float:checked ~ .hflo1-controls [for="hflo1-float"] { background-color: #dc3545; color: white; }
#hflo1-clear:checked ~ .hflo1-controls [for="hflo1-clear"] { background-color: #198754; color: white; }
.hflo1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
}
.hflo1-content-box {
background-color: #f1f3f5;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
.hflo1-img {
width: 100px;
height: auto;
border: 2px solid #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
margin-right: 15px; /* テキストとの隙間 */
margin-bottom: 10px;
transition: all 0.3s ease;
}
.hflo1-text {
font-size: 14px;
line-height: 1.6;
color: #333;
margin: 0;
}
.hflo1-next-element {
background-color: #fd7e14;
color: white;
padding: 15px;
margin-top: 15px;
border-radius: 4px;
font-weight: bold;
text-align: center;
transition: all 0.3s ease;
}
/* ❌ float: left; のみ(解除なし) */
#hflo1-float:checked ~ .hflo1-demo-area .hflo1-img {
float: left;
}
/* ⭕️ float + 解除 */
#hflo1-clear:checked ~ .hflo1-demo-area .hflo1-img {
float: left;
}
#hflo1-clear:checked ~ .hflo1-demo-area .hflo1-clearfix {
clear: both; /* ここで回り込みの魔法を断ち切る! */
}
.hflo1-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hflo1-desc { margin: 0; font-size: 14px; line-height: 1.6; }
#hflo1-none:checked ~ .hflo1-explanation #desc-none { display: block !important; }
#hflo1-none:checked ~ .hflo1-explanation #desc-float, #hflo1-none:checked ~ .hflo1-explanation #desc-clear { display: none !important; }
#hflo1-float:checked ~ .hflo1-explanation #desc-float { display: block !important; }
#hflo1-float:checked ~ .hflo1-explanation #desc-none, #hflo1-float:checked ~ .hflo1-explanation #desc-clear { display: none !important; }
#hflo1-clear:checked ~ .hflo1-explanation #desc-clear { display: block !important; }
#hflo1-clear:checked ~ .hflo1-explanation #desc-none, #hflo1-clear:checked ~ .hflo1-explanation #desc-float { display: none !important; }画像周りの余白の調整
画像と隣り合うテキストや他の要素との距離を空けるには、外側の余白を作るmarginや内側の余白を作るpaddingを使用します。
例えば、左に置いた画像の右側にテキストがある場合、画像に対してmargin-right: 20px;などを指定して隙間を作ります。
画像を配置して背景色などをつけた際、「画像の下に数ピクセルの謎の隙間が空いている。」といった実務あるあるがあります。
これはバグではなくHTMLの仕様です。
<img>は文字と同じインライン要素として扱われるため、アルファベットの「g」や「j」の尻尾部分を下へ伸ばす「文字用の隙間」が画像の下にも確保されるのが原因です。
隙間を消し去る方法は2つあります。
- 画像を文字のベースラインではなく一番下に揃える:
vertical-align: bottom; - 画像を文字ではなくブロック(箱)に変更する:
display: block;
※画像の下に赤い背景色(隙間)が数ピクセル見えてしまっています。
HTMLコード表示
<div class="hspa1-wrapper">
<input type="radio" name="hspa1-state" id="hspa1-bad" class="hspa1-radio" checked>
<input type="radio" name="hspa1-state" id="hspa1-vertical" class="hspa1-radio">
<input type="radio" name="hspa1-state" id="hspa1-block" class="hspa1-radio">
<div class="hspa1-controls">
<label for="hspa1-bad" class="hspa1-btn">❌ 初期状態 (謎の隙間あり)</label>
<label for="hspa1-vertical" class="hspa1-btn">⭕️ vertical-align: bottom</label>
<label for="hspa1-block" class="hspa1-btn">⭕️ display: block</label>
</div>
<div class="hspa1-demo-area">
<div class="hspa1-box">
<div class="hspa1-label">親要素(背景色:赤)</div>
<div class="hspa1-img-container target-container-hspa1">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=200&q=80" alt="猫" class="hspa1-img target-img-hspa1">
</div>
<p class="hspa1-note" id="note-bad">※画像の下に赤い背景色(隙間)が数ピクセル見えてしまっています。</p>
<p class="hspa1-note hspa1-note-ok" id="note-good" style="display:none;">※隙間が完全に消え、画像と親の枠がピタッとくっつきました。</p>
</div>
</div>
</div>CSSコード表示
.hspa1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hspa1-radio {
display: none;
}
.hspa1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hspa1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hspa1-bad:checked ~ .hspa1-controls [for="hspa1-bad"] { background-color: #dc3545; color: white; }
#hspa1-vertical:checked ~ .hspa1-controls [for="hspa1-vertical"] { background-color: #198754; color: white; }
#hspa1-block:checked ~ .hspa1-controls [for="hspa1-block"] { background-color: #0d6efd; color: white; }
.hspa1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.hspa1-box {
text-align: center;
}
.hspa1-label {
font-size: 12px;
color: #666;
margin-bottom: 10px;
font-weight: bold;
}
/* 隙間を分かりやすくするため、親に赤い背景を設定 */
.hspa1-img-container {
background-color: #dc3545;
display: inline-block; /* 画像の幅に合わせる */
}
.hspa1-img {
width: 200px;
height: auto;
/* borderなどを無くし、純粋に画像だけにする */
border: none;
margin: 0;
padding: 0;
}
/* ❌ 初期状態:テーマの干渉を防ぎ、意図的にインラインに戻す */
#hspa1-bad:checked ~ .hspa1-demo-area .target-img-hspa1 {
display: inline !important;
vertical-align: baseline !important;
}
/* ⭕️ 解決法1:vertical-align: bottom; */
#hspa1-vertical:checked ~ .hspa1-demo-area .target-img-hspa1 {
display: inline !important;
vertical-align: bottom !important;
}
/* ⭕️ 解決法2:display: block; */
#hspa1-block:checked ~ .hspa1-demo-area .target-img-hspa1 {
display: block !important;
}
.hspa1-note {
font-size: 13px;
color: #dc3545;
font-weight: bold;
line-height: 1.5;
margin: 15px 0 0 0;
}
.hspa1-note-ok {
color: #198754;
}
#hspa1-bad:checked ~ .hspa1-demo-area #note-bad { display: block; }
#hspa1-bad:checked ~ .hspa1-demo-area #note-good { display: none; }
#hspa1-vertical:checked ~ .hspa1-demo-area #note-bad, #hspa1-block:checked ~ .hspa1-demo-area #note-bad { display: none; }
#hspa1-vertical:checked ~ .hspa1-demo-area #note-good, #hspa1-block:checked ~ .hspa1-demo-area #note-good { display: block; }ブロックレベル要素で重要なdisplayプロパティを詳しく知りたい人は「【html&css】displayの種類は?flexやinline-blockの違い」を一読ください。
CSSを使った画像のデザイン・装飾
画像に対してCSSを用いたデザイン・装飾が欠かせません。
枠線をつけて写真を目立たせたり、角を丸めて柔らかい印象にしたり、マウスを乗せた時に動かしたりとCSSで画像の表現力高めます。
ここでは、実務で使う画像の装飾を解説します。
- 枠線をつける・角を丸くする
- 重ねる・ホバー時のエフェクト(透過・フィルター)
- 画像を回転させる(
rotate)
枠線をつける・角を丸くする
画像と背景の境界に枠線を引くには、borderプロパティを使用し、線の太さ・種類・色を一括で指定します。
さらに、Webデザインで欠かせないのが「画像の角を丸くする」処理です。これには border-radius(html img border radius)プロパティを使用します。
例えば、「プロフィールアイコンを丸にしたい」とborder-radius: 50%;を指定した際、画像が円にならず楕円形に歪むことがあります。
これは、画像の形が「正方形」ではないためです。
border-radius: 50%;は「画像の縦横の長さに対して50%の丸みをつける」という指示なので、長方形の画像にかけると歪みます。
正円にするには、CSSで縦横の長さを同じ(例:width: 100px; height: 100px;)にした上で、object-fit: cover;を使って画像を正方形にトリミングするのがよいです。
【装飾なし】
通常の横長(300×200)の画像です。
HTMLコード表示
<div class="hdec1-wrapper">
<input type="radio" name="hdec1-state" id="hdec1-normal" class="hdec1-radio" checked>
<input type="radio" name="hdec1-state" id="hdec1-border" class="hdec1-radio">
<input type="radio" name="hdec1-state" id="hdec1-radius" class="hdec1-radio">
<input type="radio" name="hdec1-state" id="hdec1-circle" class="hdec1-radio">
<div class="hdec1-controls">
<label for="hdec1-normal" class="hdec1-btn">装飾なし</label>
<label for="hdec1-border" class="hdec1-btn">枠線 (border)</label>
<label for="hdec1-radius" class="hdec1-btn">角丸 (radius)</label>
<label for="hdec1-circle" class="hdec1-btn">✨ 綺麗な正円</label>
</div>
<div class="hdec1-demo-area">
<div class="hdec1-box">
<img src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?auto=format&fit=crop&w=300&h=200&q=80" alt="猫" class="hdec1-img target-img-hdec1">
</div>
</div>
<div class="hdec1-explanation">
<p id="desc-normal" class="hdec1-desc">【装飾なし】<br>通常の横長(300x200)の画像です。</p>
<p id="desc-border" class="hdec1-desc" style="display:none; color:#0d6efd; font-weight:bold;">【border: 4px solid #0d6efd;】<br>画像の周囲に4pxの青い実線を追加しました。</p>
<p id="desc-radius" class="hdec1-desc" style="display:none; color:#198754; font-weight:bold;">【border-radius: 20px;】<br>四隅の角を20px分だけ丸くして、柔らかい印象にしました。</p>
<p id="desc-circle" class="hdec1-desc" style="display:none; color:#dc3545; font-weight:bold;">【綺麗な正円の魔法】<br>横長画像にそのまま50%をかけると楕円になるため、幅と高さを「200px」に統一し、<code>object-fit: cover;</code> で正方形にトリミングしてから <code>border-radius: 50%;</code> をかけています。</p>
</div>
</div>CSSコード表示
.hdec1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hdec1-radio {
display: none;
}
.hdec1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hdec1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hdec1-normal:checked ~ .hdec1-controls [for="hdec1-normal"] {
background-color: #6c757d;
color: white;
}
#hdec1-border:checked ~ .hdec1-controls [for="hdec1-border"] {
background-color: #0d6efd;
color: white;
}
#hdec1-radius:checked ~ .hdec1-controls [for="hdec1-radius"] {
background-color: #198754;
color: white;
}
#hdec1-circle:checked ~ .hdec1-controls [for="hdec1-circle"] {
background-color: #dc3545;
color: white;
}
.hdec1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 40px 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 250px;
}
.hdec1-box {
text-align: center;
}
/* 共通の画像スタイル */
.hdec1-img {
width: 300px;
height: 200px;
object-fit: cover; /* デフォルトで枠に合わせる設定 */
transition: all 0.4s ease; /* 変化を滑らかにするアニメーション */
box-sizing: border-box; /* 枠線を幅に含める */
}
/* 通常 */
#hdec1-normal:checked ~ .hdec1-demo-area .target-img-hdec1 {
border: none;
border-radius: 0;
}
/* 枠線 */
#hdec1-border:checked ~ .hdec1-demo-area .target-img-hdec1 {
border: 6px solid #0d6efd;
border-radius: 0;
}
/* 角丸 */
#hdec1-radius:checked ~ .hdec1-demo-area .target-img-hdec1 {
border: 6px solid #198754;
border-radius: 30px;
}
/* 綺麗な正円 */
#hdec1-circle:checked ~ .hdec1-demo-area .target-img-hdec1 {
border: 6px solid #dc3545;
/* 円にするために、まず完全な正方形にする */
width: 200px;
height: 200px;
/* はみ出しをカットする魔法 */
object-fit: cover;
/* 50%で完全な円になる */
border-radius: 50%;
}
.hdec1-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hdec1-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
}
.hdec1-desc code {
background-color: #f1f3f5;
padding: 2px 6px;
border-radius: 4px;
color: #d63384;
}
/* 説明文の切り替え */
#hdec1-normal:checked ~ .hdec1-explanation #desc-normal { display: block !important; }
#hdec1-normal:checked ~ .hdec1-explanation #desc-border, #hdec1-normal:checked ~ .hdec1-explanation #desc-radius, #hdec1-normal:checked ~ .hdec1-explanation #desc-circle { display: none !important; }
#hdec1-border:checked ~ .hdec1-explanation #desc-border { display: block !important; }
#hdec1-border:checked ~ .hdec1-explanation #desc-normal, #hdec1-border:checked ~ .hdec1-explanation #desc-radius, #hdec1-border:checked ~ .hdec1-explanation #desc-circle { display: none !important; }
#hdec1-radius:checked ~ .hdec1-explanation #desc-radius { display: block !important; }
#hdec1-radius:checked ~ .hdec1-explanation #desc-normal, #hdec1-radius:checked ~ .hdec1-explanation #desc-border, #hdec1-radius:checked ~ .hdec1-explanation #desc-circle { display: none !important; }
#hdec1-circle:checked ~ .hdec1-explanation #desc-circle { display: block !important; }
#hdec1-circle:checked ~ .hdec1-explanation #desc-normal, #hdec1-circle:checked ~ .hdec1-explanation #desc-border, #hdec1-circle:checked ~ .hdec1-explanation #desc-radius { display: none !important; }重ねる・ホバー時のエフェクト(透過・フィルター)
画像をリンクボタンとして使う場合、マウスを乗せた時に「ポインタが当たっていること」を視覚的に伝えるアニメーションは重要です。
画像を少し透過させたり、filterプロパティを使って画像の色調変更したりするのが定番の手法です。
ただし、スマートフォンやタブレットはマウスカーソルが存在しないため、:hoverエフェクトは指でタップした一瞬しか発動しません。
ホバーしないと読めないテキストを配置すると、スマホユーザーはその情報を読めずUXの低下を招きます。
実務では、「スマホの時はテキストを表示させておく(ホバーの解除)」といったメディアクエリを用いたレスポンシブな配慮が必要です。
【CSSの仕組み】
親枠にマウスが乗った(:hover)瞬間、以下の2つが同時に発動します。
1. 画像に対して filter: brightness(0.5); がかかり、画像の明るさが50%(暗く)なります。
2. 重ねていたテキストの opacity(透明度)が 0 から 1 に変わり、フワッと浮かび上がります。
HTMLコード表示
<div class="hdec2-wrapper">
<div class="hdec2-demo-area">
<div class="hdec2-label">↓ 画像にマウスカーソルを乗せてください ↓</div>
<div class="hdec2-card">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=300&h=300&q=80" alt="猫" class="hdec2-img">
<div class="hdec2-overlay-text">
<div class="hdec2-text-title">View Details</div>
<p class="hdec2-text-sub">詳細を見る</p>
</div>
</div>
</div>
<div class="hdec2-explanation">
<p class="hdec2-desc">
<strong>【CSSの仕組み】</strong><br>
親枠にマウスが乗った(<code>:hover</code>)瞬間、以下の2つが同時に発動します。<br>
1. 画像に対して <code>filter: brightness(0.5);</code> がかかり、画像の明るさが50%(暗く)なります。<br>
2. 重ねていたテキストの <code>opacity</code>(透明度)が 0 から 1 に変わり、フワッと浮かび上がります。
</p>
</div>
</div>CSSコード表示
.hdec2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hdec2-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 40px 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.hdec2-label {
font-size: 14px;
font-weight: bold;
color: #0d6efd;
margin-bottom: 20px;
background-color: #e7f1ff;
padding: 8px 16px;
border-radius: 20px;
}
/* ★カードの親枠(重ねるための基準にする) */
.hdec2-card {
position: relative; /* 子要素を絶対配置するための基準点 */
width: 250px;
height: 250px;
border-radius: 10px;
overflow: hidden; /* 画像のはみ出しや角丸を綺麗にカット */
cursor: pointer; /* クリックできることを暗示 */
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* ★ベースの画像 */
.hdec2-img {
width: 100%;
height: 100%;
object-fit: cover;
/* ホバー時の変化を滑らかにする(明るさと少し拡大) */
transition: filter 0.3s ease, transform 0.3s ease;
}
/* ★重ねるテキストの枠 */
.hdec2-overlay-text {
position: absolute; /* 親枠を基準にして絶対配置 */
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
/* 初期状態は透明にして隠す */
opacity: 0;
/* ホバー時の変化を滑らかにする */
transition: opacity 0.3s ease;
/* テキストが画像に馴染むように少し影をつける */
text-shadow: 0 2px 4px rgba(0,0,0,0.8);
}
.hdec2-text-title {
margin: 0 0 5px 0;
font-size: 20px;
font-weight: bold;
}
.hdec2-text-sub {
margin: 0;
font-size: 14px;
}
/* ===== ホバー時(:hover) ===== */
/* 親枠にマウスが乗ったら、中の画像を暗くし、少し拡大する */
.hdec2-card:hover .hdec2-img {
filter: brightness(0.5); /* 明るさを50%にして暗転させる */
transform: scale(1.05); /* ほんの少し(1.05倍)ズームさせてリッチに */
}
/* 親枠にマウスが乗ったら、透明にしていたテキストを表示する */
.hdec2-card:hover .hdec2-overlay-text {
opacity: 1; /* 透明度を1(完全表示)にする */
}
.hdec2-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hdec2-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
color: #333;
}画像を回転させる(rotate)
アクセントとして画像を傾けたり、矢印アイコンを時計回りに90度回転させたりするには、CSSのtransformプロパティのrotate()関数を使用します。
角度はdeg(degree:度)という単位で指定します。
例えば、右に90度回転させるならtransform: rotate(90deg);、左に傾けるならtransform: rotate(-5deg);のように記述します。
画像を90度回転させた際に、「画像が隣のテキストや下の要素に被る」といったミスがあります。
CSSのtransformによる変形は、あくまで「見た目だけ」になります。
HTMLのレイアウト上では、画像は回転する前のサイズと形のままその場所に存在していると認識されます。
そのため、長方形の画像を90度回転させると、見た目は縦長になってもブラウザは「まだ横長」と認識するため、上下の要素に被ります。
これを防ぐには、親要素の高さ(余白)を調整するか、回転させた後のサイズに合わせてmargin等を再設定する必要があります。
【transform: rotate(0deg);】
回転していない初期状態です。
HTMLコード表示
<div class="hdec3-wrapper">
<input type="radio" name="hdec3-state" id="hdec3-normal" class="hdec3-radio" checked>
<input type="radio" name="hdec3-state" id="hdec3-tilt" class="hdec3-radio">
<input type="radio" name="hdec3-state" id="hdec3-rotate90" class="hdec3-radio">
<div class="hdec3-controls">
<label for="hdec3-normal" class="hdec3-btn">通常 (0deg)</label>
<label for="hdec3-tilt" class="hdec3-btn">少し傾ける (-10deg)</label>
<label for="hdec3-rotate90" class="hdec3-btn">90度回転 (90deg)</label>
</div>
<div class="hdec3-demo-area">
<div class="hdec3-box">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=200&h=150&q=80" alt="猫" class="hdec3-img target-img-hdec3">
</div>
</div>
<div class="hdec3-explanation">
<p id="desc-normal" class="hdec3-desc">【transform: rotate(0deg);】<br>回転していない初期状態です。</p>
<p id="desc-tilt" class="hdec3-desc" style="display:none; color:#198754; font-weight:bold;">【transform: rotate(-10deg);】<br>マイナスの数値を指定すると、反時計回りに傾きます。ポラロイド写真のような遊び心のあるデザインによく使われます。</p>
<p id="desc-rotate90" class="hdec3-desc" style="display:none; color:#dc3545; font-weight:bold;">【transform: rotate(90deg);】<br>時計回りにカチッと90度回転しました。(※画像が枠からはみ出しそうになっているのは、回転しても「元画像の横幅」のまま計算されているためです)</p>
</div>
</div>CSSコード表示
.hdec3-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hdec3-radio {
display: none;
}
.hdec3-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hdec3-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hdec3-normal:checked ~ .hdec3-controls [for="hdec3-normal"] {
background-color: #6c757d;
color: white;
}
#hdec3-tilt:checked ~ .hdec3-controls [for="hdec3-tilt"] {
background-color: #198754;
color: white;
}
#hdec3-rotate90:checked ~ .hdec3-controls [for="hdec3-rotate90"] {
background-color: #dc3545;
color: white;
}
.hdec3-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 40px 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 250px;
}
.hdec3-box {
text-align: center;
}
.hdec3-img {
width: 200px;
height: 150px;
object-fit: cover;
border: 8px solid #fff; /* 写真風の枠 */
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
/* 回転のアニメーションを滑らかにする */
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
/* 通常 */
#hdec3-normal:checked ~ .hdec3-demo-area .target-img-hdec3 {
transform: rotate(0deg);
}
/* 少し傾ける */
#hdec3-tilt:checked ~ .hdec3-demo-area .target-img-hdec3 {
transform: rotate(-10deg);
}
/* 90度回転 */
#hdec3-rotate90:checked ~ .hdec3-demo-area .target-img-hdec3 {
transform: rotate(90deg);
}
.hdec3-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hdec3-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
}
/* 説明文の切り替え */
#hdec3-normal:checked ~ .hdec3-explanation #desc-normal { display: block !important; }
#hdec3-normal:checked ~ .hdec3-explanation #desc-tilt, #hdec3-normal:checked ~ .hdec3-explanation #desc-rotate90 { display: none !important; }
#hdec3-tilt:checked ~ .hdec3-explanation #desc-tilt { display: block !important; }
#hdec3-tilt:checked ~ .hdec3-explanation #desc-normal, #hdec3-tilt:checked ~ .hdec3-explanation #desc-rotate90 { display: none !important; }
#hdec3-rotate90:checked ~ .hdec3-explanation #desc-rotate90 { display: block !important; }
#hdec3-rotate90:checked ~ .hdec3-explanation #desc-normal, #hdec3-rotate90:checked ~ .hdec3-explanation #desc-tilt { display: none !important; }画像を使ったリンクとボタン化
Webサイト上の画像は別のページへ移動させたり、システムを動かしたりする「操作パネル」としても重要な役割を担います。
バナー画像をクリックしてキャンペーンページに飛ぶ、あるいは送信アイコンをクリックしてフォームのデータを送るなど、画像に操作できる機能を持たせるのは実務で頻出します。
ここでは、画像にリンクを貼る基本と画像をボタンとして扱う実装方法、アクセシビリティ(使いやすさ)の注意点を解説します。
- 画像にリンクを貼る
- 画像をボタンとして使う
画像にリンクを貼る
画像を別のページへのリンクにする方法は、リンクを作成する<a>タグ(アンカータグ)で<img>タグを囲むだけです。
画像をリンクにした際に見落としがちなのがalt属性(代替テキスト)の意味合いの変化です。
単なる画像の場合、altには「画像そのものの説明(例:青い鳥のイラスト)」を書きます。
画像がリンクとして機能する場合、altは「リンク先の目的やアクション(例:Twitterのトップページへ)」を書くのがSEOおよびアクセシビリティの基本です。
また、ユーザーにリンクと直感的に気づかせるため、CSSの:hoverを使って、マウスが乗った時に画像を半透明にするなどエフェクトをつける配慮があるとよいです。
HTMLコード表示
<div class="hlnk1-wrapper">
<input type="radio" name="hlnk1-state" id="hlnk1-normal" class="hlnk1-radio" checked>
<input type="radio" name="hlnk1-state" id="hlnk1-link" class="hlnk1-radio">
<div class="hlnk1-controls">
<label for="hlnk1-normal" class="hlnk1-btn">ただの画像</label>
<label for="hlnk1-link" class="hlnk1-btn">✨ aタグで囲んだ画像リンク</label>
</div>
<div class="hlnk1-demo-area">
<div class="hlnk1-box target-normal-hlnk1">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=300&h=150&q=80" alt="猫の写真" class="hlnk1-img">
<div class="hlnk1-code">
<img src="..." alt="猫の写真">
</div>
<p class="hlnk1-note">※マウスを乗せてもカーソルは矢印のままで、何も起きません。</p>
</div>
<div class="hlnk1-box target-link-hlnk1">
<a href="#dummy" class="hlnk1-img-link" onclick="alert('リンクがクリックされました!'); return false;">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=300&h=150&q=80" alt="猫の特集ページへ移動する" class="hlnk1-img">
</a>
<div class="hlnk1-code hlnk1-code-ok">
<span class="hlnk1-hl"><a href="link.html"></span><br>
<img src="..." alt="猫の特集ページへ"><br>
<span class="hlnk1-hl"></a></span>
</div>
<p class="hlnk1-note hlnk1-note-ok">※マウスを乗せるとカーソルが「指マーク」に変わり、画像が少し透過(薄く)して「押せること」が直感的に伝わります。</p>
</div>
</div>
</div>CSSコード表示
.hlnk1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hlnk1-radio {
display: none;
}
.hlnk1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hlnk1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hlnk1-normal:checked ~ .hlnk1-controls [for="hlnk1-normal"] {
background-color: #6c757d;
color: white;
}
#hlnk1-link:checked ~ .hlnk1-controls [for="hlnk1-link"] {
background-color: #0d6efd;
color: white;
}
.hlnk1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.hlnk1-box {
width: 100%;
max-width: 350px;
text-align: center;
}
.hlnk1-img {
width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
/* ホバー時の変化を滑らかにする */
transition: opacity 0.3s ease;
}
/* リンク要素(aタグ)のスタイル */
.hlnk1-img-link {
display: block; /* 画像の隙間を消すためにブロック化 */
text-decoration: none;
}
/* リンクにマウスが乗った時、中の画像を少し透過させる */
.hlnk1-img-link:hover .hlnk1-img {
opacity: 0.7;
}
.hlnk1-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
margin: 15px 0;
text-align: left;
line-height: 1.5;
}
.hlnk1-code-ok {
border-left: 4px solid #0d6efd;
}
.hlnk1-hl {
color: #61afef;
font-weight: bold;
}
.hlnk1-note {
font-size: 13px;
color: #666;
line-height: 1.5;
margin: 0;
text-align: left;
}
.hlnk1-note-ok {
color: #0d6efd;
font-weight: bold;
}
/* 切り替え */
.target-link-hlnk1 { display: none; }
#hlnk1-normal:checked ~ .hlnk1-demo-area .target-normal-hlnk1 { display: block; }
#hlnk1-normal:checked ~ .hlnk1-demo-area .target-link-hlnk1 { display: none; }
#hlnk1-link:checked ~ .hlnk1-demo-area .target-normal-hlnk1 { display: none; }
#hlnk1-link:checked ~ .hlnk1-demo-area .target-link-hlnk1 { display: block; }<a>タグによるリンクの使い方を詳しく知りたい人は「【html&css】リンク<a>タグの使い方とWebデザインによる装飾」を一読ください。
画像をボタンとして使う
画像を「送信ボタン」や「メニューを開くボタン」として使いたい場合、いくつかの実装方法があります。
<img>にonclickをつける
JSを直接呼び出せます。<button>タグで画像を囲む
Web制作において推奨されるアクセシビリティの高い手法です。<input type="image">を使う
フォームの送信ボタン(submit)として画像を代用する古いHTML仕様です。
JavaScriptを覚えたてによくやるのが<img src="..." onclick="処理">と書いて済ませることです。
これをやると、マウスを乗せてもカーソルが「指マーク」にならないため、ユーザーは押せるボタンだと気づきません。
これを防ぐには、CSSでcursor: pointer;を指定してカーソルを指マークに変える必要があります。
しかし、カーソルを変えても、画像では「キーボードのTabキーで選択できない」「スクリーンリーダーにボタンだと伝わらない」というアクセシビリティの問題が残ります。
実務では画像を<button>タグで囲み、CSSで<button>のデフォルトの枠線や背景を透明にして見えなくするのがよいです。
※JSは動きますが、マウスを乗せても矢印カーソルのままなので、ユーザーは「押せる」と気づけません。
※カーソルが指マークに変わり見た目はOKですが、キーボード操作ができないためアクセシビリティが低いです。
<img src=”…” alt=”送信”>
</button>
※buttonタグを透明にして画像を包むことで、キーボード操作も可能な完璧なボタン画像になります。
HTMLコード表示
<div class="hbtn1-wrapper">
<input type="radio" name="hbtn1-state" id="hbtn1-bad" class="hbtn1-radio" checked>
<input type="radio" name="hbtn1-state" id="hbtn1-pointer" class="hbtn1-radio">
<input type="radio" name="hbtn1-state" id="hbtn1-best" class="hbtn1-radio">
<div class="hbtn1-controls">
<label for="hbtn1-bad" class="hbtn1-btn">❌ onclickのみ (カーソル変わらず)</label>
<label for="hbtn1-pointer" class="hbtn1-btn">⚠️ + cursor:pointer (見た目だけ改善)</label>
<label for="hbtn1-best" class="hbtn1-btn">⭕️ buttonタグで囲む (実務の正解)</label>
</div>
<div class="hbtn1-demo-area">
<div class="hbtn1-box target-bad-hbtn1">
<img src="https://placehold.co/150x50/dc3545/fff?text=Submit" alt="送信" class="hbtn1-img" onclick="alert('クリックされました!')">
<p class="hbtn1-note">※JSは動きますが、マウスを乗せても矢印カーソルのままなので、ユーザーは「押せる」と気づけません。</p>
</div>
<div class="hbtn1-box target-pointer-hbtn1">
<img src="https://placehold.co/150x50/fd7e14/fff?text=Submit" alt="送信" class="hbtn1-img hbtn1-cursor-pointer" onclick="alert('クリックされました!')">
<p class="hbtn1-note">※カーソルが指マークに変わり見た目はOKですが、キーボード操作ができないためアクセシビリティが低いです。</p>
</div>
<div class="hbtn1-box target-best-hbtn1">
<button type="button" class="hbtn1-clean-button" onclick="alert('クリックされました!')">
<img src="https://placehold.co/150x50/198754/fff?text=Submit" alt="送信" class="hbtn1-img">
</button>
<div class="hbtn1-code">
<button type="button" class="clean-btn"><br>
<img src="..." alt="送信"><br>
</button>
</div>
<p class="hbtn1-note hbtn1-note-ok">※buttonタグを透明にして画像を包むことで、キーボード操作も可能な完璧なボタン画像になります。</p>
</div>
</div>
</div>CSSコード表示
.hbtn1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hbtn1-radio {
display: none;
}
.hbtn1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hbtn1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hbtn1-bad:checked ~ .hbtn1-controls [for="hbtn1-bad"] { background-color: #dc3545; color: white; }
#hbtn1-pointer:checked ~ .hbtn1-controls [for="hbtn1-pointer"] { background-color: #fd7e14; color: white; }
#hbtn1-best:checked ~ .hbtn1-controls [for="hbtn1-best"] { background-color: #198754; color: white; }
.hbtn1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.hbtn1-box {
width: 100%;
max-width: 400px;
text-align: center;
}
.hbtn1-img {
width: 150px;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
transition: opacity 0.2s ease;
}
/* ⚠️ 見た目だけ改善 */
.hbtn1-cursor-pointer {
cursor: pointer; /* これで指マークになる */
}
.hbtn1-cursor-pointer:hover {
opacity: 0.8;
}
/* ⭕️ 実務の正解(buttonタグの装飾を剥がす) */
.hbtn1-clean-button {
background: transparent; /* 背景を透明に */
border: none; /* 枠線を消す */
padding: 0; /* 内側の余白を消す */
margin: 0;
cursor: pointer; /* 指マークにする */
outline: none;
}
.hbtn1-clean-button:hover .hbtn1-img {
opacity: 0.8;
}
/* キーボードのTabキーで選択された時だけ枠線を出す配慮 */
.hbtn1-clean-button:focus-visible {
outline: 3px solid #0d6efd;
border-radius: 4px;
}
.hbtn1-code {
background-color: #f1f3f5;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
margin: 15px 0;
text-align: left;
color: #333;
}
.hbtn1-note {
font-size: 13px;
color: #dc3545;
line-height: 1.5;
margin: 15px 0 0 0;
text-align: left;
font-weight: bold;
}
.hbtn1-note-ok {
color: #198754;
}
/* 切り替え */
.target-pointer-hbtn1, .target-best-hbtn1 { display: none; }
#hbtn1-bad:checked ~ .hbtn1-demo-area .target-bad-hbtn1 { display: block; }
#hbtn1-bad:checked ~ .hbtn1-demo-area .target-pointer-hbtn1 { display: none; }
#hbtn1-bad:checked ~ .hbtn1-demo-area .target-best-hbtn1 { display: none; }
#hbtn1-pointer:checked ~ .hbtn1-demo-area .target-bad-hbtn1 { display: none; }
#hbtn1-pointer:checked ~ .hbtn1-demo-area .target-pointer-hbtn1 { display: block; }
#hbtn1-pointer:checked ~ .hbtn1-demo-area .target-best-hbtn1 { display: none; }
#hbtn1-best:checked ~ .hbtn1-demo-area .target-bad-hbtn1 { display: none; }
#hbtn1-best:checked ~ .hbtn1-demo-area .target-pointer-hbtn1 { display: none; }
#hbtn1-best:checked ~ .hbtn1-demo-area .target-best-hbtn1 { display: block; }<button>タグによるボタンの使い方を詳しく知りたい人は「【HTML】buttonタグの使い方:リンク・CSS装飾・無効化」を一読ください。
表示速度の改善と高度な読み込み設定
Webサイトの表示速度は、ユーザー体験(UX)やSEO(検索順位)に直結する重要な要素です。
そして、Webページを重くしている原因は「画像」の読み込みです。
HTMLには、画像の読み込みタイミングや優先度をブラウザに指示する設定が用意されています。
ここでは、遅延読み込み、画像を直接HTMLに埋め込む手法、高度な<picture>タグの使い分けを解説します。
- 遅延読み込みと優先度
- Base64エンコードによる画像の直接埋め込み
<picture>タグとの違いと使い分け
遅延読み込みと優先度
スクロールしないと見えない位置にある画像をギリギリまで読み込ませないようにする属性がloading="lazy"です。
これを指定するだけで初期表示の通信がカットされ、表示速度が速くなります。
逆に、初期表示で読み込みたい場合はloading="eager"を指定します。
さらに、「この画像はページの中で一番重要だから最優先で読み込みたい。」とブラウザに指示を出すfetchpriority="high"という属性も実務で多用されます。
(※JavaScriptの読み込みを遅らせる属性としてdeferがありますが、画像に対してdeferという属性は存在しません。画像にはloading属性を使います。)
「ページを速くしたいから」と全ての<img>タグにloading="lazy"をつけるミスがあります。
これをやると、ページを開いて最初に目に入る一番上の画像まで読み込みが後回しにされ、結果「ユーザーから見て画面の完成が遅い」と判断され、Googleの評価指標が落ちします。
画面の最初に見える画像にはfetchpriority="high"(またはeager)、スクロールして見える画像には loading="lazy"という使い分けがよいです。
💻 パソコンの画面(最初に見える領域)
<img src=”hero.jpg” loading=”lazy”>
⬇️ スクロールした先の領域
<img src=”thumb.jpg” loading=”lazy”>
※ページを開いた瞬間に必要なメイン画像まで後回しにされるため、画面が真っ白な時間が長くなりSEO評価が下がります。
💻 パソコンの画面(最初に見える領域)
<img src=”hero.jpg” fetchpriority=”high”>
⬇️ スクロールした先の領域
<img src=”thumb.jpg” loading=”lazy”>
※最初の画像を超高速で表示しつつ、見えない画像は後回しにして通信を節約する、完璧なパフォーマンス設定です。
HTMLコード表示
<div class="hlod1-wrapper">
<input type="radio" name="hlod1-state" id="hlod1-bad" class="hlod1-radio" checked>
<input type="radio" name="hlod1-state" id="hlod1-good" class="hlod1-radio">
<div class="hlod1-controls">
<label for="hlod1-bad" class="hlod1-btn">❌ 全てにlazy (表示が遅れる罠)</label>
<label for="hlod1-good" class="hlod1-btn">⭕️ 正しい優先度の設定 (最速表示)</label>
</div>
<div class="hlod1-demo-area">
<div class="hlod1-box target-bad-hlod1">
<div class="hlod1-v-screen">
<p class="hlod1-v-label">💻 パソコンの画面(最初に見える領域)</p>
<div class="hlod1-code-block hlod1-code-error">
<!-- メインビジュアル --><br>
<img src="hero.jpg" <span class="hlod1-hl-red">loading="lazy"</span>>
</div>
</div>
<div class="hlod1-v-scroll">
<p class="hlod1-v-label">⬇️ スクロールした先の領域</p>
<div class="hlod1-code-block hlod1-code-error">
<!-- 記事のサムネイル --><br>
<img src="thumb.jpg" <span class="hlod1-hl-red">loading="lazy"</span>>
</div>
</div>
<p class="hlod1-note">※ページを開いた瞬間に必要なメイン画像まで後回しにされるため、画面が真っ白な時間が長くなりSEO評価が下がります。</p>
</div>
<div class="hlod1-box target-good-hlod1">
<div class="hlod1-v-screen">
<p class="hlod1-v-label">💻 パソコンの画面(最初に見える領域)</p>
<div class="hlod1-code-block hlod1-code-success">
<!-- メインビジュアルは最優先! --><br>
<img src="hero.jpg" <span class="hlod1-hl-green">fetchpriority="high"</span>>
</div>
</div>
<div class="hlod1-v-scroll">
<p class="hlod1-v-label">⬇️ スクロールした先の領域</p>
<div class="hlod1-code-block hlod1-code-success">
<!-- 見えない画像は遅延させる --><br>
<img src="thumb.jpg" <span class="hlod1-hl-green">loading="lazy"</span>>
</div>
</div>
<p class="hlod1-note hlod1-note-ok">※最初の画像を超高速で表示しつつ、見えない画像は後回しにして通信を節約する、完璧なパフォーマンス設定です。</p>
</div>
</div>
</div>CSSコード表示
.hlod1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hlod1-radio {
display: none;
}
.hlod1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hlod1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hlod1-bad:checked ~ .hlod1-controls [for="hlod1-bad"] {
background-color: #dc3545;
color: white;
}
#hlod1-good:checked ~ .hlod1-controls [for="hlod1-good"] {
background-color: #198754;
color: white;
}
.hlod1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
display: flex;
justify-content: center;
}
.hlod1-box {
width: 100%;
max-width: 450px;
}
.hlod1-v-screen {
border: 3px solid #333;
border-radius: 8px 8px 0 0;
padding: 15px;
background-color: #e7f1ff;
margin-bottom: 0;
position: relative;
}
.hlod1-v-scroll {
border: 3px dashed #ccc;
border-top: none;
padding: 15px;
background-color: #f8f9fa;
border-radius: 0 0 8px 8px;
margin-bottom: 15px;
}
.hlod1-v-label {
font-size: 13px;
font-weight: bold;
margin: 0 0 10px 0;
color: #333;
}
.hlod1-code-block {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
line-height: 1.5;
}
.hlod1-code-error {
border-left: 4px solid #e06c75;
}
.hlod1-code-success {
border-left: 4px solid #98c379;
}
.hlod1-hl-red {
color: #e06c75;
font-weight: bold;
}
.hlod1-hl-green {
color: #98c379;
font-weight: bold;
}
.hlod1-note {
font-size: 13px;
color: #dc3545;
font-weight: bold;
line-height: 1.5;
margin: 0;
}
.hlod1-note-ok {
color: #198754;
}
.target-good-hlod1 {
display: none;
}
#hlod1-bad:checked ~ .hlod1-demo-area .target-bad-hlod1 {
display: block;
}
#hlod1-good:checked ~ .hlod1-demo-area .target-bad-hlod1 {
display: none;
}
#hlod1-good:checked ~ .hlod1-demo-area .target-good-hlod1 {
display: block;
}Base64エンコードによる画像の直接埋め込み
通常、画像を表示するには画像ファイル(.jpg等)をサーバーに置いて、URLをsrcに記述します。
しかし、異なるアプローチとして、画像データを文字列(テキスト)に変換し、HTMLのsrc属性に直接書き込む技術が存在します。
これがBase64エンコードです。
画像ファイルの読み込みリクエストをゼロにできるため、アイコンなどの小さな画像を高速に表示したい場合に重宝されます。
「通信回数が減るなら、Base64にすれば速いのでは?」と思ってしまいますが、写真などの画像をBase64化してしまうのは典型的なアンチパターンです。
画像をBase64文字列に変換すると、ファイル容量よりデータサイズが約1.3倍に膨れ上がります。
写真を埋め込むとHTMLファイル自体が数MB〜数十MBというサイズになり、ページ全体がフリーズしたように重くなります。
また、ブラウザの「画像キャッシュ(一時保存)」も効かなくなります。
「Base64を使うのは、数KBの極小アイコン画像やローディング画像のみに限定する」のがよいです。
<img src=”images/icon-arrow.svg” alt=”アイコン”>
<img src=”data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…(中略:何千文字も続く謎の文字列)…QmCC” alt=”アイコン”>
HTMLコード表示
<div class="hlod2-wrapper">
<input type="radio" name="hlod2-state" id="hlod2-normal" class="hlod2-radio" checked>
<input type="radio" name="hlod2-state" id="hlod2-base64" class="hlod2-radio">
<div class="hlod2-controls">
<label for="hlod2-normal" class="hlod2-btn">通常 (別ファイル読み込み)</label>
<label for="hlod2-base64" class="hlod2-btn">Base64 (HTMLに直接埋め込み)</label>
</div>
<div class="hlod2-demo-area">
<div class="hlod2-box target-normal-hlod2">
<div class="hlod2-img-container">
<img src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'></circle><polyline points='12 16 16 12 12 8'></polyline><line x1='8' y1='12' x2='16' y2='12'></line></svg>" alt="アイコン" class="hlod2-img">
</div>
<div class="hlod2-code">
<!-- 外部ファイルを取得する通信が1回発生する --><br>
<img src="<span class="hlod2-hl-blue">images/icon-arrow.svg</span>" alt="アイコン">
</div>
</div>
<div class="hlod2-box target-base64-hlod2">
<div class="hlod2-img-container">
<img src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'></circle><polyline points='12 16 16 12 12 8'></polyline><line x1='8' y1='12' x2='16' y2='12'></line></svg>" alt="アイコン" class="hlod2-img">
</div>
<div class="hlod2-code hlod2-code-long">
<!-- HTMLの中に画像データが文字として存在(通信0回) --><br>
<img src="<span class="hlod2-hl-orange">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...(中略:何千文字も続く謎の文字列)...QmCC</span>" alt="アイコン">
</div>
</div>
</div>
</div>CSSコード表示
.hlod2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hlod2-radio {
display: none;
}
.hlod2-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.hlod2-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#hlod2-normal:checked ~ .hlod2-controls [for="hlod2-normal"] {
background-color: #0d6efd;
color: white;
}
#hlod2-base64:checked ~ .hlod2-controls [for="hlod2-base64"] {
background-color: #fd7e14;
color: white;
}
.hlod2-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
display: flex;
justify-content: center;
}
.hlod2-box {
width: 100%;
max-width: 500px;
text-align: center;
}
.hlod2-img-container {
margin-bottom: 15px;
}
.hlod2-img {
width: 40px;
height: 40px;
}
.hlod2-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
text-align: left;
line-height: 1.6;
word-break: break-all;
}
.hlod2-hl-blue {
color: #61afef;
font-weight: bold;
}
.hlod2-hl-orange {
color: #d19a66;
font-weight: bold;
word-break: break-all;
}
.target-base64-hlod2 {
display: none;
}
#hlod2-normal:checked ~ .hlod2-demo-area .target-normal-hlod2 {
display: block;
}
#hlod2-normal:checked ~ .hlod2-demo-area .target-base64-hlod2 {
display: none;
}
#hlod2-base64:checked ~ .hlod2-demo-area .target-normal-hlod2 {
display: none;
}
#hlod2-base64:checked ~ .hlod2-demo-area .target-base64-hlod2 {
display: block;
}<picture>タグとの違いと使い分け
レスポンシブデザインにおいて、スマホとPCで「表示する画像を切り替えたい」という要望は発生します。
この時、<img>タグのsrcset属性を使うべきか、<picture>タグを使うべきか迷います。
実務における使い分けのルールは以下の通りです。
<img>のsrcsetを使う場合
画像の内容は同じで、「スマホ用に解像度の低い画像、PC用に解像度の高い画像」を出し分けたい場合に使用します。
どちらの画像を読み込むかは、ブラウザが通信環境や画面幅を見て自動的に判断します。<picture>タグを使う場合
スマホの時は縦長の専用写真、PCの時は横長の専用写真というように、構図を切り替える「アートディレクション」を行いたい場合に使用します。
また、「次世代フォーマットに対応しているブラウザにはWebP、非対応のブラウザにはJPGを表示する」といった高度な出し分けにも使用します。
レスポンシブ=<picture>と思い込み、同じ構図の画像なのに<picture>を使って複雑なコードを書くことがあります。
<picture>は「強制的にこの画像を読む」とブラウザに指示を出すため、ブラウザ側の最適化を阻害します。
トリミングや構図が変わるなら<picture>、サイズが変わるだけなら<img>のsrcsetと覚えておきましょう。
上のボタンを押して枠の幅を変えてみてください。
単に画像が縮小されるのではなく、「スマホ用の縦長の写真」と「PC用の横長の写真」が完全に切り替わります。
本来、<picture> はブラウザの画面幅(ビューポート)に基づいて切り替えますが、このデモではCSSのコンテナクエリを使って、親の枠(点線)の幅に基づいて疑似的に再現しています。
HTMLコード表示
<div class="hlod3-wrapper">
<div class="hlod3-resize-controls">
画面の幅:
<button type="button" class="hlod3-resize-btn hlod3-btn-mobile" onclick="document.getElementById('demo-pic-box').style.width = '200px'">狭い (スマホ相当)</button>
<button type="button" class="hlod3-resize-btn hlod3-btn-pc" onclick="document.getElementById('demo-pic-box').style.width = '100%'">広い (PC相当)</button>
</div>
<div class="hlod3-demo-area">
<div id="demo-pic-box" class="hlod3-parent-box">
<div class="hlod3-label">親要素の幅を基準にシミュレート</div>
<div class="hlod3-img-container">
<img src="https://images.unsplash.com/photo-1592194996308-7b43878e84a6?auto=format&fit=crop&w=200&h=400&q=80" alt="猫の写真" class="hlod3-img">
</div>
</div>
</div>
<div class="hlod3-explanation">
<p class="hlod3-desc">
上のボタンを押して枠の幅を変えてみてください。<br>
単に画像が縮小されるのではなく、<strong>「スマホ用の縦長の写真」と「PC用の横長の写真」が完全に切り替わります。</strong><br>
本来、<code><picture></code> はブラウザの画面幅(ビューポート)に基づいて切り替えますが、このデモではCSSのコンテナクエリを使って、親の枠(点線)の幅に基づいて疑似的に再現しています。
</p>
</div>
</div>CSSコード表示
.hlod3-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.hlod3-resize-controls {
text-align: center;
margin-bottom: 20px;
font-size: 14px;
font-weight: bold;
color: #333;
}
.hlod3-resize-btn {
border: none;
padding: 8px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
font-weight: bold;
color: white;
margin: 0 5px;
transition: 0.2s;
}
.hlod3-btn-mobile {
background-color: #fd7e14;
}
.hlod3-btn-pc {
background-color: #0d6efd;
}
.hlod3-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 20px;
display: flex;
justify-content: center;
min-height: 450px;
box-sizing: border-box;
}
.hlod3-parent-box {
width: 100%; /* 初期はPCサイズ */
background-color: #e9ecef;
border: 2px solid #ccc;
padding: 10px;
box-sizing: border-box;
text-align: center;
transition: width 0.4s ease; /* 幅変更のアニメーション */
/* この要素の幅を基準にして、中の要素(画像)のCSSを切り替える */
container-type: inline-size;
}
.hlod3-label {
font-size: 12px;
color: #666;
margin-bottom: 10px;
font-weight: bold;
}
.hlod3-img-container {
display: flex;
justify-content: center;
}
/* 画像の基本スタイル(スマホ用の縦長) */
.hlod3-img {
max-width: 100%;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
display: block;
}
@container (min-width: 400px) {
.hlod3-parent-box .hlod3-img {
/* PC用の横長画像に `src` を差し替える */
content: url("https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?auto=format&fit=crop&w=600&h=200&q=80");
}
}
.hlod3-explanation {
background-color: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 4px;
margin-top: 15px;
}
.hlod3-desc {
margin: 0;
font-size: 14px;
line-height: 1.6;
color: #333;
}
.hlod3-desc code {
background-color: #f1f3f5;
padding: 2px 6px;
border-radius: 4px;
color: #d63384;
font-weight: bold;
}<picture>タグの使い方を詳しく知りたい人は「【HTML】pictureタグの使い方:imgとの違い・レスポンシブ対応」を一読ください。
画像が表示されない:原因と対策
「設定した画像が表示されない。」というトラブルがあります。
画面上に壊れた画像アイコン(リンク切れ)が表示される現象は、ユーザーに不信感を与え、サイトの離脱率を上げるエラーになります。
ここでは、画像が表示されない原因であるパス間違いの確認方法と万が一エラーが起きた際に「No Image」などの代わりの画像を表示させる対策を解説します。
- パス間違いや404エラーの確認
- エラー時の代替画像表示
パス間違いや404エラーの確認
画像が表示されない原因は、「画像のパス(場所)の指定間違い」による404エラーです。
以下のポイントを確認してください。
- 階層(フォルダ)の指定ミス
一つ上の階層に戻る../の数が足りない、または多すぎる。 - 拡張子の間違い
.jpg、.jpeg、.png、.webpなど、実際のファイル名とコードの記述が一致していない。 - 余計なスペースの混入
ファイル名やフォルダ名に半角・全角のスペースが混ざっている。
例えば、自分のPC(ローカル環境)で画像が表示されたが、本番のサーバーにアップロードしたら表示されなくなったというミスです。
WindowsやMacのパソコンはファイル名の大文字・小文字を区別しないため、コードにPhoto.jpgと書いて実際のファイルがphoto.jpgでも表示されます。
しかし、Webサーバーの多くは大文字と小文字を別のファイルとして区別します。
これを防ぐため、実務では「画像ファイル名は小文字の半角英数字で統一する」というルールが存在します。
※指定したファイル名と実際のファイル名が完全に一致しているため、正しく表示されます。
<img src=”cat.png” alt=”猫”>
※「.jpg」と「.png」など、拡張子が1文字でも違うとブラウザは画像を見つけられずリンク切れになります。
<img src=”Cat.jpg” alt=”猫”>
※パソコンのフォルダ内では表示されても、サーバー上では「cat」と「Cat」は別物と判断されてエラーになります。
HTMLコード表示
<div class="herr1-wrapper">
<input type="radio" name="herr1-state" id="herr1-good" class="herr1-radio" checked>
<input type="radio" name="herr1-state" id="herr1-ext" class="herr1-radio">
<input type="radio" name="herr1-state" id="herr1-case" class="herr1-radio">
<div class="herr1-controls">
<label for="herr1-good" class="herr1-btn">⭕️ 正しい指定 (表示される)</label>
<label for="herr1-ext" class="herr1-btn">❌ 拡張子ミス (.png / .jpg)</label>
<label for="herr1-case" class="herr1-btn">❌ 大文字・小文字の混同</label>
</div>
<div class="herr1-demo-area">
<div class="herr1-box target-good-herr1">
<div class="herr1-code">
<img src="<span class="herr1-hl-ok">cat.jpg</span>" alt="猫">
</div>
<div class="herr1-img-container">
<img src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?auto=format&fit=crop&w=300&h=200&q=80" alt="猫の画像(正常)" class="herr1-img">
</div>
<p class="herr1-note herr1-note-ok">※指定したファイル名と実際のファイル名が完全に一致しているため、正しく表示されます。</p>
</div>
<div class="herr1-box target-ext-herr1">
<div class="herr1-code herr1-code-bad">
<!-- 実際のファイルは .jpg なのに .png と書いた --><br>
<img src="cat.<span class="herr1-hl-error">png</span>" alt="猫">
</div>
<div class="herr1-img-container herr1-error-container">
<img src="https://placehold.co/invalid-extension.png" alt="猫の画像(拡張子ミスで表示不可)" class="herr1-img">
</div>
<p class="herr1-note">※「.jpg」と「.png」など、拡張子が1文字でも違うとブラウザは画像を見つけられずリンク切れになります。</p>
</div>
<div class="herr1-box target-case-herr1">
<div class="herr1-code herr1-code-bad">
<!-- 実際のファイルは cat.jpg なのに 大文字が混ざっている --><br>
<img src="<span class="herr1-hl-error">Cat</span>.jpg" alt="猫">
</div>
<div class="herr1-img-container herr1-error-container">
<img src="https://placehold.co/invalid-case-Cat.jpg" alt="猫の画像(大文字小文字違いで表示不可)" class="herr1-img">
</div>
<p class="herr1-note">※パソコンのフォルダ内では表示されても、サーバー上では「cat」と「Cat」は別物と判断されてエラーになります。</p>
</div>
</div>
</div>CSSコード表示
.herr1-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.herr1-radio {
display: none;
}
.herr1-controls {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.herr1-btn {
background-color: #e9ecef;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
color: #495057;
transition: 0.2s;
font-size: 14px;
}
#herr1-good:checked ~ .herr1-controls [for="herr1-good"] {
background-color: #198754;
color: white;
}
#herr1-ext:checked ~ .herr1-controls [for="herr1-ext"],
#herr1-case:checked ~ .herr1-controls [for="herr1-case"] {
background-color: #dc3545;
color: white;
}
.herr1-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.herr1-box {
width: 100%;
max-width: 400px;
text-align: center;
}
.herr1-code {
background-color: #d1e7dd;
color: #0f5132;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
border-left: 4px solid #198754;
margin-bottom: 15px;
text-align: left;
line-height: 1.5;
}
.herr1-code-bad {
background-color: #f8d7da;
color: #842029;
border-left-color: #dc3545;
}
.herr1-hl-ok { font-weight: bold; }
.herr1-hl-error { font-weight: bold; text-decoration: underline; color: #dc3545; }
.herr1-img-container {
background-color: #f1f3f5;
padding: 20px;
border: 1px solid #ccc;
border-radius: 4px;
min-height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
.herr1-error-container {
background-color: #f8d7da; /* エラー時は背景を赤っぽくして目立たせる */
border-color: #dc3545;
}
.herr1-img {
max-width: 100%;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.herr1-note {
font-size: 13px;
color: #dc3545;
font-weight: bold;
line-height: 1.5;
margin: 15px 0 0 0;
text-align: left;
}
.herr1-note-ok {
color: #198754;
}
/* 切り替え */
.target-ext-herr1, .target-case-herr1 { display: none; }
#herr1-good:checked ~ .herr1-demo-area .target-good-herr1 { display: block; }
#herr1-good:checked ~ .herr1-demo-area .target-ext-herr1 { display: none; }
#herr1-good:checked ~ .herr1-demo-area .target-case-herr1 { display: none; }
#herr1-ext:checked ~ .herr1-demo-area .target-good-herr1 { display: none; }
#herr1-ext:checked ~ .herr1-demo-area .target-ext-herr1 { display: block; }
#herr1-ext:checked ~ .herr1-demo-area .target-case-herr1 { display: none; }
#herr1-case:checked ~ .herr1-demo-area .target-good-herr1 { display: none; }
#herr1-case:checked ~ .herr1-demo-area .target-ext-herr1 { display: none; }
#herr1-case:checked ~ .herr1-demo-area .target-case-herr1 { display: block; }エラー時の代替画像表示
他サイト画像を引用して元サイトから画像が消されたり、アップロードのミスで画像が欠損したりすることは起こり得ます。
もし画像がリンク切れを起こした場合、通常はブラウザ標準の「壊れたアイコン」が表示されます。
これを防ぎ、予め用意した「No Image」などの代わりの画像を表示させるのがonerror属性を使った方法です。
実務で気をつけてほしいのが代替画像のパスが間違っていたり、代替画像も消えてしまった場合です。
onerror="this.src='no-image.jpg'"と記述した場合、no-image.jpgもエラーになると無限ループに陥り、ブラウザがフリーズしたり画面が点滅したりするバグに発展します。
これを防ぐため、実務ではonerrorの処理の中でthis.onerror=null;をセットで記述します。
onerror=”this.onerror=null; this.src=’no-image.jpg’;”>
※上のボタンを押すと意図的にリンク切れ(エラー)を起こします。その瞬間、onerrorが発動して「No Image」画像に切り替わる様子を確認してください。
HTMLコード表示
<div class="herr2-wrapper">
<div class="herr2-controls">
<button type="button" class="herr2-btn" onclick="triggerErrorDemo()">🔄 画像エラーを発生させる</button>
</div>
<div class="herr2-demo-area">
<div class="herr2-box">
<div class="herr2-label">ユーザーに見える画面</div>
<div class="herr2-img-container">
<img id="demo-fallback-img"
src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?auto=format&fit=crop&w=300&h=200&q=80"
alt="コンテンツ画像"
class="herr2-img"
onerror="this.onerror=null; this.src='https://placehold.co/300x200/dee2e6/6c757d?text=No+Image'; alert('エラーを検知!No Imageに差し替えました。');">
</div>
<div class="herr2-code">
<img src="<span id="demo-src-text" class="herr2-hl-src">cat.jpg</span>"<br>
<span class="herr2-hl-js">onerror="this.onerror=null; this.src='no-image.jpg';"</span>>
</div>
<p class="herr2-note">※上のボタンを押すと意図的にリンク切れ(エラー)を起こします。その瞬間、onerrorが発動して「No Image」画像に切り替わる様子を確認してください。</p>
</div>
</div>
</div>CSSコード表示
.herr2-wrapper {
background-color: #f8f9fa;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 4px;
font-family: sans-serif;
}
.herr2-controls {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.herr2-btn {
background-color: #dc3545;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
font-size: 15px;
transition: 0.2s;
box-shadow: 0 4px 6px rgba(220,53,69,0.2);
}
.herr2-btn:hover {
background-color: #bb2d3b;
transform: translateY(-2px);
}
.herr2-demo-area {
background-color: #ffffff;
border: 2px dashed #adb5bd;
padding: 30px 20px;
display: flex;
justify-content: center;
}
.herr2-box {
width: 100%;
max-width: 400px;
text-align: center;
}
.herr2-label {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
background-color: #e9ecef;
padding: 8px;
border-radius: 4px;
}
.herr2-img-container {
margin-bottom: 15px;
min-height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
.herr2-img {
max-width: 100%;
height: auto;
border-radius: 4px;
border: 1px solid #dee2e6;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.herr2-code {
background-color: #282c34;
color: #abb2bf;
padding: 15px;
font-family: monospace;
font-size: 13px;
border-radius: 4px;
text-align: left;
line-height: 1.6;
}
.herr2-hl-src {
color: #98c379;
font-weight: bold;
transition: color 0.3s ease;
}
.herr2-hl-src.error {
color: #e06c75;
}
.herr2-hl-js {
color: #e5c07b;
font-weight: bold;
}
.herr2-note {
font-size: 13px;
color: #666;
line-height: 1.5;
margin: 15px 0 0 0;
text-align: left;
}JavaScriptコード表示
function triggerErrorDemo() {
const imgElement = document.getElementById('demo-fallback-img');
const srcTextElement = document.getElementById('demo-src-text');
// わざと存在しない壊れたURLに書き換えてエラーを誘発する
imgElement.src = 'https://example.com/not-exist-image-force-error.jpg';
// コードの見た目もエラー状態に変更
srcTextElement.textContent = 'broken-image.jpg';
srcTextElement.classList.add('error');
}まとめ
分かりやすいようにまとめを記載します。
- 必須属性
画像のパスを指定するsrcと代替テキストになるaltは記述する。 - パスの指定
画像が表示されない原因は、階層の間違いや大文字・小文字、拡張子の記述ミスによるリンク切れ(404エラー)である。 - サイズと比率
画像が潰れるのを防ぐため、widthかheightの片方をautoにする。
枠に収めて切り抜く場合はobject-fit: cover;を使用する。 - レスポンシブ対応
スマホなどで画像を画面幅に合わせる際は、画質劣化を防ぐためにwidth: 100%;ではなくmax-width: 100%;を指定する。 - 配置とレイアウト
画像を中央に寄せるにはdisplay: block;とmargin: 0 auto;をセットで指定する。 - 画像下の隙間
インライン要素の画像下の隙間は、display: block;かvertical-align: bottom;で解消する。 - 装飾テクニック
border-radius: 50%;で正円を作る際は、事前に画像を正方形にしておく必要がある。 - リンクとボタン化
リンクにする場合は<a>タグ、ボタンとして扱う場合は<button>タグで画像を囲むのがアクセシビリティの鉄則。 - 読み込み最適化
ファーストビューの画像はfetchpriority="high"、スクロールして見える画像はloading="lazy"を指定して表示速度を上げる。 - アートディレクション
画面幅によって違う構図の画像を出し分ける場合は、<img>ではなく<picture>タグを使用する。 - エラー時の代替画像
リンク切れ時にonerror属性で「No Image」画像を表示させる際、無限ループを防ぐためthis.onerror=null;を併記する。
よくある質問(FAQ)
HTMLで画像を中央に寄せるにはどうすればいいですか?
画像(<img>タグ)は文字と同じ「インライン要素」扱いになるため、そのままでは中央に寄りません。
確実な方法は、CSSで画像にdisplay: block;を指定してブロック(箱)に変更した上でmargin: 0 auto; を指定することです。
または、画像を囲んでいる親要素(<div>や<p>など)に対してtext-align: center;を指定することでも中央寄せが可能です。
画像が表示されず、リンク切れのアイコンになるのはなぜですか?
原因は画像のパス(保存場所)やファイル名の指定間違いです。
初心者が陥りやすいのが拡張子の間違い(.jpgと.pngの違いなど)や大文字・小文字の混同です。
サーバー上では「Photo.jpg」と「photo.jpg」は別のファイルとして区別されるため、ファイル名は小文字で統一し、パスが正しく指定されているか見直してください。
スマホで見ても画像がはみ出さないように(レスポンシブに)するには?
CSSで画像に対してmax-width: 100%;とheight: auto;をセットで指定するのがよいです。
width: 100%;だと小さな画像が画面幅に引き伸ばされて画質が粗くなりますが、max-width: 100%;であれば親の枠より大きくならないため、サイズと画質を保ちスマホ画面の時でも縮小してくれます。
imgタグのalt属性とは何ですか?
alt属性は、画像が表示されなかった時の代替テキストであり、記述する必要があります。
視覚障害者の方が使う音声読み上げソフトで読み上げられる他、Googleの検索エンジンに何の画像かを伝えるSEOの役割を持ちます。
ただし、単なる区切り線や背景のあしらいなど意味を持たない装飾用の画像の場合、読み上げの邪魔にならないようalt=""と中身を空にして記述してください。
画像をクリックしたら別のページに飛ぶにはどう書きますか?
リンクを作成する<a>タグで<img>タグを囲むだけで画像リンクになります。
<a href="飛ばしたいURL"><img src="画像パス" alt="リンク先の説明"></a>画像がリンクとして機能する場合alt 属性には「画像そのものの説明」ではなく、「クリックした後に何が起きるか」というリンク先の目的を記述するのがよいです。

