Встроенный ролик с YouTube, VK или Rutube — это iframe с чужим плеером. И этот плеер начинает грузить мегабайты скриптов, стилей и превью сразу, как только iframe оказался в странице, — задолго до того, как кто-то нажмёт «плей». Три ролика на странице — три полноценных чужих приложения в окне первой отрисовки.
Это тридцать четвёртая, заключительная часть цикла «PageSpeed без мифов».
Решение: картинка вместо плеера
Приём называют «фасадом»: на странице — плитка с превью ролика и кнопкой «плей». Сама плитка — обычная картинка (с размерами, ленивой загрузкой, в нужном формате — всё, о чём шла речь в части про картинки). Плеер подставляется только по клику.
До клика — ноль чужих скриптов. Посетитель разницы не замечает: он видит превью и кнопку, как и раньше.
Тонкость: видео должно пойти с первого клика
Если по клику просто вставить iframe, посетитель увидит плеер со своей кнопкой «плей» — и ему придётся нажать второй раз. Это раздражает и выглядит как баг. Нужно сразу запустить ролик, и у каждого видеохостинга это делается по-своему:
| Хостинг | Как запустить сразу |
|---|---|
| YouTube | параметр autoplay=1 в адресе плеера (плюс playsinline=1 для iPhone) |
| VK Видео | параметр autoplay=1; плеер живёт на двух доменах — vk.com/video_ext.php и vkvideo.ru/video_ext.php, проверять оба |
| Rutube | параметров автозапуска в адресе нет — только API сообщений: дождаться от плеера player:ready и отправить player:play |
Клик по плитке — это жест посетителя, а атрибут allow="autoplay" передаёт iframe право стартовать. На iPhone всё равно проверяйте на устройстве: правила автозапуска там строже.
// плитка с превью → iframe плеера по клику, с запуском с первого нажатия
function playerUrl(url) {
let m;
if ((m = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([\w-]{11})/)) || /^[\w-]{11}$/.test(url)) {
const id = m ? m[1] : url; // в админке часто лежит голый id ролика
return `https://www.youtube.com/embed/${id}?autoplay=1&playsinline=1`;
}
if (/(?:vk\.com|vkvideo\.ru)\/video_ext\.php/.test(url)) { // у VK два домена плеера
return url + (url.includes("?") ? "&" : "?") + "autoplay=1";
}
return url; // Rutube — запуск только через postMessage, см. ниже
}
document.querySelectorAll(".videoTile").forEach(tile => tile.addEventListener("click", () => {
const iframe = document.createElement("iframe");
iframe.src = playerUrl(tile.dataset.video);
iframe.allow = "autoplay; fullscreen; picture-in-picture";
iframe.allowFullscreen = true;
tile.replaceChildren(iframe);
if (/rutube\.ru/.test(iframe.src)) autoplayRutube(iframe);
}, { once: true }));
function autoplayRutube(iframe) {
addEventListener("message", function onMsg(e) {
if (e.source !== iframe.contentWindow) return;
let msg; try { msg = JSON.parse(e.data); } catch { return; }
if (msg.type === "player:ready") {
iframe.contentWindow.postMessage(JSON.stringify({ type: "player:play", data: {} }), "*");
removeEventListener("message", onMsg);
}
});
}
Грабли, на которые мы наступили
- Голый id в админке. Контент-менеджеры часто вставляют не ссылку, а только идентификатор ролика YouTube. Старый код подставлял его в iframe как есть — и открывал несуществующую страницу сайта. Распознавайте оба варианта.
- Второй домен VK. На тестовом сайте ролики были на
vk.com, на боевом — наvkvideo.ru. Проверка только первого домена прод не поймала, пришлось выкатывать второй раз. - Rutube не понимает параметры. Мы перепробовали
autoplay=1,autoStart=1,autoStart=true— бесполезно. Работает только API сообщений.
Конец цикла — и что дальше
На этом цикл «PageSpeed без мифов» закончен: от того, как модель считает оценку, через окно первой отрисовки, шрифты, картинки и CSS до сторонних скриптов. Главная мысль всех 34 частей одна: оценку определяет не вес страницы, а то, что попадает в окно до первой отрисовки, и честная оптимизация — это правильный порядок загрузки, а не прятанье контента от проверки.
Следующий цикл — про кэширование: как отдавать страницы мгновенно и не показывать посетителю устаревшее. Подпишитесь, чтобы не пропустить.
Хотите применить цикл к своему сайту?
Пришлите адрес — пройду по всем пунктам и скажу, что даст больше всего.
// загружаю комментарии…