iOSでfixed要素の背景がツールバーの高さ分 消える件

スマホ(iOS)のバグ?のお話です。
いつもこの問題に直面するのですが、検索しても出てこないので書いてみます。

※2017/01/11時点、検証可能な範囲 iOS8.4 〜 10.2で発生を確認。

モーダルウィンドウなどを実装する時に、ブラウザ全面に背景色を引いたfixed要素を置くことはよくありますよね。
iOSにおいて、ツールバーが一度出た状態からスクロールして、ツールバーが消える時にこの高さ分(よりやや多め) 背景が消えてしまう問題があります。
文章で説明してもよくわからないと思うので、以下をご覧ください。

数秒以内に正しい状態に治るので大きな問題ではないのですが、割と気になります。
解決方法としては、fixed要素には背景をつけず、背景用のabsolute要素を別に配置する、となります。
発生状態のコードと、解決後のコードを解説します。

バグ発生状態のコード

デモはこちらから
※iOSでご確認ください
※以下 要点のみ、他省略

HTML


<body>
<div class="content">コンテンツ 〜省略〜</div>
<div id="modal">
<div class="inner">
モーダル内 〜省略〜
</div>
</div>
</body>

CSS


body{
position: relative;
}
#modal{
position: fixed;
background: rgba(0,0,0,.6);
width: 100%;
height: 100%;
top: 0;
left: 0;
}

解説

「#modal」がfixed要素、つまり「position:fixed;」を指定しています。縦横100%で背景をつけて全画面表示となっています。
bodyに「position: relative;」を入れることでfixed要素の基準点としています。
この状態だと先程の背景が消えるバグが発生しています。

解決後のコード

デモはこちらから
※iOSでご確認ください
※以下 要点のみ、他省略

HTML


<body>
<div id="wrapper">
<div class="content">コンテンツ 〜省略〜</div>
<div id="modal">
<div class="inner">
モーダル内 〜省略〜
</div>
</div>
<div id="modal-bg"></div>
</div>
</body>

CSS


#wrapper{
position: relative;
}
#modal-bg{
position: absolute;
top: 0;
left: 0;
background: rgba(0,0,0,.6);
width: 100%;
height: 100%;
}
#modal{
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1000;
}

解説

「#modal」から背景色を消します。代わりに「#modal-bg」という空の「div」タグを配置し、そちらに背景をつけます。
ポイントは「#modal-bg」は「position:absolute;」ということです。要はfixed要素でなければ背景が消える問題が起きないので、背景はfixed要素じゃないところで補おうということです。
もう一つポイントとして、全体を囲う「div」タグ「#wrapper」を追加していることです。
この要素に「position:relative;」を指定することで、positionの基準値にしています。
bodyが基準値のままだと、「#modal-bg(position:absolute;)」の背景がブラウザの高さ分にしかつかず、その下は途切れた状態になってしまうことがあるからです。
(不明瞭ですみません。以前に実装した時にこのように対処したのですが、様々な指定が絡んでたので、ちょっとどういう条件だったか思い出せず。。)
特にその問題がなければ「#wrapper」入れなくても大丈夫です。

補足

今回のデモでは、本題からズレるのでJSでモーダルウィンドウの動きを入れることはしませんでしたが、実際にはJSで出したり消したりを実装するかと思います。
そのときには、うまく「#modal-bg」も一緒に出したり消したりすればOKです。

もっと簡単に解決できる方法を知っていたら、ぜひ教えてください。

デモ

※iOSでご確認ください
解決前のデモはこちらから
解決後のデモはこちらから