Тег source (от английского source, «источник») задаёт один вариант файла для своего родителя: video, audio или picture. Сам он ничего не показывает: браузер читает его атрибуты и решает, брать этот файл или перейти к следующему. Тег пустой, содержимого у него нет, а закрывающий тег не нужен.
Что именно делает source, зависит от родителя. В video и audio работают src и type, и браузер перебирает теги сверху вниз, пока не найдёт файл, который сможет открыть. В picture работают srcset, sizes, media и type, а выбор строится по условиям. Контейнер picture разобран на странице о теге picture, поэтому здесь о нём только то, что нужно для работы самого source.
<video controls>
<source src="film.webm" type="video/webm">
<source src="film.mp4" type="video/mp4">
</video>
В этой статье
- Тег source в HTML: что это и где его можно использовать
- Атрибуты src и type у тега source в video и audio
- Порядок тегов source в video и audio: что будет, если файл не открылся
- Атрибут srcset у тега source в picture: дескрипторы x и w
- Атрибут sizes у тега source: как браузер выбирает файл по ширине
- Атрибуты тега source: какие работают в video, audio и picture
- Тег source в JavaScript: src, srcset и метод load()
Тег source в HTML: что это и где его можно использовать
Сначала о том, в каких родителях тег работает и что у него общего во всех случаях.
Допустимых родителей три: video, audio и picture. В любом другом месте, например в div или в body, тег ничего не выбирает и не загружает, браузер его просто не использует. Все source записывают в начале родителя: в picture до img, в video и audio до track. Такой порядок требует стандарт.
<picture>
<source srcset="kot.webp" type="image/webp">
<img src="kot.jpg" alt="Кот">
</picture>
<audio controls>
<source src="song.ogg" type="audio/ogg">
<source src="song.mp3" type="audio/mpeg">
</audio>
<div>
<source src="film.webm" type="video/webm">
</div>
Пример: где source выбирает файл, а где нет
Переключайте кнопки: для video, audio и picture браузер показывает выбранный файл, а в div выбирать нечего. Файлы встроены в пример, буква или надпись показывает, какой из них взят.
Тег поддерживается всеми браузерами: по данным справочника MDN, он доступен с июля 2015 года. Подробное описание есть и в стандарте HTML.
Атрибуты src и type у тега source в video и audio
В видео и звуке тег описывает файл двумя атрибутами: адресом и типом.
Атрибут src задаёт адрес файла, и здесь он обязателен: без него source пропускается. Атрибут type сообщает браузеру формат файла в виде MIME-типа, при желании с кодеками после точки с запятой. Если браузер не умеет воспроизводить такой формат, он пропускает тег, не скачивая файл. Без type браузер сначала обратится к файлу, а уже потом поймёт, что открыть его не сможет.
<video controls>
<source src="a.mp4"
type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
<source src="a.webm"
type='video/webm; codecs="vp9, opus"'>
</video>
Значение type | Что за формат | Пример записи |
|---|---|---|
video/webm | Видео в контейнере WebM (VP8, VP9, AV1) | src="a.webm" type="video/webm" |
video/mp4 | Видео в контейнере MP4 (чаще всего H.264) | src="a.mp4" type="video/mp4" |
video/ogg | Видео в контейнере Ogg (Theora) | src="a.ogv" type="video/ogg" |
audio/mpeg | Звук MP3 | src="a.mp3" type="audio/mpeg" |
audio/ogg | Звук в контейнере Ogg (Vorbis, Opus) | src="a.ogg" type="audio/ogg" |
audio/wav | Несжатый звук WAV | src="a.wav" type="audio/wav" |
Чтобы узнать, какие типы понимает браузер, используют метод canPlayType. Он возвращает строку probably («скорее всего играет»), maybe («возможно играет») или пустую строку. Набор форматов зависит от браузера и установленных кодеков, поэтому таблица ниже у каждого читателя получится своей.
const video = document.createElement("video");
console.log(video.canPlayType("video/webm"));
console.log(video.canPlayType('video/mp4; codecs="avc1.42E01E"'));
Пример: что вернёт canPlayType для разных type
Таблица строится прямо сейчас вашим браузером. Строки с пустым ответом показывают type, из-за которых тег source был бы пропущен.
Заявленный type браузер проверяет только при выборе. После загрузки он определяет формат по самому файлу. Поэтому неверный type не ломает файл, но из-за него браузер может пропустить тег, который подошёл бы.
Порядок тегов source в video и audio: что будет, если файл не открылся
Когда у видео или звука несколько тегов, браузер идёт по ним сверху вниз и останавливается на первом рабочем.
Для каждого source браузер сначала смотрит на атрибуты: нет src, не подходит type или media, тег пропускается без загрузки. Если условия выполнены, он загружает файл. Не нашёлся адрес или формат не удалось разобрать, берётся следующий source. Берётся первый рабочий, остальные не загружаются. В этом главное отличие от picture: там выбор делается один раз по условиям, и если выбранный файл не загрузился, браузер к следующему не переходит.
<video controls>
<source src="film.mp4" type="video/mp4">
<source src="film.webm" type="video/webm">
</video>
Пример: перебор source в video и в picture
В первых четырёх сценариях строится настоящий video, и под ним видно, какой файл выбран и на каком source сработало событие error. Последний сценарий показывает picture, где перебора нет.
| Ситуация | Что делает браузер | Пример записи |
|---|---|---|
| Файл не существует или не открывается | Событие error на этом source, потом берётся следующий | src="broken.webm" |
type не подходит браузеру | Файл не скачивается, на source всё равно приходит error | src="a.webm" type="video/foo" |
У video есть свой src | Все source внутри игнорируются | <video src="b.webm"> |
| Не открылся ни один файл | У video нет события error, networkState равен 3, а video.error пуст | src="x.webm" и src="y.webm" |
Число networkState, равное 3, означает, что подходящего источника нет. Это единственный признак: страница никак не сообщит, что ролик не показан, пока вы сами не проверите состояние или не подпишетесь на событие error у последнего source.
Атрибут srcset у тега source в picture: дескрипторы x и w
В picture список файлов записывают в srcset, и у каждого файла есть дескриптор: плотность или ширина.
Значение srcset состоит из вариантов через запятую: адрес файла и дескриптор. Дескриптор x означает плотность пикселей экрана: 2x для файла, который нужен экрану с удвоенной плотностью. Запись без дескриптора считается 1x. Chrome берёт ближайший вариант, который не меньше плотности экрана, а если таких нет, самый большой.
<picture>
<source srcset="kot-1x.png, kot-2x.png 2x, kot-3x.png 3x">
<img src="kot-1x.png" alt="Кот">
</picture>
Пример: выбор файла по плотности пикселей
Кнопки меняют набор вариантов в srcset. Плотность в примере берётся у вашего экрана, а масштаб страницы клавишами Ctrl и плюс её меняет.
| Пример записи | Плотность 1 | Плотность 2 | Плотность 3 |
|---|---|---|---|
srcset="1x.png 1x, 2x.png 2x, 3x.png 3x" | 1x | 2x | 3x |
srcset="1x.png 1x, 3x.png 3x" | 1x | 3x | 3x |
srcset="2x.png 2x, 3x.png 3x" | 2x | 2x | 3x |
Дескриптор w указывает ширину самого файла в пикселях, например 800w. Его записывают вместе с sizes, о котором дальше: без него валидатор сообщит об ошибке, а браузер возьмёт 100vw. Смешивать в одном srcset дескрипторы x и w нельзя, так требует стандарт. Пустой srcset делает тег бесполезным: браузер пропускает такой source и показывает файл из img. Те же правила действуют и у самого img, подробнее о них на странице о теге img.
Атрибут sizes у тега source: как браузер выбирает файл по ширине
Дескриптор w говорит, какой ширины файл, а sizes говорит, какую ширину займёт картинка на странице.
Значение sizes — это список через запятую: условие в скобках и ширина, а в конце ширина без условия. Браузер берёт первую подходящую ширину, умножает её на плотность экрана и выбирает самый маленький файл, у которого w не меньше полученного числа. Если подходящего нет, берётся самый большой. Без sizes считается 100vw, то есть вся ширина окна, даже если картинка на странице уже.
<picture>
<source
srcset="kot-400.jpg 400w,
kot-800.jpg 800w,
kot-1200.jpg 1200w"
sizes="(min-width: 600px) 50vw, 100vw">
<img src="kot-800.jpg" alt="Кот" width="800" height="600">
</picture>
Пример: выбор файла по ширине окна и sizes
Ширина окна имитируется скрытой рамкой, поэтому можно проверить окна любой ширины. Плотность пикселей берётся у вашего экрана, и от неё зависит, какой файл будет выбран.
| Пример записи | Место под картинку | Файл при окне 800 px, плотность 1 |
|---|---|---|
sizes="(min-width: 600px) 50vw, 100vw" | 400 px | 400w |
sizes не записан | 800 px (100vw) | 800w |
sizes="300px" | 300 px | 400w |
sizes="calc(100vw - 200px)" | 600 px | 800w |
Если значение sizes записано с ошибкой, браузер возвращается к 100vw. Атрибут sizes у img внутри picture в этом случае не помогает: когда source подошёл, ширину берут только из него. При увеличении окна Chrome подгружает более крупный файл без перезагрузки страницы, а обратно на меньший не переключается. Условия для выбора самого source по типу экрана и теме записывают в media, это разобрано на странице о теге picture.
Атрибуты тега source: какие работают в video, audio и picture
У тега семь собственных атрибутов, но каждый из них относится только к одному или двум родителям.
Кроме них допустимы глобальные атрибуты вроде class и id. В таблице видно, какие атрибуты действуют в video и audio, а какие в picture.
| Атрибут | В video и audio | В picture | Пример записи |
|---|---|---|---|
src | Работает | Не действует | src="a.webm" |
type | Работает | Работает | srcset="a.avif" type="image/avif" |
srcset | Не действует | Работает | srcset="a-1x.jpg, a-2x.jpg 2x" |
sizes | Не действует | Работает | srcset="a.jpg 800w" sizes="50vw" |
media | Работает (в Chrome) | Работает | srcset="a.jpg" media="(min-width: 600px)" |
width | Не действует | Работает | srcset="a.jpg" width="800" height="450" |
height | Не действует | Работает | srcset="a.jpg" width="800" height="450" |
Пример: какие атрибуты source не действуют
Три кнопки строят тег с атрибутом, который у этого родителя не читается. Выбранный файл показывает, какой source браузер пропустил.
Атрибуты width и height в picture помогают браузеру заранее узнать пропорции выбранного кадра, об этом подробно на странице о теге picture. Стандарт допускает media и в video, и Chrome пропускает там тег с неподходящим условием, но MDN советует использовать его только в picture, поэтому рассчитывать на это не стоит: файл для видео подбирайте по type и порядку.
Тег source в JavaScript: src, srcset и метод load()
Скрипт может создавать теги source и менять их, но браузер реагирует на такие изменения не сразу.
У объекта тега те же свойства, что и атрибуты: src, type, srcset, sizes, media, width и height. Если добавить source в пустой video, браузер сам начнёт выбор. Когда файл уже выбран, смена src у тега ничего не меняет, как и добавление нового тега перед ним. Чтобы выбор прошёл заново, у video вызывают метод load(). Он нужен и после того, как не открылся ни один файл: добавленный позже source сам по себе ничего не запускает.
const video = document.querySelector("video");
const source = video.querySelector("source");
source.src = "film2.webm";
video.load();
console.log(video.currentSrc);
Пример: когда браузер замечает изменение source
Кнопки по очереди строят пустой video, добавляют тег и меняют его. Журнал под видео запоминает, какой файл был выбран после каждого действия.
В picture всё иначе: если сменить srcset у source, картинка обновится сразу. А вот присвоение img.src игнорируется, пока подходит хоть один source. Узнать выбранный файл можно в свойстве currentSrc: у video и audio оно есть у самого элемента, у picture его читают у вложенного img.
Частые ошибки с тегом source
Большая часть сбоев с этим тегом связана с родителем, порядком и атрибутами, которые у него не читаются.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
<div><source src="a.webm"></div> | Тег вне video, audio и picture ничего не делает | Записать source внутрь нужного родителя |
<source src="a.webm"></source> | Закрывающий тег для пустого элемента считается ошибкой разметки | Писать только открывающий тег |
<source src="a.webp"> | В picture атрибут src не читается, тег пропущен | Заменить на srcset="a.webp" |
<source srcset="a.webm"> | В video атрибут srcset не читается, тег пропущен | Заменить на src="a.webm" |
<source src="a.mp4"> | Без type браузер сначала обращается к файлу и только потом узнаёт, что не умеет его открыть | Добавить type="video/mp4" |
<video src="b.webm"> | Если у video есть src, теги внутри игнорируются | Убрать src у video и записать файлы тегами |
<source srcset="a.jpg 400w, b.jpg 800w"> | Без sizes считается 100vw, и выбирается файл больше нужного | Добавить sizes с реальной шириной картинки |
srcset="a.jpg 1x, b.jpg 800w" | Смешаны дескрипторы x и w, стандарт это запрещает | Использовать один вид дескрипторов |
source.src = "b.webm" | После выбора файла смена src ничего не меняет | Вызвать у video метод load() |
Ожидание события error у video | Когда не открылись все файлы, у video события нет, оно приходит на каждый source | Слушать error у последнего source |
<img ...><source ...> | В picture тег после img игнорируется | Записать все source до img |