【実務・中級編】 ::cue 擬似要素による字幕のスタイリング – CSS実践ガイド

やあ。今日も今日とてCSSの沼にハマっているかい?
フロントエンドをやっていると、「これ、デザインカンプ通りにブラウザがレンダリングしてくれないんだけど……」っていう絶望的な壁に何度もぶつかるよね。特に、メディア周り。`

今回は、その中でも特に「アクセシビリティの要」でありながら、多くの開発者がスタイリングをあきらめがちな字幕(WebVTT)の領域に切り込む。テーマは `::cue` 擬似要素 だ。

「ただ文字を出すだけだろ?」なんて思ってたら大間違い。実はこの `::cue`、ブラウザの内部実装や仕様のクセを理解していないと、マルチブラウザでデザインが盛大に崩れる地雷原でもあるんだ。
シニアとして、現場で即座に使える「生きた知見」を全部置いていくから、しっかりついてきてほしい。

—

そもそも `::cue` とは何か?ブラウザの裏側の話

まず、仕様の話を軽くしておこう。
`::cue` は、`

ここで一つ、フロントエンドエンジニアとして知っておくべき「ブラウザの裏側の現実」がある。
通常、私たちが書くCSSは、DOMツリーの要素に対して適用されるよね。しかし、`

つまり、普通に `.my-video span` なんて書いても、字幕には一切スタイルが当たらない。なぜなら、その要素は外部のCSSから隠蔽されているからだ。
そこで登場するのが `::cue`。こいつは、「通常の世界からシャドウツリーの向こう側へ介入するための数少ない特権的なパスポート」なんだ。

—

現場で使える! `::cue` の基本と適用可能なプロパティ

「よし、じゃあ何でもかんでもスタイリングできるぜ!」と意気込みたいところだが、実は `::cue` には適用できるCSSプロパティに強烈な制限がある。

CSSのフルパワーが使えるわけじゃない。仕様上、安全に(そしてブラウザの描画エンジンがクラッシュしないように)使えるプロパティは限られている。実務でよく使う安全なプロパティを挙げておこう。

  • `color` / `background-color`
  • `font-family` / `font-size` / `font-weight` / `font-style`
  • `text-shadow` / `text-decoration`
  • `opacity`

レイアウト系(`display` や `width`、`margin` など)の多くは、字幕の配置アルゴリズムと競合するため、指定しても無視されるか、期待しない挙動になることが多い。この「制限されている」という事実を忘れないことが、無駄なデバッグ時間を生まないコツだ。

基本のコード例

百聞は一見にしかず。まずは、NetflixやYouTubeのような、モダンでリッチな動画プレイヤーに馴染む、鉄板の字幕スタイリングを見てみよう。

/ 1. 字幕全体の基本スタイル(視認性を高めるための定番設定) /
video::cue {
/ フォントは洗練されたゴシック系を指定、かつ読みやすくする /
font-family: “Helvetica Neue”, Arial, sans-serif;
font-size: 1.1rem;

/ Netflixの字幕っぽく、文字色を真っ白に /
color: #ffffff;

/ 生の背景色だと四角くなってダサいので、テキストシャドウで浮かせるのがプロの技 /
background-color: transparent;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000,
0 2px 4px rgba(0, 0, 0, 0.9);
}

この `text-shadow` の重ねがけ、いいテクニックだろ?
背景に半透明の黒帯(`background-color: rgba(0,0,0,0.6)`)を敷くのも悪くないんだけど、動画の雰囲気を邪魔したくないデザインの場合は、この「多重シャドウによる縁取り」が圧倒的にリッチに見える。覚えておいて損はない。

—

さらに踏み込む:特定の話者や部分的なスタイリング

WebVTTファイル側でタグ(`こんにちは` や `太字` など)を使っている場合、`::cue` にセレクタを追加して、さらに詳細な制御ができる。ここが実務で一番感動するポイントだ。

例えば、対話形式の動画で、話者ごとに字幕の色を変えたいケース。

CSS側

/ デフォルトの字幕 /
video::cue {
color: #ffffff;
background-color: rgba(0, 0, 0, 0.7);
padding: 0.2em 0.4em;
border-radius: 4px;
}

/ 話者A(インタビュアー)のセリフは少し色を変える /
video::cue(v[voice=”Interviewer”]) {
color: #60a5fa; / 爽やかなブルー /
}

/ 強調(bタグ)が入った部分だけ黄色にする /
video::cue(b) {
color: #facc15;
font-weight: bold;
}

WebVTT(字幕ファイル)側

WEBVTT

00:00:01.000 –> 00:00:04.000
本日はお時間をいただきありがとうございます。

00:00:04.500 –> 00:00:08.000
こちらこそ、今日は重要なお知らせがあります。

どうだろう? このように `::cue(v[voice=”…”])` のように書くことで、字幕データ側とCSS側を美しく連携させることができる。動画コンテンツのクオリティが一気に「プロのプロダクト」のそれに引き上げられる瞬間だね。

—

シニアからの警告:ブラウザごとの闇とハック

最後に、実務で絶対にハマる「罠」について共有しておく。

Safari、Chrome、Firefox……これらモダンブラウザのシェアを占めるエンジンたちだが、Shadow DOMの内部構造や `::cue` の解釈には、いまだに微妙な差異がある。
特に、Safariは独自のデフォルトスタイルを強烈に持っていることが多く、CSSでリセットしきれないパディングや背景が勝手に付与されることがある。

そんなときの現場の荒技(ワークアラウンド)として、もしデザインの完全一致がどうしても求められる場合は、無理にネイティブの `` と `::cue` に頼るのをやめ、JavaScriptで `video.currentTime` を監視し、独自のカスタムDOMレイヤーを動画の上に重ねて字幕をレンダリングするというアーキテクチャを選択することもある。

「ネイティブのアクセシビリティを取るか、ピクセルパーフェクトなデザインを取るか」
このトレードオフに直面したとき、クライアントやディレクターと冷静に議論できるのが、中級からシニアへステップアップする鍵だ。

まずは今回紹介した `::cue` の基本と、シャドウツリーへのアプローチ方法を自分の引き出しにしっかり入れておいてほしい。実務でのコードレビューで、後輩から「すげえ、こんなところまでスタイリングできるんだ!」って言われること間違いなしだからさ。

それじゃ、また次のコードレビューの現場で会おう。いいCSSライフを!

コメント

タイトルとURLをコピーしました