Safari や iOS 上のブラウザで border-radius で子要素をマスクできない問題
Safari で HTML を閲覧した際に、親要素に overflow: hidden
と border-radius
を設定してあるのに子要素が border-radius
の範囲をはみ出して表示されてしまう問題についてです。
追記: 親要素に overflow: hidden
を設定している前提の説明が抜けてしまっていたのでタイトルと本文を修正しました(コメントいただいた方ありがとうございました)。
問題
子要素に角丸スタイルを適用するために親要素で overflow: hidden
と border-radius
を設定しても、子要素が border-radius
の範囲外でも表示されてしまいます。
デスクトップ版の Safari や iOS 上の Chrome 等で発生します。
たとえば次のように <img>
を <div>
で囲って overflow: hidden
と border-radius
を設定すると現象を再現することができます。
HTML:
<div class="parent">
<img src="avatar.jpg" width="100" height="100" />
</div>
CSS:
.parent {
overflow: hidden;
border-radius: 50%;
}
(当然のことながら)適用したい要素そのものに border-radius
を設定した場合は意図したとおりに表示されるので、問題は親要素に overflow: hidden
と border-radius
を設定したときにのみ発生します。
私は以下のブラウザ・バージョンで現象を再現できました。
- macOS Safari: 15.4 (17613.1.17.1.13)
- iOS Chrome: 100.0.4896.85
- iOS Brave: 1.37 (22.4.6.8)
原因
早速結論ですが、どうやら Safari (正確には WebKit )のバグ(?)が原因のようです。 WebKit Bugzilla の Bug 140535 で「 non-stacking context でのみ発生する」と言われています。
検証のために、 stacking context を生成するような CSS プロパティを追加すると現象が解消します。
対処方法
上述のとおり non-stacking context でのみ発生するので、意図的に stacking context を生成すれば回避できます。 具体的には、見栄えに影響を与えずに stacking context を生成するために以下のような方法があります:
方法 A) isolation: isolate
をセットする
.parent {
isolation: isolate;
}
方法 B) position
と z-index
をセットする
.parent {
position: relative;
z-index: 0;
}
方法 C) transform
をセットする
.parent {
transform: translateZ(0);
}
「 stacking context を生成する」という本来の意味合いから言うと、最も直接的なのはおそらく方法 A) の isolation: isolate
になるかと思います。
他の方法を使いたい理由が特に無ければ A) を選んでおくとよいのかなと思います。
stacking context を生成する方法は他にもいろいろあるようなので、興味のある方は MDN のページなどを参照してみてください:
参考
Safari (WebKit) 関連:
- html - Overflow: hidden with border radius not working on Safari - Stack Overflow
- 140535 – Border-radius clip of non-stacking composited descendant doesn't work
- 98538 – overflow: hidden + border radius does not work when transform is added to child
- 77572 – content inside element with border-radius is not clipped to border-radius when overflow: hidden is set.
Chrome (Chromium) 関連:
stacking context 関連: