position: sticky;を使った時にa要素のタップの位置がズレる

stickyは、特定の位置から要素を固定し、要素の指定位置まで達すると相対位置に配置される便利なCSSです。
iOS 6.0、Android 5以上とスマートフォンサイトで使える場が増えていますが、バグに遭遇したのでご紹介します。

iOS 11でa要素のタップの位置がズレる

iOS 10では問題なかったのですが、iOS 11で発生しました。
viewportを固定した状態で、stickyを使った要素の子にa要素があると、相対位置に配置されるまでスクロールした時に、そのa要素のタップの位置がズレます。

sticky.gif

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=320">
  <title>Document</title>
</head>
<body>
  <div class="box">
    コンテンツ
  </div>
  <div class="sticky">
    <a href="/">Sticky</a> 
  </div>
  <div class="footer">
    footer
  </div>
</body>
</html>
.box {
  height: 800px;
}
.sticky {
  position: -webkit-sticky;
  position: sticky;
  right: 0;
  bottom: 0;
  left: 0;
}
.sticky a {
  display: block;
}
.footer {
  padding: 16px 0;
}

解決方法 1

viewportの固定をやめる。

<meta name="viewport" content="width=320">

320pxでviewportを固定している箇所をdevice-widthに変更します。

<meta name="viewport" content="width=device-width">

解決方法 2

デザインの都合上、viewportを固定をする必要がある場合は、stickyの下の要素を高さを大きくしてみる
例では.footerpadding: 16px 0;の宣言が指定されていましたが、padding: 54px 0;にすると、直りました。
なぜ直るのか、よくわかりません。
そして、viewportを固定する時は、基本的に枠にとらわれない大らかなデザインを厳密に再現する場合なので、使えません。

解決方法 3

html要素をスクロールさせないようにして、bodyの要素をスクロールさせる。
viewportを固定しつつ、stickyでおかしな挙動がでたら、スマートフォン限定でこちらを使うといいかもしれません。

html {
  overflow: hidden;
  height: 100%;
}
body {
  -webkit-overflow-scrolling: touch;
  overflow-scrolling: touch;
  overflow-y: auto;
  height: 100%;
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.