やりたかったこと
ある選択肢の選択内容によって、一つのセレクトボックス内のoption要素を出し分けできるように実装したい件がありました。
非表示にするだけであればCSSをあてなくてもコメントアウトや削除で十分なのですが、今回は別の選択内容と連動する仕様だったため、jQueryを使用して選択内容の条件に対し動的にCSSをあて、セレクトボックスの中身が変わるよう実装しました。
デベロッパーツールでは気づけない問題
ステージングの段階で実機確認ができない環境下だったため、PCブラウザ(chrome/Edge/FireFox)のデベロッパーツールよりスマホの表示確認を行いました。この段階ではコンソールエラーもなく、セレクトボックスの中身は問題なく出し分けができていました。
しかし、実際にiPhone上で確認してみると、option要素へのCSS「display:none;」が効いておらず、すべての選択肢が表示されている状態で出し分けができていませんでした。
まず最初にjsファイル自体の読み込み問題を疑いましたが、同一ファイル内で実行している選択肢変更によるセレクトボックスの選択初期化は問題なく動作確認ができていました。
またsafariの拡張機能デベロッパーツール「Web Inspector」上でコンソールエラーもなかったので問題に気づきにくく、原因究明と解決に少々手間取りました。
これはsafari特有の現象かと思いましたが、アプリ版chromeでも同様の現象が起きていたので、どうやらiPhoneではブラウザ問わず起こる問題のようでした。
今回は、この問題に対して、試してみたことや解決した方法を備忘としてまとめたいと思います。
前提
・HTML、CSS、jQueryの使用で実装
・一つのselect要素で行う
クラスで「select-a=条件aを選択した場合に表示する選択肢(a-1, a-2)」「select-b=条件bを選択した場合に表示する選択肢(b-1, b-2)」と分けています。
試したこと (うまくいかなかった例)
● jQueryでCSS「display:none;」を付与
ブール値「selectedA=条件a」がtrueの場合、「select-a」のみ表示したいので、セレクタ「.select-a」を指定しcssメソッドで「display:inline;」とします(非表示(条件b)→表示(条件a)へ切り替わるパターンも要考慮)。
「select-b」は非表示にするので「display:none;」を付与します。
else内(条件b)では、逆の内容でCSSを付与。
こちらはPC上の確認では問題はありませんでしたが、下の画像のようにiPhone実機では適応されず「select-a」「select-b」どちらの選択肢も表示されてしまいます。
● jQueryメソッド「.show()」「.hide()」を使う
jQueryメソッドを使った方法です。パラメーターを指定せず「.show()」を実行すると前述の「.css("display", "inline")」と同じ挙動ではあるので、こちらも同様にiPhone実機では適応されませんでした。
● CSSでデフォルトスタイルを初期化
ブラウザ特有のスタイルが影響している可能性も考え、appearanceプロパティで標準スタイルを解除してみました。select要素、option要素それぞれにあててみましたが、期待した変化はありませんでした。
解決した方法
● CSS有効のspan側で「display:none;」を付与し、非表示にするoptionを囲む ( .wrap() )
optionにCSSが効かないのであれば、iPhone上でもきちんとCSSが効く要素を使う必要があると思い、試しにspanタグを使ってみたところ、うまくいきました。
↑ まずは非表示用クラスを準備します。クラス「selector-hide」にはCSS「display:none;」を付与して非表示となるようにします。
↑ 条件aのとき、非表示にしたい「select-b」に対し「.wrap()」を使用して、非表示用クラス「selector-hide」のspan要素を付与します。
↑ これにより、条件aのときは、非表示用クラス「selector-hide」のspan要素がセレクタ「.select-b」を囲います。
また、条件b→条件aになったときは「select-a」の再表示が必要なため、付与前にすべての「selector-hide」のspan要素を「.unwrap()」でリセットします。
「.unwrap()」は指定したセレクタの親要素を削除します。
単純に「select-a」のwrapを解除するので「$('.select-a').unwrap();」とすればいいように思いますが、「select-a」が「selector-hide」にwrapされていない場合の親要素はselect要素になるため、select要素が削除対象となってしまいます。
これを回避するために、「.contents()」で「selector-hide」の子要素を指定し、その親要素である「selector-hide」をunwrapするようにしています。
この方法であれば、「selector-hide」にwrapされていない状態のoptionについてはunwrapの対象外となり、select要素を削除することはありません。
結果
span要素「selector-hide」にCSSが効いて、中身のoptionまるごと非表示が成功しました。
条件a ↔ 条件b の切り替えも、iPhone上で正常に実装できました。
もちろんPCのブラウザ上でも問題はありません。
まとめ
デベロッパーツールでの表示確認はあくまでも疑似的再現であり、当然ですが完璧ではありません。いろんなデバイスでの表示が一つの画面で可能で、ついついその便利さに、さも正常に表示されているかのように錯覚してしまいますが、実際は気づかないところで意図しない挙動になってしまっているという落とし穴がひそんでいるものですね。
もとよりiPhoneでの表示のクセや違いなどについての知識があれば、今回の件も事前に把握できていたかもしれませんが、めまぐるしいスピードでアップデートされてゆく日々のなかでは、既存の知識や常識も突如として通用しなくなることも多々あり、知識は知識で蓄えつつ、可能であるならやはり事前に実機で検証するに越したことはないと改めて感じました。
とはいえ、デベロッパーツールが万能であることはいうまでもなく、これからもデバッグできるところはきちんと確認しつつ、過信しすぎず実機の動作確認とあわせてうまく活用していきたいです。