border-radiusやoverflow: hidden;がSafariで効かない時の対処法

目次

Safariでのみborder-radius: 50%;とoverflow: hidden;を外すとスタイルが崩れてしまい、画像を円形にトリミングできない

といった現象に出くわしました。

解決法を探っていると、どうやらpositionプロパティとz-indexプロパティに原因がありそうです。

【Point】Safariでborder-radiusとoverflow: hidden;を適用させるには

  • 子要素のpositionプロパティにstatic以外の値が指定されていないか確認する

【結論】Safariでborder-radiusとoverflow: hidden;を適用させるには

  • 子要素のpositionプロパティを解除できない場合
    →親要素にz-index: 1;を指定する
  • 子要素のpositionプロパティを解除しても問題ない場合
    →子要素のpositionプロパティを解除する

【基本コード】Safariでborder-radiusとoverflow: hidden;を適用させるには

HTML

<figure class="icon">
    <img src="/img/icon-profile.png" width="96" height="96" loading="lazy" aria-hidden="true" alt="さおさん">
</figure>

SCSS

.icon{
  border-radius: 50%;
  overflow: hidden;
  
  img{
    position: relative;
  }
}

こちらのコードをベースに見ていきます。
下記のスパイスカレーの画像部分のコードです。
.iconという親要素の中に画像が入っています。

【解説】Safariでborder-radiusとoverflow: hidden;を適用させるには

まずは子要素にpositionプロパティが指定されているかを確認する

親要素に指定されているborder-radiusoverflowプロパティがきかないケースでは、
子要素のpositionプロパティにstatic以外の値が指定されていることが多いです。

指定されていた場合、
指定の解除の可否によって対処法が変わってきます。

positionプロパティを解除できない場合の対処法

子要素のpositionプロパティを外すとスタイルが崩れてしまうなどの不具合が起こる可能性があります。
そういったケースでは子要素の指定は変更せず、
親要素にz-index: 1;を指定します。

.icon{
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  z-index: 1;
  
  img{
    position: relative;
  }
}

z-indexプロパティはpositionプロパティにstatic以外の値を指定しないとONにならないので、
あわせてposition: relative;も指定します。

positionプロパティを解除しても問題ない場合の対処法

こちらのケースでは、単純に子要素のpositionプロパティを外してあげましょう。
なので下記で問題ありません。

.icon{
  border-radius: 50%;
  overflow: hidden;
}

これで円形にアイコン画像をトリミングできました。

スタッキングコンテキストとスタックレベルとは?

なぜこのような対処法で解決できるのでしょうか?
この問題の根底には「スタッキングコンテキスト」と「スタックレベル」という概念が存在しています。

  • 「スタックレベルってなんなん?」

スタックレベルとは「スタッキングコンテキスト内の要素の重なり順」のことです。

  • 「なるほど。んじゃ、スタッキングコンテキストってなんなん?」

スタッキングコンテキストとは「スタックレベルの比較範囲」のことです。

まとめると、
スタッキングコンテキスト内の要素間でのみ、重なり順が比較される
ということです。

——————————————–

期末試験を例に説明してみようと思います。

期末試験が終わると成績順が発表されます。
学年全体の順位もあれば、クラスごとのもの出されます。

このクラスごとの順位を算出するときの

  • 「クラスという単位」が「スタッキングコンテキスト
  • 「クラス内の成績順」が「スタックレベル

です。

A組とB組がある場合、それぞれのクラスごとに生徒の点数を比較しますよね。
A組の最下位とB組の最下位の点数を比較して順位をつけたりしませんよね。

順位はクラス内の生徒の間でのみ比較」します。

これと同じことがWebページ上でもなされています。
要素の重なり順(成績順)は、スタッキングコンテキスト内(クラスの中)でのみ比較されているのです。

——————————————–

なぜ今回の不具合が起こったのかというと、
親要素にスタッキングコンテキストが生成されていないのに、
子要素であるアイコン画像にpositionプロパティが適用されていたからだと考えられます。

スタッキングコンテキストを作成するには、要素にz-indexを指定する必要があります。
しかしpositionプロパティを指定することで、z-indexを指定しなくても、
スタッキングコンテキストのような振る舞いをします。
つまり、通常の要素よりも上に位置するようになります。
(※参考:君は真に理解しているか?z-indexとスタッキングコンテキストの関係

このことからSafariでは、
子要素がスタッキングコンテキストのような振る舞いをすると
親要素の領域に所属していないと認識されてしまうのかもしれません。
(親要素のスタッキングコンテキストから外れるのかもしれないということです)

なので対処法は下記の二通りになります。

  • 親要素にスタッキングコンテキストを生成する
  • 子要素に対するスタッキングコンテキストの適用をやめる

スタッキングコンテキストの生成方法

スタッキングコンテキストを生成するのはカンタンです。
スタッキングコンテキストを生成したい要素に、position プロパティと z-index プロパティを指定するだけです。

.icon{
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  z-index: 1; //これで.icon要素を基準にスタッキングコンテキストが生成されました
}

この指定で、子要素であるアイコン画像が、親要素のスタッキングコンテキストに所属することになりました。
親要素の領域に内包されることでSafariでも円形トリミングに成功しました

【まとめ】Safariでborder-radiusとoverflow: hidden;を適用させるには

position プロパティのこととか z-index プロパティのこととか、
はたまた「スタッキングコンテキスト」や「スタックレベル」いう概念が出てきたりとか。

調査すればするほど奥が深くて難しくて
オーバーヒートしました…

Safariで border-radiusoverflow プロパティがきいていない時は、
まず下記の方法をお試しください!

  • 親要素に z-index: 1; を指定する
  • 子要素の position プロパティを解除する

以上です!
少しでもお役に立てたら嬉しいです。

【参考サイト】Safariでborder-radiusとoverflow: hidden;を適用させるには

Share

Comments

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。

CAPTCHA