私事ですが先日引っ越した. それはよくて,引っ越しすると住所変更が面倒で 外部キーでマスターからカスケードですべて変わってくれないかと思う. それもよくて,大事な書類が届かないと大変だと 銀行口座やクレジットカードの住所変更をしていた.
起
生活に必要なものを大抵スマホのアプリで入れている. クレジットカードアプリも生体認証でログインできたりして, いまや 2段階認証なりが必要な PC よりも楽な気がする. (なんか本末転倒でダメなことをしているような気もする)
なので,住所変更もキーボードのほうがやりやすいのは脳裏によぎりつつも 簡単な操作はスマホアプリからやっている.
前置きが長いけど,問題はドロップダウンで住所を選ぶ箇所で, iOS だと選択のドラムがグルグル回るやつが 住所が長いと途切れるということに気づいた:
住所の文字数が多いと選択が厳しい世の中になっていることに気づいた。 pic.twitter.com/f7x54kLQm1
— マンガーノ・伊藤 (@mangano_ito) November 12, 2021
↓
省略されてしまって何丁目か確認できないので, ここかな というポジションを選択して 結果が入力されたフィールドを確認することになる:
(※ お気づきのかたがいらっしゃるかもしれませんが,草稿を書いた当時は iOS 14 でした.後日談は後述します)
承
あまりにもバカバカしくて, 流石に世間でも話題になっていて なんらかの属性なりで回避できるだろう……と思って調べてみると CodePen の例が一番上に出てくる:
See the Pen IOS long dropdown values fix by Jérémie Gisserot (@ledjay) on CodePen.
まさに今回のケースでどうするのかな,と思ったら
空の <optgroup>
を末尾に挿入すると長い文字列でも折返しがされるらしい:
なかなか不可解なこの workaround は Web デザイナーの間で有名らしくて, 検索するといくつもページが出てくる:
ちなみに Android では <optgroup>
がなくても折り返しされる:
転
5年以上 Web プログラマーしていたけど, いままでこの仕様を知らなかったので きっと他にも知らない人がいるかもしれない. (それとも実はこれは一般教養だったりするかもしれない).
この経験のおかげで もし今後こういうケースに出会ったら
「末尾に <optgroup>
いれましょう」と
<!-- iOS では 末尾に空の optgroup を入れることで長い項目でも折返しさせる-->
みたいなコメントを入れてコミットすることができる.
そもそも PC でも長い <option>
は好ましくなさそうという話題もある.
異常に長い文字列を表示したときに途切れるのは変わらない:
結
iOS 開発は知識ゼロだけど,カンだけでコードを見てみよう.ピッカーは UIPickerView
というらしい.ガイドラインでは Consider using a picker to offer medium-to-long lists of items.
となっている:
そのクラスから探すと,WebKit で該当の実装をしているソースはここだろうか:
WebKit 側でのピッカーには WKSelectSinglePicker
と WKMultipleSelectPicker
という 2 つの実装があるようで,文字列がトリムされていたりいなかったり,後者はフォントやラップの指定に違いが見られるようだ:
ここで,<select>
の実装がおもしろポイントになっている:
if (!currentUserInterfaceIdiomIsSmallScreen()) control = adoptNS([[WKSelectPopover alloc] initWithView:view hasGroups:hasGroups]); else if (view.focusedElementInformation.isMultiSelect || hasGroups) control = adoptNS([[WKMultipleSelectPicker alloc] initWithView:view]); else control = adoptNS([[WKSelectSinglePicker alloc] initWithView:view]);
▲ WKFormSelectControl.mm#L88-L93
currentUserInterfaceIdiomIsSmallScreen()
は対象が小さいスクリーンを持つデバイスかどうか判定しているようだ.コード的にはつまり iPhone か Apple Watch のことだと思われる:
isSmallScreen = idiom == UIUserInterfaceIdiomPhone || idiom == UIUserInterfaceIdiomWatch;
▲ UserInterfaceIdiom.mm#L51-L71
ここから
1 つめの条件
if (!currentUserInterfaceIdiomIsSmallScreen())
は大きいスクリーンの環境であるときはWKSelectPopover
のピッカー実装となりそうだ (ポップアップするピッカーだろう).2 つめは
else if (view.focusedElementInformation.isMultiSelect || hasGroups)
であるから,複数選択可のselect
要素であるか,optgroup
要素によってグルーピングされているselect
要素である場合はWKMultipleSelectPicker
が選ばれる.最後にどちらでもないときは
WKSelectSinglePicker
が選ばれる.
つまり,この実装から推測すると,<optgroup>
を含むか,multiple
属性により複数選択可になっていると同じく折り返しがされることになるはずだ:
繰り返すけれど iOS 開発はわからないので,期待と想像から雰囲気で実装だと主張している.間違っているかもしれない (鵜呑みにしないでください).しかし最後は符合したので,大筋ではあっている気がしている.
後日談
この体験のあと iOS 15 にアップデートした.Safari が変わっていてピッカーも変わっている.そして,ピッカーはポップアップになっていてうまく折り返しされるようになっている!
つまり,この workaround は既に過去の話題となっている!
この変更は https://github.com/WebKit/WebKit/commit/27da6af7a7aa54634af4b80d6a4d4b801f4fcdf0 で取り入れられたようで,いつのまにか状況は変わるものだ (僕が OS のバージョンアップをずっとしてなかったからなのですけれど).
ちなみに複数選択のコントロールも変わっている (新しいのは WKSelectMultiplePicker
で,古いのは WKMultipleSelectPicker
のようでややこしい):
開発者ツールを使って selected="selected"
にするユーザーがいるわけがないので,
ユーザーエージェントでどうにかしてもらえるのはとてもありがたい.
余談
運転免許証の住所変更をすると 裏書きにあたらしい住所が追記されるだけで 次回更新まではそのままになる. 僕は既に2回の転居が追記されていて あわや あと1行という感じで確実に次回は入らない:
噂では足りないと紙が上から貼られるとか聞いたのだけれど, まさか身分証明書がそんなおてがる対応なのだろうか, この場合は新しい運転免許証が発行されるのだろうか. 調べればわかるのだけれど次回更新が来月までなのでもうよいと思った. (この転居の手続きをした後に更新のハガキが届いた.良い二度手間だ)
つまり,コンピューターでも日常でもはみ出す長い文字列はやっかいだということでこの話をまとめたかった.
🌟 今週の仲間求むのコーナー 🌟
ところで,僕は株式会社はてな の マンガチーム で開発を行うエンジニアで,はてなでは一緒にはたらく仲間を募集しております.iOS / Android アプリエンジニア や サーバーサイド・フロントエンド開発を行うエンジニアを積極募集しておりますので,ぜひご応募またはご連絡ください.そして この2職種だけではございません.詳しくは採用ページをごらんください: