15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CSSでheight:100%指定したimg、Safariで見ると画像がボックスをはみ出ていた意外な原因

Posted at

テキストを画像化してimg要素としてdivに配置し、iPhoneやデスクトップ版のSafariで表示したら、なんだか画像のサイズがおかしい。CSSに指定したheightの寸法よりも大きく見える。インスペクタで要素の高さを確認したところ、問題のimg要素だけheightの計算値がおかしい!こんな現象にハマりました。発生条件が判ったのでメモ。

動作環境
macOS 10.14 (Mojave), Safari 13.1

現象

要素div.tabに固定のheightと上下にpaddingを持たせ、子要素としてimg要素をheight: 100%で埋め込みます(下図)。図で「LOREM IPSUM」はテキストを画像化したものです。デスクトップ版のChromeやFirefoxでは、上側のようにLOREM IPSUM画像がdiv.tabのコンテンツボックスにぴったり収まって表示されますが、Safariで表示すると、ある条件で画像がコンテンツボックスをはみ出してしまいます。
fig1_w500.png

サンプルのコード

下記サンプルでは、テキストを画像化したファイルlabel.pngを2つの方法で親要素div.tab 内に表示しています。最初のdiv.tab は、img要素の高さをheight: 100%で指定したもの。2つ目のdiv.tabは、img要素の高さをピクセル値で直接指定したものです。

html
<div class="sample">
  <div class="tab"><img src="img/label.png" alt=""></div>
</div>
<div class="sample">
  <div class="tab px"><img src="img/label.png" alt=""></div>
</div>
css
.sample {
  width: 300px;
  margin-bottom: 20px;
}
.tab {
  height: 26px;
  padding-top: 8px;
  padding-bottom: 8px;
  background-color: lightgoldenrodyellow;
}
.tab img {
  height: 100%;
  width: auto;
}
.tab.px img {
  height: 26px;
  width: auto;
}

Safariで表示した場合

冒頭に示した現象は次の手順で再現させることができます。下図のアニメーションです。Safariのインスペクタを開いて、.tabセレクタのpadding-top値を0から徐々に大きくしてみましょう。すると……
Safari_1_3_crop.gif
padding-topが19pxになった時、「LOREM IPSUM」が下側のものより少し大きく表示されるのがわかります。
Safari_1_3_overflow.png
この時、img要素の高さの計算値は27pxで、親要素div.tabのコンテンツボックスの高さ26pxを超えてしまいました。そのままpadding-top値を増やしていくと、画像もどんどん大きくなっていきます。
しきい値27pxとは、どうやら

padding-top + padding-bottom > height

となる地点のようです。つまり、height: 100%を指定したimg要素に対して、Safariはimg要素の高さを次のように算出しているように見えます。

padding-top + padding-bottom img要素のheight計算値
1 height以下 divのcontent boxの高さ
2 heightより大 divのpadding boxの高さ

CSSの仕様を確認

念のため、heightプロパティの値にパーセンテージを指定した時のCSSの仕様を確認しておきましょう。

heightのパーセンテージの基準は?
MDN: https://developer.mozilla.org/ja/docs/Web/CSS/height

<percentage>
包含ブロックの高さのパーセントで高さを定義します。

W3C: 10.5 Content height: the 'height' property

The percentage is calculated with respect to the height of the generated box's containing block.

包含ブロックとは?
MDN: https://developer.mozilla.org/ja/docs/Web/CSS/Containing_block#Identifying_the_containing_block

包含ブロックを識別するプロセスは、要素の position プロパティの値に全面的に依存します。

  1. position プロパティが static 又は relative の場合、包含ブロックはブロックコンテナー (略) 又は整形文脈を確立する要素 (略) である直近の祖先要素のコンテンツボックスの辺によって構成されます。

W3C: 10.1 Definition of "containing block"

  1. For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.

今回のサンプルはこれに該当するので、img要素のheightをパーセンテージで指定した場合は、やはりdiv.tabのコンテンツボックス(paddingを含まない)の高さが基準になるはずです。1

Chromeで表示した場合

実際、デスクトップ版のChrome(Blink), Opera(Blink)やFirefox(Gecko)では上記の仕様どおりに表示されます。IE11やEdgeブラウザでも問題なく表示されました。下図は、ChromeのDevToolsを使って同様にdiv.tabpadding-topの値を増やしていった時のアニメーションです。paddingの値によらず、img要素の高さは26pxのまま変わりません。
Chrome_1_3_crop.gif

WebKitの問題?

上記の現象はSafariのレンダリングエンジンWebKitの問題か?と思って、WebKitのBugzillaを検索したところ、ありました!これです。同じ現象です。

Bug 131486 - Percentage height on replaced elements is computed wildly incorrectly

なんと2014年4月10日にBugzillaに登録されて以来、ステータスNEWのまま放置状態orz
今回、たまたまスマホ用にdivのサイズを「divのpaddig > divの(content-boxの)height」になるまで小さく調整したため、このバグを踏んでしまったのでした。仕方なく、この要素だけimgのheightをpxで指定して回避しました。

  1. position: absoluteにした場合は、paddingを含んだ高さが基準になります。

15
14
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?