Safariでvideoのmedia判定が不安定になる原因と対処
Safariでvideoのmedia条件によるsourceの出し分けが、意図通りに動作しないケースがありました。
原因は実装ではなく、Safariの判定タイミングによるものだと思います。
本記事では、その原因と対処方法をまとめます。
目次
問題の構成
今回問題となった動画はメインビジュアルで使用されており、780px以上の時はPC動画、それ以外の時はSP動画が表示されます。
<video autoplay muted loop playsinline>
<source src="../assets/images/pc/mv.mp4" media="(min-width: 780px)" type="video/mp4">
<source src="../assets/images/sp/mv.mp4" type="video/mp4">
</video>しかし、Safariではmedia属性の条件が適用されず、常にSP動画(デフォルトのsource)が再生されてしまいます。
リロードで稀に正常になることがあるものの安定はしません。
原因の特定
headタグ内はシンプルで、CSSファイルとJSファイルを1枚ずつ読み込んでいるだけです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<!-- css -->
<link rel="stylesheet" href="../assets/css/style.css">
<!-- js -->
<script src="../assets/js/main.js" defer></script>
</head>検証を進める中で、scriptタグのdefer属性を外すと、正常に表示されるケースが増えることがわかりました。
おそらくこう
Safariの内部挙動
- HTML解析開始
- video発見
- 即座に
source選択を開始(←ここが早すぎる?) - まだCSSやviewport完全確定してない
- media判定が曖昧 → SP動画を選択
なぜdeferを外すと改善するか
- scriptが解析中に実行される
- video評価との順序が変わる
- 結果として正しく判定されるケースが増える
改善案
JSで制御する
フォールバックとして、JavaScriptでvideoのsourceを切り替えます。
// Safariでvideoのmedia判定が不安定なため、JSで動画を明示的に切り替える
const v = document.querySelector('.mv video');
const mq = matchMedia('(min-width: 780px)');
if (v) {
const set = () => {
v.src = mq.matches
? '../assets/images/pc/mv.mp4'
: '../assets/images/sp/mv.mp4';
v.load();
};
set();
mq.addEventListener('change', set);
}load()で動画の再読み込みを明示的に行うchangeイベントで画面幅変更にも対応
CSSで切り替える
メディア属性を使わずCSSで動画を切り替える方法です。
<div class="mv">
<video class="is-pc" autoplay muted loop playsinline src="../assets/images/pc/mv.mp4"></video>
<video class="is-sp" autoplay muted loop playsinline src="../assets/images/sp/mv.mp4"></video>
</div>.is-pc { display: none; }
.is-sp { display: block; }
@media (min-width: 780px) {
.is-pc { display: block; }
.is-sp { display: none; }
}複数の動画を同時に読み込むためパフォーマンスは落ちますが、JS無効環境でも確実に切り替えが可能です。
補足:リロードによる対応
※上記のアプローチを採用している場合は不要です。
videoタグはページ読み込み後に画面幅が変わってもsourceを切り替えてくれないので、タブレットの向き変更などで表示が崩れることがあります。
例:PCは横長動画、スマホでは縦長動画など
そういったケースでは、画面幅の変化を検知してリロードさせるのが良いかもしれません。
// 特定の画面幅でリロード(video sorce切り替えのため)
const mq = window.matchMedia("(min-width: 780px)");
mq.addEventListener("change", () => {
location.reload();
});Safariのバグ?
最終的に解決はできたものの、根本的な原因は不明なため、少しモヤッとしてしましますね。
一応記録として残しておきます。
あわせて読みたい


【CSS】Safariでfilterプロパティの描写がうまくいかない場合の対処法
iOSのSafariで、filter:drop-shadowの描写が途切れたり、うまく表示されない場合があります。 今回はその対処法を記しておきます。 よく使うfilterプロパティ filterプ…
カスタマイズに困ったらお気軽にご相談を!
- 「ちょっとしたCSSの調整だけお願いしたい」
- 「不具合を直してほしい」
料金は3,000円〜、お支払いは銀行振込・Amazonギフトカードなど柔軟に対応してます🤔
お気軽にコメントどうぞ