Запобежчанне кумуляatyвным зсувам раскладкі за дапомогою відеа-фону у Next.js
Выучыце практычныя тэхнікі CSS і структуравання, каб запобiec таму, што відэа на фоне ў Next.js спрычыняла кумуляatywnыя змены распакоўкі на разных прыстроях і з разной шыроцай сяброў.
Існуе спецыяльны тип бага фронтэнду, які залічваецца невидным пад час разработкі за ідеальных умаўлянняў, але як толькі спадае швальнасць сеті, відэа на фоне, якое вы дадалі, пачынае спрычыняць рывкі на сторанцы, як у хаотычнай сцэне сіткому.
Празважанні: вы ўжо зустрэліся з явам Кумуляatywnага схылу лейауту.
Відэа на фоне лёгкая пераходзіць зарады адзінакоў перагляду, таму што яны знаходзяцца на фоне, яны нормальна працуюць пад швайной з’яўленнёй, а інжынеры часта спрыягліваюць відэа як чыста візуальны слой, а не як элемент, який берае участак у лейауте сторанцы.
Аднак браузер не падтрымлівае нашыя прыпускі. Калі размер элемента не вядомы пад час першага атрыбутавання, браузер вынужаны ўгадваць. А саме гадкі ёсць тое, чаго вы не хочаце, каб яно вплывала на рашэнняя па лейауту.
Калі гэты контекст вядомы, давайце перейдзем да тэхнічных деталяў.
Асалідныя правілы: Звярнуце прастор да запуску відэа
Cumulative Layout Shift паказывае, насколькі видны кантэнт неспадзевана перасуваецца. Найпростышы спосаб прыменшыць гэтае явісце — задаць элементам медыя прыемлівыя, вядомыя размеры ўсё раней, чым будуць завершаны загрузкі фактычных ресурсаў. Заданне чысткага шыроці і высоты, або использованне атрыбута CSS aspect-ratio, дазволяе браузеру заздалегідь выдзеліць неабходны прастор пад час расчытку лейауту.
Проста кажучы: звярніце прастор для элемента ўсё раней, чым яны будуць адрасаваны.
Для роздзела з відэам у калеры, гэты хорашы пачатковы пункт — кантеўнер з фіксаванымі размерамі, а не дазволаць самой тагу <video> вялікім чынам адначынаць размеры ціх роздзелаў.
export function VideoHero() {
return (
<section className="relative min-h-[70svh] overflow-hidden">
<video
className="absolute inset-0 h-full w-full object-cover"
autoPlay
muted
loop
playsInline
preload="metadata"
aria-hidden="true"
>
<source src="/hero-video.mp4" type="video/mp4" />
</video>
<div className="relative z-10 mx-auto max-w-6xl px-6 py-24">
<h1 className="text-5xl font-bold text-white">
Build products people remember.
</h1>
</div>
</section>
);
}
Асалідным элементам тут зовсім не ёст калькюляцыя відэа.
Это проста гэтыя адзіныя рэчы:
min-height: 70svh;
З-за гэтаго роздзел з героем вже мае відомы візуальны футпринт яшчэ до таго, калі пачынаецца відпрацоўкаваць відеа.
Сама відеа розташоўваная абсалютна ўнутры таго контейнера, што значыць, у яе няма можлівасці раптам падсунуць контэнт пад сябе, калі ўсе яе ресурсы завершаюць загрузку.
Гэтае адрозненне зміняе ўсё, што стосуецца стабільнасці адчутка сторанкі.
Не дазвольце відеа кантролюваць вашу структуру
Тыповая, проблематычная наладка выглядае так:
<video
src="/hero-video.mp4"
autoPlay
muted
loop
/>
Потым хтось дадае ўжо:
video {
width: 100%;
}
А пазней задаецца пытаннем, чаму сторанка ведае ся нестабільна залежна ад якасці з’ѐеднання чы размеру экрана.
Проблема заключаецца у тым, што браузер павінен знать размеры відеа заздалегідь. Якщо відеа ўсёляка декоратыўны фонавы контэнт, рэдкая є прычына, чаму яно павінна браты участь у звычным абліку дакумента.
У замену перакладзіце адміністрацыю разметкі ва ўпаковач, які абгортае элемент відзначэння.
<div style="height: 100px; width: 100%">
<video
src="/hero-video.mp4"
autoPlay
muted
loop
/>
</div>
Калі такая структура ўстановлена, відзначэння можа дзеяць як захоча ўсередзіні, але абгортаючы div утримвае все гэта ў сабе.
Ўжывайце object-fit: cover для фонавага відзначэння
Калі відзначэння размешчаецца абсалютна, object-fit: cover становіць ся практычна корыстным (рэдкі случай, калі CSS-атрыбут працуе самэй так, як і планавалася).
.heroVideo {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
Гэта дазволяе відзначэнню абсалютна запаўніць выдзеланую зону без будзь-яых змян у сабеўных размерах упаковача.
Є незначны компроміс, які варта адзначыць. Значэнне cover будзе адсекаць часткі відзначэння, калі співвядношэнне сторон вікна не падходзіць да співвядношэння сторон вачальных кадраў. Гэта разумная цена, якую можна прыняць.
Праўdziва памылка — ставіць прыоритет на ідеальнае, піксель за пікселем, збережэнне вачальнага відэа, калі на самай працы дизайну трэбуецца стабільны, праўдападны лейяут.
Іспользуйце постер як першы візуальны стан
Однай з особліва эфектыўных тэхнік є выкарыстоўванне ретельна выбранага зображэння-постера для елемента відэа.
<video
className="absolute inset-0 h-full w-full object-cover"
autoPlay
muted
loop
playsInline
preload="metadata"
poster="/images/hero-poster.webp"
aria-hidden="true"
>
<source src="/videos/hero.mp4" type="video/mp4" />
</video>
Постер дае візітарамаў што-та конкрэтна, на што можна паглядзець, пакуль фактычны відэа ўсё яшчэ завантажваецца. Выбірайце такое зображэнне адзячна, адколькі ёно фактычна выступае як ваш альтэрнатыўны дизайн.
Што ўжо важлівей, гэта значыць, што ваш лейяут больш не залежыць ад таго, чы рэсурс відэа будзе доступны мгновена.
Спрыяйце пастеру як надзейнаму базоваму стану, а сам відэа дадзіце як дапаможны элемент, што павышае якасць, падобна да таго, як працююць загрузчыкі скелета або індыкаторы завантажэння ў іншых сценарыях.
Якщо відеа завантажуецца колька секундаў через поваленую мобайльную наянос, стораніца все раве выглядае завершанай і правільнаю, а не зламанай чы розпачатая.
Актуальныя проблемы з 100vh
Відеа ў режыме повнага екрана таксама маюць іншую тонкую прыемку.
Раней разработчыцы часта пісалі:
height: 100vh;
Мобайльныя браузеры ускладняюць гэта, таму што вышынка видныя часткі екрана зменшваецца, калі з’яўляецца чы зникае элемент браузера (радка адреса, панель інструментав), таму 100vh не працюе так, як можна было б спадзявацца.
Для макетаў, якія павінны добра прыстосоўвацца да разных прыстроёў, зазвычай краща вжываць новейшыя елементы для пазначэння часткі екрана, такія як:
min-height: 100svh;
чы, залежна ад таго, насколькі екрана хочаце, каб відеа заполняла:
min-height: 80svh;
Короткая версія: вжывайце 100dvh чы 100svh замест старэйшага 100vh.
Утримайцеся ад выдачы відеа размерам дэсктапа корыстуначам мобайльных прыстроёў
Нават стораніца з ідеальным показнікам CLS можа застацца надта повольной, якщо сама відеа-фонавая картынка ў величыне.
Сюдзеўна праця над выконаннем становіцца болей складной.
Кінематаграфічны кліп вазой 12 MB можа гарна працаваць на шырокаспектной дэсктапнай з’ѐеднанні, але на мобайльным прыстрою через нестабільную сеть той жа файл становіцца справжнім прытворам.
Для большасці стартовых стораніцаў логічна ствараць адзінаковыя відеа-ресурсы для дэсктапа і мобайльных прыводзоў.
У дазначальных случаях правым рашэнням є абоўсумова прыхіліцца да відеа для певных візітароў.
Пашанаванне прагаперкі корыстунача ў вялікай швальнасці — гарны прыклад гэтага:
const prefersReducedMotion =
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
У рэальным прыкладах аплікацый на React гэтыя пераконтрольванні павінны знаходзіцца ў кліентскай складовай, і яе трэба адмаўляць адпаведна, каб не паспяшыць на стабільнасць HTML, які быў выраслі на серверы.
Основны прынцып прост: праблемы выконвання та доступнасці трэба выважваць пры адліквідаванні, чы глядаць відеа ўзагалі, а не толькі штоўкасці яго завантажэння.
Ніколі не дазволяйце відеа кераваць макетам
Гэты є прынцып, які трэба памятаць у всіх ситуацыях.
Структура вашай сторонкі павінна застацца ціла ў такой последовасці:
Hero container
↓
Poster
↓
Video enhancement
і ніколі не павінна завышацца на гэта:
Video starts loading
↓
Browser discovers dimensions
↓
Hero changes height
↓
Everything below moves
↓
Lighthouse gets angry
Браузер павінен вже разумець ваш макет пры тым, як показуецца болей важкая медыйная асэтка.
Гэта ўласна спосаб рашэння проблем CLS, якія вызваны відеамі.
Ёнколі ў практыцы, запусцыце свой сайт через сповальванае, медленэе сетевае з’яўленне і пазірце, як ён будзе працаваць.
Спадні матэрыялы
- Адкладэнне пабочных эфектаў у Next.js за дапамогою API after() — Дзеянне API after() у Next.js для адкладэння аналітыки, логавання і фоновых задач пасля адпаведзі, а таксама яго гарантіі, проблемы і способы адрабаткі памылак.
- Настройка новых элементаў кантролю чанкавання Turbopack у Next.js 16.3 — Практычны аналіз новай настройкі turbopackChunking у Next.js 16.3, якая адпаведзае за розмер пакета і кэшаванне, а таксама як maxChunkCountPerGroup і generateComponentChunks на ўсё гэта вплываюць.