少しの記述でユーザビリティやアクセシビリティを向上させるHTML/CSSテクニック集
広告
少しの記述・工夫でユーザビリティやアクセシビリティを向上させるHTML/CSSテクニックを独断と偏見で集めてみました。最近クローズドな場所で登壇を行ったのですが、そちらで話した内容を纏めたものにいくつか内容を追加したものとなります。
原則的にこのブログで取り入れられている手法だったり過去の記事で触れた手法を紹介したものです。
button要素には touch-action:manipulation を指定する
iOS限定の話ではありますが、button
要素をつい連続でタップすると画面が拡大表示されてしまい非常に煩わしいです。
そのため、パンおよびズームのジェスチャーは有効にしつつダブルタップ時のズームなどの標準外の追加的なジェスチャーを無効にするtouch-action:manipulation
を指定して誤作動を防止しておくと良いでしょう。
ハンバーガーボタンやその他のJSで操作するクリッカブルな要素をbutton
で実装している場合はevent.preventDefault()
を適用しておけばこの現象は防止できますが、指定忘れだったりevent.preventDefault()
の適用が望ましくないケースも存在するため、原則的にはプロジェクトのベースCSSに指定しておくと良いと思います。
overflow:auto を指定している要素には overscroll-behavior:contain も指定する
デスクトップで操作している際は気にならない項目ではありますが、overflow:auto
が指定されたスクロールが可能な要素でラバーバンド効果(スワイプで更新や履歴を戻る処理をする際のバウンス効果)が有効なままだと暴発して操作がしにくい印象となります。
特にモーダル内でラバーバンド効果が発生すると「下にスクロールしようとしたら更新アクションに入ってしまう」みたいなケースが多く、そのたびに毛根へのダメージが加わるので原則的にoverflow:auto
を指定している要素には overscroll-behavior:contain
も指定するようにしています。
当ブログのtable
要素のようにインライン軸(横書き時:X軸)をスクロールさせる際にoverscroll-behavior:contain
を指定すると縦スワイプに影響が出てしまうので、原則的にはインライン軸(横書き時:X軸)のスクロールであればoverscroll-behavior-inline
、ブロック軸(横書き時:Y軸)のスクロールであればoverscroll-behavior-block
にcontain
値を指定することを推奨します。
画面下部にコンテンツを固定配置する際はセーフエリアを考慮した位置調整を行う
position:fixed
でハンバーガーボタンやトップへ戻るボタンを画面下部に固定配置する実装はよく用いられますが、iPhoneXの登場以降はホームバーが画面下部に表示されるようになった関係でそのまま固定配置するとホームバーにかぶさって表示されたり、ボタンを押したつもりがSafariのメニューボタンが出現して2度タップする手間が発生するといった問題があります。
env(safe-area-inset-bottom)
で画面下部のセーフエリアの高さを取得できるため、calc()
関数などと合わせてセーフエリアを考慮した位置調整を行うと良いでしょう。
ホバー時のスタイルは any-hover メディア特性内に指定する
タップ操作orポインター操作の区別を行い、タップデバイスでのホバーアクションを無効にするためにany-hover
メディア特性内にてホバー時のスタイルを指定することを推奨します。
タップデバイスでのhoverアクションを無効にすべき理由や@media (hover:hover)
よりも@media (any-hover: hover)
を優先したほうが良い理由は過去に投稿した記事「hoverを指定するならany-hoverメディア特性を使いなさい!俺流hover実装例も紹介します」にて詳細に解説しているのでそちらを参照してください。
for 属性を指定している label 要素や summary 要素には cursor:pointer を指定しておく
for
属性を指定しているlabel
要素やsummary
要素にホバーしてもカーソルはデフォルトのままですが、クリックしたら何かが行われる要素は原則的にカーソルをポインターアイコンに変えたほうが良いのでベースのCSSでcursor:pointer
を指定しておくと良いでしょう。
サードパーティー製のプラグインにはdiv
要素にrole="button"
を指定してボタンとするみたいな実装も多く見受けられるので、[role='tab']
と[role='button']
にもcursor:pointer
を指定しておくのを推奨します。
デフォルトのフォーカスインジケーターは :focus:not(:focus-visible) 時に非表示にする
一般的にクリックやタップ時に表示されるフォーカスリングはデザイン的に好ましくないという場合で非表示にされることが多いです。
しかし、a
要素やbutton
要素に直接outline:none
を指定するとキーボード操作時のフォーカスリングも消えてしまい、アクセシビリティに悪影響を与えるため厳禁とされています。
キーボード操作時のフォーカスリングを維持しつつクリックやタップ時のフォーカスリングを抑えたい場合は、以下のCSSをベースとしてプロジェクトに追加するようにします。
:focus-visible
はユーザーエージェントが要素にフォーカスを明示するべきであると推測的に判断した場合に適用される擬似クラスです。開発者がoutline:none
を指定してキーボード操作時での悪影響を防ぐために設計されたという経緯があり、まさにこのようなケースの対応策としてベストな選択肢と言えるでしょう。
ただし、「フォーカスを明示するべきであると推測的に判断した場合」とあるようにユーザーエージェントによって動作に多少の違いがあることは留意してください。具体的にはdialog
要素やポップオーバー APIでのautofocus
はSafariのみ:focus-visible
のスタイルがあたってしまいます。過去の投稿にてSafariでの非キーボード操作時のoutlineの出現を抑制する方法を紹介していますのでこちらも参照してください。
ホバーのスタイルは :focus-visible 擬似クラスにも適用する
キーボード操作時にフォーカスされている要素を明確に示すために:hover
擬似クラスに指定している定義を:focus-visible
にも適用することを推奨します。
フォーカスの明示をユーザーエージェントで用意されているoutline
のみで行うとフォーカスリングの色が背景色と似ている場合はフォーカスリングが見えにくくなる可能性がありますし、フォーカスリングは要素の外側に表示されるため親要素にoverflow:hidden
等が指定されたりすると最悪フォーカスリングが隠れてしまうリスクもあります。
フォーカス時のスタイルを別途考えるとなるとデザイナーへの負担だったりコミュニケーションコスト増加の懸念があるため、大抵の場合はfocusableな要素には状態変化が明確なホバーのスタイルが指定されているでしょうからそれを流用するのが手っ取り早いと思います。
上下マージンを要素に含めたい場合は親要素に display:flow-root を指定する
要素に上下マージンを完全に含むようにする場合、親要素にoverflow:hidden
を指定するのが一つの回答として有名ですが、前項で説明した理由からフォーカスリングが切り取られてしまうリスクがあります。
上下マージンを完全に含むようにしたい場合は親要素にoverflow:hidden
ではなくdisplay:flow-root
を指定することを推奨します。
transition を指定する際は transition-property も同時に指定する
これは過去の有料noteとかでも触れていますが、transition-property
の値はアニメーションで動くものだけに絞るようにします。
transition: 0.3s
のようにtransition-property
の記述をサボると初期値がall
故にブレイクポイント跨いだ時や配色をデバイス設定で変えた際などに意図しないアニメーションが起こる可能性があります。僕は昔からtransition-property
の値の指定を必須としています。
チェックボックスやラジオボタンを自作する際はフォーカスリングも追加する
チェックボックスやラジオボタンを自作するテクニックは多くの技術記事で紹介されていますが、残念ながらそれらの方法の多くはフォーカスが可視化されないことが多く、a
要素やbutton
要素にoutline:none
を指定しているのと変わらない実装がされている場合が多いです。
親要素(大抵の場合はlabel
要素で囲まれるはずなのでそれ)に:has()
セレクタで子孫要素に:focus-visible
が適応されている場合にフォーカスリングを表示するなどしてフォーカスを可視化することを推奨します。前述したようにホバー時のスタイルも適用しておくと良いでしょう。
これは過去に僕も通った道ですが、チェックボックスやラジオボタンを自作する際にinput
要素をdisplay:none
やvisibility:hidden
するとキーボード操作時にフォーカスが不可能になるため厳禁です。
ただし、現在ではinput
要素を直接スタイリングすることができるため、input
要素を非表示にして空のspan
要素でパーツを自作する必要があるかは考えたほうがいいでしょう。加えて、[type="radio"]
および[type="checkbox"]
には::before
::after
疑似要素も適用できるため、実装コストやアクセシビリティチェックの観点からもinput
要素を直接スタイリングするのが望ましいかもしれません。
入力欄の font-size は計算上 16px 以上とする
input
やtextarea
の入力欄に計算上16px未満のfont-size
が指定されているとiOSでフォーカスするたびにズームされてしまいます。入力欄のfont-size
は計算上16px
以上にしてください。
つい最近某通販サイトにてこの現象に苦しめられたので、文部科学省はそろそろ義務教育で教えるべきだと考えます。
もしもデザインの都合上入力欄のfont-size
を16px未満にすることが求められ、政治活動では覆せないような場合は:focus-visible
時にfont-size
を16px以上にするか、scale
プロパティで入力欄を縮小するようにしてください。
実装例1の:focus-visible
時にfont-size
を16px以上する方法はコストが低いですが、入力前後と入力中でfont-size
に変動が起こるため見た目が不格好になる可能性があります。:active
時にfont-size
を16px以上にする実装方法もありますが、こちらはオートコンプリート時に拡大されてしまうので非推奨です。
実装例2のscale
プロパティで入力欄を縮小する方法は見た目が不格好になりにくいメリットがありますが、それに至るためのプロセスに様々な工夫を要する必要があり、導入コストが高いです。
font-size
の変動ごとに縮小率を変動させるのは面倒ですし、clamp()
との相性が悪いのでJSで縮小率を計算するようにします。
- 初期化時に
--ratio
カスタムプロパティに縮小率をセットしつつ、--font-size
カスタムプロパティに16px
をセットします。読み込み時にフォントサイズが変動するため、挙動が不格好になるリスクがあるのに加えてレイアウトシフトも生じる可能性があるためです。scripting
メディア特性でJS無効環境ではCSS側で1rem
をセットします。JSでセットするfont-size
を16px
とする理由は、1rem
とするとscale
で縮小率を管理している兼ね合いでブラウザの文字サイズ調節機能有効時に期待されるfont-size
以上に拡大されてしまうためです。 - 要素の書字方向をチェックし、
--origin
カスタムプロパティを適切に設定します。 - リサイズイベントは
requestAnimationFrame
を使用したdebounce
関数で最適化します。
また、iOSでの拡大を防ぐ方法としてmeta[name="viewport"]
にuser-scalable=no
およびmaximum-scale=1
を指定することを紹介している文献が多く見受けられます(Google検索で上位にヒットする記事は大体これ)が、現在のユーザーエージェントの多くはこの値を無視するとは言えユーザーへのズーム機能を制限する記述であるためアクセシビリティには良くないとされています。なるべくなら避けるべきでしょう。
いずれの方法もデメリットが目立つため、可能な限り入力欄のfont-size
は計算上16px
以上とするように政治活動をしたほうが良いと思います。
textarea には field-sizing:content を指定しておく
field-sizing:content
はtextarea
の高さを内容に応じて調整することができるCSSプロパティです。
高さが固定されたtextarea
要素は領域が狭い場合に長い文章の入力が煩わしくなったり、長い文章に備えて大きな領域を確保すると無駄にスクロールする必要が生じるなど使い勝手が少し悪い印象ですが、field-sizing:content
を利用することでこれらの問題を解決することができます。
field-sizing:content
は現状Google ChromeとMicrosoft Edgeのみの対応となりますが、非対応のブラウザでfield-sizing:content
の指定が問題を起こすことはないのでプログレッシブエンハンスメントの一環として導入する価値はあります。
field-sizing:content
が指定された場合cols
属性とrows
属性は無効となるため、横幅はCSSで調整しつつある程度の高さを確保しておきたい場合はmin-block-size
を指定しておきます。また、高さの可変に制限がないとレイアウトの見た目に影響が出る可能性もあるのでそれが気になる場合はmax-block-size
で上限値も設定しておくと良いでしょう。
ローディングオーバーレイはJS無効環境では非表示にする
このブログでは使用していませんが、読み込み完了までローディング画面をposition:fixed
でオーバーレイする実装をよく見かけます。これらのローディングオーバーレイは読み込みが完了するとJSで非表示にする関係上、JS無効の状況ではローディング画面が消えずにコンテンツを見ることができないケースが多発しています。
SPAのようにJS依存のWebサイトであれば話は別ですが、JSにそこまで依存しない一般的なWebサイトであればJS無効環境でコンテンツが見えなくなってしまうのは避けるべきです。scripting
メディア特性を使用してJS無効の際はdisplay:none
するなど、JS無効環境の際はローディングオーバーレイを非表示にするようにしておくと良いでしょう。
他にもスクロール連動アニメーションを採用しているサイトではJS無効時にアニメーション発火前のスタイルが当たったままになっている関係でコンテンツの大部分が見えなくなっているケースも散見されます。こういった場合の対処法は過去に投稿した記事『スクロール連動アニメーションの実装例』を参照してください。
ローディング画面のように絶対に最前面に表示させたい要素には z-index:calc(infinity) を指定する
ローディング画面やshowModal()
を使わないモーダルのように絶対に最前面に表示させたい要素のz-index
にはcalc(infinity)
を指定しておくと良いでしょう。z-index:calc(infinity)
は上限値の2147483647
と同等になるため、同一レイヤー内であれば原則的に最前面に表示させることができます。(z-index:calc(infinity)
が複数存在する場合は要素の順序が後ろのものが最前面に来ます)
showModal()
したdialog
要素やpopover
された要素のような最上位レイヤーに位置する要素には勝つことができませんし、z-index:calc(infinity)
の要素の親にスタッキングコンテキストが生成された場合はその中でイキることしかできませんのでスタッキングコンテキスト外のz-index:1
に負けるなど z-index
管理の銀の弾丸になる実装方法ではありません が、外部ライブラリのz-index
も考慮して絶対に最前面に表示させたい要素にz-index:calc(infinity)
を明示しておくのはアリだと思います。
calc(infinity)
の他の使い道としては、錠剤型のコンテンツを作成する際のborder-radius
にcalc(infinity * 1px)
を指定することで確実に角丸を維持することが可能となります。よっぽどのことがない限り999em
や100vmax
でも角丸を維持することはできると思いますが、確実性を持たせるならこちらの指定が良いでしょう。
視差効果(アニメーション)を減らす設定がされている場合にはアニメーションを行わないようにする
一部のユーザーはWebサイトのアニメーション効果により前庭機能障害によるめまい、頭痛、吐き気などを引き起こす可能性があるため、アクセシビリティの観点から視差効果(アニメーション)を減らす設定がされている場合にはアニメーションの無効化を行うようにします。
prefers-reduced-motion
メディア特性を使用して、ワイルドカードでアニメーションに纏わるスタイルを無効化するのを推奨します。
transition
およびanimation
の間隔(duration
)を1ms
に強制することで実質的にアニメーションを無効化します。間隔を0ms
もしくはtransition
とanimation
をnone
にするとJSのtransitionend
イベントおよびanimationend
イベントが発火せずに表示面で不具合を起こす可能性があるため、1ms
を指定するようにしてください。
ul 要素や ol 要素のリストマーカーは list-style-type:"" で非表示にする
ul
要素やol
要素のデフォルトのリストマーカーを非表示にする際、list-style:none
を指定するケースが殆どだと思いますが、SafariとVoiceOverの組み合わせではlist-style:none
が指定されているリスト要素を「リスト」として認識しないようになっています。
これはVoiceOverの不具合ではなく仕様であり、VoiceOverユーザーから寄せられた「リストが多すぎるためにリストの情報が繰り返し読み上げられるのが煩わしい」というフィードバックに起因しているものです。
例外としてnav
要素内に含まれているlist-style:none
が指定されているリスト要素は「リスト」として認識されます。
とは言え、デフォルトのリストマーカーはスタイリングに制約が大きく、「リスト」として認識されて欲しいけどデザインの都合上list-style:none
を指定するケースが多いのが実情です。この問題の解決策としてlist-style:none
が指定されているリスト要素にrole="list"
を指定する方法が提案されていますが、一般的に暗黙のロールを同一のロールで上書きするのは冗長であるため推奨される方法ではありません。
そういった事情もあり、a11y css resetで取り入れられていてMDNにも記述のあるlist-style-type
に空のSVG要素を指定する方法でリストマーカーは非表示にしつつ「リスト」として認識してもらうようにしていましたが、最近Xにてlist-style-type:""
の指定でも問題を解決できると教えていただいたので穴を突いている感は否めませんが現在はそちらを指定しています。
ただし、SafariとVoiceOverの組み合わせで読み上げられなくなった理由にもある通り実装者はリスト要素の乱用をしがちだということを念頭に入れておくべきでしょう。リスト要素はdisplay:flex
やdisplay:grid
でレイアウトを組むために存在しているわけではないので、それは本当に「リスト」としてマークアップすべきかどうかは慎重に検討したほうが良いと思います。
[id] 属性セレクタに固定ヘッダー分の scroll-margin-block を指定する
ページ内リンクで遷移した際、position:sticky
やposition:fixed
が指定されている固定ヘッダーが存在する場合、ページ内リンクで遷移した際に見出しやコンテンツと被ってしまいます。
[id]
属性セレクタに固定ヘッダーの高さ分のscroll-margin-block
を指定することにより、その分多めにスクロールされるので見出しやコンテンツと被ってしまう問題を解決できます。ついでにフォーカス時の被さりも防止しておくと良さそうです。
これだけだとヘッダーの高さに変動があった際にスクロール位置がズレてしまいかねないので、JSでヘッダーの高さを監視して動的にカスタムプロパティの値を変えるようにしておくと良いでしょう。
動的な監視にはResizeObserver
を使用すると少ない記述量なのにパフォーマンスに優れていて、かつ論理プロパティ(blockSize)で出力してくれるためオススメです。
また、ページ内リンク繋がりでスムーススクロールを実現するためにhtml
要素にscroll-behavior:smooth
を指定する方法が広く普及していますが、僕はこの方法に賛成しておりません。詳細な理由は『スムーススクロールの実装例』にて詳しく解説しているため、そちらを参照してください。
画像の上にテキストを表示する際は文字色と反対の background-color も指定する
img
要素や画像をbackground-image
で指定しているコンテンツの上にテキストを表示する際は文字色と反対のbackground-color
も指定するようにしましょう。
通信障害や万が一のリンク切れで画像の読み込みに失敗しても背景色が設定されていればテキストを読めるようになります。
リンクの下線は位置の調整や色の微調整などを行う
リンクに下線を設ける場合、ディスレクシアの方はテキストと下線が被ると読みにくくなったり、線のバリエーションによっては煩雑になるという問題点が指摘されています。
text-decoration-line
を使用してリンクに下線を設けるのであればtext-underline-offset
やtext-decoration-color
を使用して位置の調整や色の微調整などを行うと良さそうです。
スマートフォン横向き時のテキストの拡大を防ぐために text-size-adjust:100% を指定する
多くの場合リセットCSSに含まれている記述ですが、スマートフォンを縦向き・横向きに切り替えた際に文字サイズを自動調整する機能が働いて意図せないフォントサイズになる場合があります。
そのため、text-size-adjust:100%
を指定して自動調整を無効にしておくことを推奨します。
タブメニューやアコーディオンの非活性コンテンツは hidden=“until-found” 属性で非表示にする
タブメニューやアコーディオンの非活性コンテンツは多くの場合display:none
で非表示にされるケースが多いですが、hidden="until-found"
属性を使用して非表示にするほうが次のようなメリットを享受できます。
- ページ内検索で検出することが可能となり、ヒットした際は自動で
hidden
属性が取り除かれて表示することが可能になる。 - JS無効環境のフォールバックが容易になる。
- Chrome for Developersの文書によれば
hidden="until-found"
が指定された要素内のコンテンツには検索エンジンのロボットもアクセスできるようになるようなので、SEOに良い影響を与える可能性がある。
hidden="until-found"
の詳細や注意点、詳しい使い方については『タブやアコーディオンの非表示コンテンツにはhidden=“until-found”を使うべし』にて詳細に解説しているのでこちらを参照してください。
また、hidden="until-found"
を用いたタブメニューやアコーディオンの実装例については次の項目を参照してください。
ブランド名やコピーライト等の誤翻訳されて欲しくないテキストには translate=“no” 属性を指定する
Google翻訳などの機械翻訳はブランド名やコピーライトなどを上手く翻訳できず、誤った表記で表示される可能性があります。
日本語のブランド名に関してはたとえ誤訳されたとしても翻訳自体はされた方が良いケースもあり、一概にすべてのブランド名とは言えませんが、ロゴやコピーライト等にはtranslate="no"
属性の指定を推奨します。
他にも『テキストを1文字ずつアニメーションさせる時の注意点と実装例』で触れたように、アニメーションの実装でdisplay:inline-block
を指定したspan
要素で文字ごとに区切る際にもtranslate="no"
属性の指定を推奨します。これを怠るとGoogle翻訳はspan
ごとに翻訳する故に支離滅裂な翻訳がされてしまい、更には「し」を”death”と翻訳するなど不穏な文章に化ける可能性もあります。
ただし、至極当たり前のお話ですが、なんでもかんでもtranslate="no"
属性を指定するのは避けて本当に誤翻訳されることを望まない要素のみに指定するようにしましょう。
動的にコンテンツが差し込まれる場合は親要素に contain プロパティを指定することも検討する
contain
プロパティはDOMのレンダリングを開発者側で調整できるようにするパフォーマンス系のプロパティです。指定することでページが効率的にレンダリングされるようにユーザーエージェントに伝えることが可能となります。
静的なコンテンツではそこまで効果を発揮しませんが、コンテンツを動的に差し替える場合はブラウザに再レンダリング部分を指定することができるためパフォーマンスの向上に大きく貢献する可能性があります。
例えば日経電子版では各要素にcontain:content
を付与したところPaint Timeが半分になったとのことです。
ただし、何でもかんでもcontain
プロパティを指定すれば良いというわけではなく、次のデメリットには注意してください。
overflow:hidden
のようにコンテンツを境界の外に表示しなくなります。故に先述したフォーカスリングの消失が起こり得るので注意してください。- 新しいスタッキングコンテキストを生成するので
z-index
の管理には注意してください。 - 子孫要素の
position:fixed
が軒並み無効化されるので気をつけてください。body
要素などに指定するのは避けたほうが良いでしょう。
contain
プロパティの値はプリミティブな値としてsize
,layout
,paint
が存在し、size layout paint
を複合したstrict
とlayout paint
を複合したcontent
が存在します。contain:strict
は扱いが難しいため、原則的にはcontain:content
で問題ないでしょう。
また、上記のデメリットをクリアできるのなら静的なコンテンツで使用するのもアリだと思います。例えば当ブログの記事一覧のサムネイルのように、ホバーしたら画像をscale
で拡大しつつabsolute
でテキストをオーバーレイするといった実装の場合、position:relative
とoverflow:clip
の2つを指定するところをcontain
プロパティ1つで済ませることができます。
フォームの入力欄のオートコンプリートを有効にする
オートコンプリートの利便性は皆さんがよく知っていることでしょうから説明するまでもないかもしれませんが、ブラウザに保存された補完機能を利用できるようになることは次のようなメリットがあります。
- オートコンプリートはユーザーが以前に入力したデータを利用してフォームフィールドを自動的に補完します。ユーザーは何度も同じ情報を入力する手間が省け、入力速度が向上します。
- 手動入力の際に起こりうるタイプミスやフォーマットエラーが減少します。オートコンプリートは正しい情報を提案するため、正確なデータ入力が促進されます。
- 煩雑なフォーム入力が原因でユーザーが途中で離脱するのを防ぎます。オートコンプリートにより入力が簡単になるためフォームの送信完了率が上がります。
- 支援技術を使用しているユーザーもオートコンプリート機能によりスムーズに情報を入力できます。
input
要素にautocomplete
属性を指定してオートコンプリートを有効にすることを推奨します。
主に使用される代表的な項目は次のとおりです。
値 | 補完する内容 |
---|---|
name | 氏名 |
family-name | 名字 |
given-name | 名前 |
tel | 電話番号 |
メールアドレス | |
username | ユーザー名orアカウント名 |
postal-code | 郵便番号 |
address-level1 | 都道府県 |
address-level2 | 市区町村 |
address-level3 | 町域 |
address-level4 | 番地など |
organization | 企業・団体・組織名 |
cc-name | クレジットカード登録名 |
cc-number | カード番号 |
cc-exp | カードの有効期限 |
オートコンプリートを無効にするためにautocomplete="off"
をするケースも考えられますが、現在は殆どのユーザーエージェントで無視されてしまうためオフに設定してもあまり意味がありません。
iframe を埋め込む際は参照元のリンクも用意しておく
これはブログを運営している方向けではありますが、XやCodePen、YouTubeなどの外部サービスをiframe
で埋め込む際は参照元のリンクも用意すると良いでしょう。
Safari等のリーダーモードで表示している場合にiframe
のみだと表示されずに参照元を辿ることができませんが、参照元のリンクも用意しておくと辿ることが可能になります。
また、参照元にアクセスできなくなって埋め込みが無効になった場合に出典に対する動線を確保することもできます。
スクロールバーのカスタムは強制カラーモードが行われていない時に限定する
『スクロールバーにまつわるエトセトラ』でも触れましたが、強制カラーモードが有効な場合にスクロールバーのスタイリングを行うとスクロールバー自体が表示されなくなるリスクがあります。
また、以下のプロパティは、強制カラーモードでは特別な動作をします。
box-shadow は ‘none’ に強制されます
text-shadow は ‘none’ に強制されます
background-image は URL ベースでない値では ‘none’ に強制されます
color-scheme は ‘light dark’ に強制されます
scrollbar-color は ‘auto’ に強制されます
(MDN『forced-colors』より引用)
そのため、forced-colors
メディア特性を使用して、強制カラーモードが有効ではない場合にのみスクロールバーのスタイリングを適応するようにしてください。
また、先程の引用にもあるようにbox-shadow
は強制カラーモード有効下ではnone
に強制される点は留意したほうが良いでしょう。キーボード操作時のフォーカスをより明確にするためにouline
を非表示にして代わりにbox-shadow
でフォーカスリングを実装する方がいらっしゃいますが、その場合強制カラーモード有効下ではフォーカスリングが消失してしまいます。
また、疑似要素を使ったアイコンやUIに関しても消失してしまう可能性があるため注意してください。強制カラーモードの対応に関してはこちらの記事にて解説しています。
一定の画面幅未満ではviewportを固定する
4インチスマートフォンのシェア率は現在ではstatcounterのデータに現れないほどに減少していますが、iPadのSlide OverおよびにSplit Viewの論理サイズは320pxであったり、ガジェット系YouTuberが挙って称賛しているGalaxy Foldなどの折りたたみスマートフォンの一部の画面幅は229px〜320px相当にであるため、現在でも320px以下の画面サイズで見られる可能性はあります。
ただし、375px付近でデザインが作られる現在、4インチ未満の対応は実装コストの割にリターンが小さいのは確かであるため、過去に投稿した記事『俺流レスポンシブコーディング』で紹介した内容ではありますが一定の画面幅未満ではJSでviewportを固定することを推奨します。
現時点で360pxの端末のシェア率が合計6%程度なので、原則的には360px未満はviewportを書き換える方針で問題ないと思います。過去に投稿した内容の変更点としてはdebounce
関数を使ってリサイズイベントの最適化をしています。
Web Storageを使うときは必ず例外をキャッチする
HTML/CSSのテクニックではありませんが、設定でCookieを無効にしている状態でlocalStorage
やsessionStorage
にアクセスするとSecurityError
が発生して処理が止まる可能性があります。
localStorage
やsessionStorage
を読み書きする際はtry...catch
を用いて例外が起きても処理が止まらないようにしましょう。
参考リンク
ドキュメント
- :focus-visible - CSS: カスケーディングスタイルシート | MDN
- display #flow-root - CSS: カスケーディングスタイルシート | MDN
- scrollbar-color | MDN
書籍
技術記事
- フロントエンドの「想定外」に対応する考え方とTipsいくつか | ダーシマ・ヱンヂニヤリング
- 「端っこ」におけるスクロールの挙動を制御する overscroll-behavior プロパティ | ダーシマ・ヱンヂニヤリング
- ユーザーのプリファレンスに応じて過度なアニメーションを無効にする「prefers-reduced-motion」 | Accessible & Usable
- Designing dyslexia-friendly navigational components: accessibility insights and atomic design patterns | UX Collective
- Google翻訳を防ぐtranslate属性はcopyrightには必須! | iwb.jp
- 今どきの入力フォームはこう書く!HTMLコーダーがおさえるべきinputタグの書き方まとめ | ICS Media
- ツイートの埋め込みに元ソースへのリンクを設定するようにした | 富永日記帳
- Don’t use custom CSS scrollbars – Eric Bailey
- 俺流レスポンシブコーディング
- Web Storage API を使う際は Cookie 無効環境も考慮しよう | 富永日記帳
投げ銭機能を追加しました。下の「Support Me」より投げ銭が可能です!