ビデオプレーヤー
グラデーションのポスター上に自作の動画プレーヤーUIを重ねる。中央の再生ボタン、クリックでシークできる進捗バー、経過/総時間、ミュート・全画面のアイコンが揃う。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- 自社デザインに合わせた動画プレーヤー
- ポスター上に再生 UI を重ねるヒーロー
- <video> の標準 UI を置き換えるとき
- 避ける場面
- 標準コントロールで足りる短い動画
- 全画面・字幕など標準機能を多用する場面
- <video> へ結線しない見た目だけの利用
- 構成要素
- ポスター
- 中央の再生ボタン
- シークバー
- 経過/総時間
- ミュート
- 全画面
- 持っている状態
- 通常
- ホバー
- フォーカス
- 押下中
- キーボード
Tab で各ボタンとシークバーに到達。シークバーで←→ 5秒・Home/End で端・Space/Enter で再生切替。ボタンは Enter/Space
- 支援技術
シークは role=slider・aria-valuenow(0〜100)・aria-valuetext(時刻)。再生ボタンの aria-label は再生/一時停止に更新、ミュートと全画面は aria-pressed。svg は aria-hidden
- 動き
中央ボタン 160ms・再生中はホバー時のみ 200ms フェードで表示。進捗は rAF で連続更新。reduce で transition 停止
デザインの要点
- 再生中は中央ボタンを消し、ホバーで戻す。映像の上に大きな UI が居座ると見る邪魔になる
- シークバーは 5px の見た目に上下 8px の padding で 21px の当たり判定を作る。細い線そのものは指で掴めない
- 時間表示は tabular-nums で桁幅を固定する。0:09→0:10 で文字幅が変わると横の要素が毎秒揺れる
- 全画面は requestFullscreen を試し、拒否されたら枠を広げる代替に落とす。iframe や許可なしでは reject される
実装メモ
実際の音声・映像は使わず、JSのタイマーで進捗を進める疑似再生です。実装時は <video> 要素に置き換え、progress の更新を timeupdate、シークを currentTime、時間を duration/currentTime に差し替えてください。全画面は .vp に対する requestFullscreen() で、許可されない環境(sandbox の iframe 等)では枠を広げる .is-full に落とします。ポスターは background の linear-gradient でダミー表現しています。
コード(コピーして使えます)
<div class="vp" id="vp">
<div class="vp-poster" aria-hidden="true">
<div class="vp-orb"></div>
</div>
<button class="vp-center" id="vpCenter" type="button" aria-label="再生">
<svg class="vp-ic-play" width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M7 4.5v15l12-7.5-12-7.5z" fill="currentColor"/>
</svg>
<svg class="vp-ic-pause" width="26" height="26" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<rect x="6" y="4.5" width="4" height="15" rx="1.2" fill="currentColor"/>
<rect x="14" y="4.5" width="4" height="15" rx="1.2" fill="currentColor"/>
</svg>
</button>
<div class="vp-bar">
<div
class="vp-seek"
id="vpSeek"
role="slider"
tabindex="0"
aria-label="再生位置"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
aria-valuetext="0:00 / 3:20"
>
<div class="vp-track">
<div class="vp-buffer"></div>
<div class="vp-fill" id="vpFill"></div>
<div class="vp-knob" id="vpKnob"></div>
</div>
</div>
<div class="vp-row">
<button class="vp-mini" id="vpToggle" type="button" aria-label="再生">
<svg class="vp-ic-play" width="15" height="15" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M7 4.5v15l12-7.5-12-7.5z" fill="currentColor"/>
</svg>
<svg class="vp-ic-pause" width="15" height="15" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<rect x="6" y="4.5" width="4" height="15" rx="1.2" fill="currentColor"/>
<rect x="14" y="4.5" width="4" height="15" rx="1.2" fill="currentColor"/>
</svg>
</button>
<span class="vp-time"><span id="vpCur">0:00</span> / <span id="vpDur">3:20</span></span>
<span class="vp-spacer"></span>
<button class="vp-mini" id="vpMute" type="button" aria-label="ミュート" aria-pressed="false">
<svg class="vp-ic-vol" width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 9v6h3.5L12 19V5L7.5 9H4z" fill="currentColor"/>
<path d="M15.5 8.5a5 5 0 010 7M17.5 6a8.5 8.5 0 010 12" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
</svg>
<svg class="vp-ic-muted" width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 9v6h3.5L12 19V5L7.5 9H4z" fill="currentColor"/>
<path d="M16 9.5l5 5M21 9.5l-5 5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</button>
<button class="vp-mini" id="vpFull" type="button" aria-label="全画面" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
</div>