フロントエンドの現場で日々コードを書いていると、「画面のデザインは完璧に仕上げたのに、ユーザーが入力するテキストエリアのネイティブな挙動までは制御しきれない……」という壁にぶつかることがよくある。特に、ブラウザが標準で持つスペルチェック機能が暴発して、意図しない赤い波線がテキストに表示されるのを見たことはないだろうか。
「なんだかカッコ悪いから消したい」「いや、むしろブランドカラーに合わせてスタイリッシュに赤線ではなく青い波線にしたい」――中級から一歩抜け出そうとするエンジニアなら、一度はそう思ったことがあるはずだ。
今回は、そんなブラウザのネイティブ機能にCSSで正面から立ち向かえる、`::spelling-error` 擬似要素について、実務の現場目線で徹底的に解説しよう。
—
そもそも `::spelling-error` とは何か?
`::spelling-error` は、ブラウザのスペルチェッカー(OSやブラウザが持つ辞書機能)によって「スペルミス」と判定されたテキスト範囲にスタイルを適用するためのCSSの実験的(あるいは策定が進む)擬似要素だ。
これまで、ブラウザが自動で付与するスペルミスの波線(アンダーライン)の色やスタイルを制御するのは、JavaScriptでDOMを無理やり書き換えるか、ブラウザの言語設定に頼るしかなかった。しかし、この擬似要素を使えば、CSSのスコープ内でネイティブのスペルミス表示をコントロールできるようになる。
スタイリングの「厳しい」制限を知る
さて、ここでシニアとして君臨する私から、現実の冷徹な仕様の壁を伝えておかなければならない。CSSのあらゆるプロパティが使えるわけではないのだ。ブラウザのセキュリティやネイティブUIの整合性を守るため、`::spelling-error`(および類似の `::grammar-error`)で使用できるCSSプロパティは、極めて限定的である。
具体的に変更できるのは、主に以下のプロパティ周辺に限られる。
- `color`(テキスト自体の色)
- `background-color`(背景色)
- `text-decoration` 関連(波線の色、スタイル、太さなど)
- `text-shadow`
レイアウトを崩すような `display` や `margin`、`padding` などのプロパティは当然ながら一切効かない。あくまで「ブラウザが指摘した誤字箇所の見た目を調整する」ためのものだと心得ておいてほしい。
—
ブラウザの裏側の動きと実務での注意点
ここで少し、ブラウザが裏側でどう処理しているかという話をしよう。
スペルチェックは、DOMツリーのテキストノードに対して、ブラウザのエンジン(BlinkやWebkitなど)がバックグラウンドで走査を行っている。ユーザーがタイピングするたびに、OSのネイティブAPIや内蔵辞書と突合し、「おっと、この単語は辞書にないぞ」と判定された瞬間に、ブラウザ側が動的に内部的なハイライト範囲をマークする。
`::spelling-error` は、その「ブラウザが勝手にマークした隠し範囲」をキャッチしてスタイルを上書きする仕組みだ。
現場で直面する「罠」
1. ブラウザサポートのバラつき: この手のUI関連の疑似要素は、WebKit/Blink系(Chrome, Safari, Edgeなど)とGecko系(Firefox)で実装状況やデフォルトの挙動が微妙に異なる。本番環境に投入する前には、必ず主要ブラウザでの実機確認が必要だ。
2. contenteditable と textarea の違い: `textarea` や `input` の内部のテキストに対して直接この擬似要素が効くかどうかは、ブラウザのレンダリングエンジンの実装に強く依存する。多くの場合、`contenteditable` を付与したリッチテキストエディタの文脈で真価を発揮する。
—
コピペで使える!実践的コードスニペット
百聞は一見にしかずだ。実際のプロジェクトですぐに検証できるよう、リッチテキストエディタやコメント入力欄を想定したスタイリングのサンプルコードを用意した。
/ ————————————————————————– /
/ contenteditable属性を持つエディタ領域のベース設定 /
/ ————————————————————————– /
.editor-container {
width: 100%;
min-height: 200px;
padding: 16px;
font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, sans-serif;
font-size: 1rem;
line-height: 1.6;
color: #333333;
background-color: #ffffff;
border: 1px solid #cbd5e1;
border-radius: 8px;
outline: none;
resize: vertical;
}
.editor-container:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}
/ ————————————————————————– /
/ ::spelling-error を使ったカスタムスタイリング /
/ ————————————————————————– /
/
ブラウザ標準の赤い波線を、プロダクトのトーン&マナーに合わせて
「ブランドカラーのオレンジの波線」に変更しつつ、背景色を薄くハイライトする
/
.editor-container::spelling-error {
/ テキスト自体の色は変えずにそのままにする(視認性維持のため) /
color: inherit;
/ 指摘箇所を薄いオレンジで背景ハイライト /
background-color: rgba(249, 115, 22, 0.1);
/ ネイティブの波線の色やスタイルを強制上書き(対応ブラウザ向け) /
text-decoration: underline wavy #f97316;
text-decoration-thickness: 2px;
}
/ ついでに文法エラー(::grammar-error)も同じ世界観で統一しておく /
.editor-container::grammar-error {
color: inherit;
background-color: rgba(59, 130, 246, 0.1);
text-decoration: underline wavy #3b82f6;
text-decoration-thickness: 2px;
}
HTML側のマークアップ例
—
シニアからの実務アドバイス
この `::spelling-error` を使うときの最大の判断基準は、「そのスペルミス表示が、ユーザーの入力体験を邪魔していないか」だ。
例えば、社内向けの業務システムや、専門用語(IT用語や医療用語など)が飛び交う入力フォームでは、ブラウザの辞書がそれらを「スペルミス」と誤判定してしまい、画面中が赤い波いだらけになるという大惨事がよく起きる。ユーザービリティの観点から、プロダクトの性質によっては `spellcheck=”false”` をHTML側で完全に切ってしまう方が正解なケースも多い。
しかし、英語圏向けのグローバルなSaaSや、一般的なテキスト入力を扱うサービスであれば、こうした細かいディテール(ブラウザ標準のダサい赤線を、サービスのブランドカラーに合わせた上品な波線に変えるなど)の積み重ねが、プロダクト全体の「品質の高さ」を決定づける。
仕様の制限とブラウザの挙動を正しく理解した上で、ここぞという場面でこの擬似要素を使いこなしてほしい。君の書くUIのクオリティが、一段階引き上がるはずだ。

コメント