flexboxでabsoluteの子要素の位置がおかしくなる【IE11】

,

こんにちは、katori@xxbicotです。
IE11では、flexboxの子要素(flexアイテム)にposition:absoluteがかかっている要素があると、並び方がおかしくなるときがあります。
毎回遭遇しては対応法を忘れてしまうので、備忘録用に対処法をいくつかまとめました。

今困っているという方は、この中から現状に合った方法を試してみてください!

absoluteの子要素の領域が確保されてしまう

まず、事象が発生するサンプルを作成してみました。
IE11と他のブラウザでの表示をキャプチャで比較します。

IE11以外の場合はこちら。


そしてIE11の場合。

次にサンプルのコード。
このコードはロゴ(flex item 1)、ハンバーガーメニュー(flex item 2)、ハンバーガーメニューをクリックすることで開閉するナビゲーションメニュー(flex item 3)を想定したものです。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<div class="flex">
	<div class="flex-item">flex item 1</div>
	<div class="flex-item">flex item 2</div>
	<div class="flex-item poa">flex item 3(absolute)</div>
</div>
<style>
* {
  box-sizing: border-box;
}
.flex {
  display: flex;
  justify-content: space-between;
  position: relative;
}
.flex-item {
  padding: 2rem;
}
.flex-item:nth-child(1) {
  background-color: #f17474;
}
.flex-item:nth-child(2) {
  background-color: #f7ec5a;
}
.flex-item:nth-child(3) {
  background-color: #65bd65;
}
.poa { 
  position:absolute;
  left: 0;
  top: 6rem;
  width: 100%;
  transition: all .2s ease;
}	
	
</style>
</body>
</html>

flexアイテムの並び方はspace-betweenを指定しているので、本来ならflex item 1とflex item 2が両端に置かれるはずです。
それがIE11だけflex item 2の右に空白ができてしまいました。

この原因として、IE11ではabsolute要素は通常のflexアイテムとして扱ってしまうことにあります。
本来absolute要素はフレックスレイアウトに参加しないはずが、IE11の不具合により参加=領域が確保され、そのためサンプルではIE11だけ右側に余白(flex item 3の領域)ができた、ということのようです。

このサンプルはjustify-contentプロパティがspace-betweenの場合ですが、space-aroundでも位置ずれが発生するという事例も見かけました。どうやらjustify-contentプロパティが怪しい動きをするとのこと。

ちなみに、以前はFirefoxでも同様のバグが発生していましたが、2017年3月リリースのバージョンで修正されて、今はIE11だけで起きます。

対処法について

flexアイテムの並び順を変える

absolute要素がカウントされてもされなくても、影響がでない順番に並び替える方法です。

先ほどのコードで例えると、

<div class="flex">
	<div class="flex-item">flex item 1</div>
	<div class="flex-item">flex item 2</div>
	<div class="flex-item poa">flex item 3(absolute)</div>
</div>

この順番を、

<div class="flex">
	<div class="flex-item">flex item 1</div>
	<div class="flex-item poa">flex item 3(absolute)</div>
	<div class="flex-item">flex item 2</div>
</div>

このようにします。

こうすると、absoluteがカウントされてもflex item 1とflex item 2を両端に置くことができます。

orderプロパティでflexアイテムの並び順を指定する

「文書構造上要素の順番を変えたくない」または「もうCSSコーディングが済んでいて今から順番変えると影響が出る」という場合はこれが一番おすすめ。

orderはflex・gridコンテナの中で、アイテムを並べる順序を設定できるプロパティです。

サンプルの場合、order:1を2番目の要素に設定します。

<div class="flex">
	<div class="flex-item">flex item 1</div>
	<div class="flex-item" style="order:1">flex item 2</div>
	<div class="flex-item poa">flex item 3(absolute)</div>
</div>

こうすると、orderの初期値は0なので、レイアウト上でflex item 1、flex item 3(absolute)(orderの値が一緒の場合は要素の記述順)、flex item 2という順番になり、前述の「flexアイテムの並び順を変える」と同じように表示されます。

orderプロパティ、あんまり使ったことなかったんですが、スタイルを1つ追加しただけでレイアウトを調整できるのは便利ですね!

flexコンテナの外へ出す

そもそも論ですが、この案を見かけて「確かに!」と思ったのでご紹介。

いっそ、flexコンテナからabsolute要素を外に出すという方法です。

<div class="flex">
	<div class="flex-item">flex item 1</div>
	<div class="flex-item">flex item 2</div>
</div>
<div class="flex-item poa">flex item 3(absolute)</div>

他のflexアイテムと並列の関係にすべき要素なのか?と考えた時、もしそうでなければ外に出した方がよりセマンティックになる可能性も。

コードを見直すいい機会かも知れませんね。

display:noneを設定する

absolute要素は、visibility: hidden やopacity: 0を指定しても領域が確保されてしまいますが、display: noneなら問題ありません。

結局display: block にしたタイミングでずれてしまうので、サンプルの開閉ナビでは使いづらい方法ですが…(´Д`)

違うケースでは役立つかもしれないのでご紹介まで。

flexboxを使うとき必ずIE11で確認を

「flexbox IE11」と調べるとバグ報告がたくさんでてきますよね。

コーディング中念の為チェックしなきゃなぁと思っていたんですが、今回のマークアップはよくある使い方のひとつだと思っていたので、ここでもバグが出るのか!とちょっと予想外でした。

こういうことがあるとIE11が早くサポート外になることを祈りたくなります(ヽ´ω`)

一方で、コードに対する警告に関しては「確かにここは明示的に書いた方がいいよなぁ」という気づきも多々。
まだまだIE11チェックは欠かせないですね。

以上、「flexboxでabsoluteの子要素の位置がおかしくなる【IE11】」でした!