iOS 11のフォームのバグの原因を考察してみた

前回までブロックチェーンの記事を続けて投稿し、イーサリウム!トランザクション!ドンペリニョン!みたいなバブル感でお届けしてきたテックブログ。
今日は打って変わってやや重苦しい感じの幕開けとなっております。
今回のお題は、iOS11のWebkitで発生しているバグについてです。

それはさかのぼることちょうど3ヶ月前、9月20日の丑三つ時のことでした。
今となっては既定路線となったワッショイ感と共に、世界で最も先進(略)iOS 11が華々しくデビューしたのです。
やれARだのDockだのと新機能にスポットライトが当たりましたが、その華やかなデビューの陰で発生していたこの事件に、当時はまだ誰も気づきませんでした。
ただ一人・・・そう、Siriをのぞいて・・・。(未検証)

フォームでキャレットがずれる
いきなり本題をズバリ挙げてしまいましたが、事件はSafariを始めとするWEBブラウザで起きています。
会議室ではありませんし、レインボーブリッジでもありません。
ある特定の条件下にあるHTMLの入力フォームで、キャレット(青い線)がズレるという事象が発生しています。

これは当初「単にキャレットがズレているだけなんだ」「すぐにAppleが修正するさ」くらいの認識だったのですが、その認識も5分後には断たれます。
入力フォームをタップした後、キャレットが表示された状態で再び指を乗せて上にゆっくり動かすと
なんと、フォームの領域を遥かに超えてキャレットが飛び立つじゃありませんか!
これをキャレットの自由の獲得と見るかバグと見るかは当然後者なので、早速調べてみました。

1. CSSでpositionを変更してみる
まずは同様の現象が起きていないかを調べると、どうもモーダルウィンドウ内にあるフォームで同じ現象(またはもっとひどい現象)が発生しており、
フォームの親要素のpositionの指定が関連しているらしい、ということが分かりました。
あちこちで position: fixed を absolute に変更したら直った、<body>に position: fixed を追加したら直った、クララが立った、という声が上がっていたので、まずは暫定的にフォームを囲む要素を position: absolute に変更してみました。が、変化なし。

2. もうちょっとCSSでpositionを変更してみる
親要素でダメならおじいちゃんおばあちゃんだ、ということでさらに上の要素を見ていくと、一番外側の要素が position: fixed になっています。
じゃあそれを直せばいいのでって、ちょっと待って!それ変えると全部崩れるよ!今日までの日々はなんだったんだ!
いやしかし、やるしかない・・・
なんて言ってるヒマはないのでキーボードを叩いてみましたが、ダメでした。

3. CSSでフォーム自身を拘束してみる
レイアウトを調整しても直らなかったので、じゃあ原因はどこにあるのかを探るべく<textarea>自体をCSSであれこれしてみます。
まずはブラウザのデフォルトスタイルを全部リセットして、上にずれるっていうことは padding かなと思って padding: 0 を指定しましたが、ダメ。
じゃあ高さを縛り付けてやるとばかりに max-height: 1em を指定すると、あれ、キャレットが上に行かないじゃないですか。
なんだよーそういうことかよーってもう一度フォームをタッチして指をゆっくり上に動かすとあれ?飛び立ってる。

4. 原因を推察してみる
CSSで拘束することで確かに画面上はフォームが短くなるのですが、なんだか高さが余計に作られているのは変わりませんでした。
しかし表示上のサイズは変わるし、スタイルをリセットして背景色を消すと消えるので、CSSは確かに解釈されているようです。
ということから、以下のような流れでこの事象は起きているのではないかと考えました。

HTMLを解釈

CSSを解釈してレンダリング開始(JSのあれこれとかは割愛します)

<textarea>タグを発見、CSSで意図した通りのスタイルで表示をレンダリング(この時点では正しい)

その後Webkit内部でタッチ検知パーツや入力したテキストを反映するパーツを生成(ここで何か間違ってる?)

表示サイズとは異なる<textarea>に対応したエリアが生成される

表示エリアとブラウザの認識エリアにズレが生じ、スタックがオーバーフローする

5. 後編へ続く
上記の推察が正しいかどうかは分かりませんが、どうやらCSSで制御しきれないバグのようです。
ということはJSでも手が届かない部分になりそうなので、今回はAppleの対応を待つしかなさそうですね。
なお、執筆時点で最新版のiOS 11.2.1ではまだ解消されていません。

Appleの対応が終わったら物語もいよいよ最終局面、運命の糸が絡み合い、<input type=”text”>と<textarea>がついに激突!(しません)