Свойство
content-visibility: auto позволяет эту работу отложить. Элемент с таким значением, пока он далеко от вьюпорта, не рендерит своё содержимое, а когда пользователь подбирается ближе, браузер рендерит его вовремя. Важно, что узлы остаются в DOM, ничего не удаляется и не пересоздаётся, в отличие от виртуализации списка на JavaScript.
.card {
content-visibility: auto;
contain-intrinsic-size: auto 600px;
}
Пропущенный элемент с точки зрения лейаута пустой, с нулевой высотой, и без подсказки о размере скроллбар начнёт прыгать. Поэтому необходим параметр
contain-intrinsic-size, который здесь указывает ширину и высоту элемента. На практике важна лишь высота, так как ширину блочный элемент всё равно получает от родителя.Ключевое слово
auto, стоящее внутри contain-intrinsic-size перед длиной, делает оценку одноразовой: как только элемент хоть раз отрисовался по-настоящему, браузер запоминает реальный размер и дальше использует его вместо указанных 600 пикселей. Запомненный размер живёт в памяти страницы, поэтому при перезагрузке расчёт начинается заново.Частый страх про эту механику — что она сломает поиск по странице и доступность. С
content-visibility: auto этого не происходит: содержимое остаётся в дереве доступности, Ctrl+F находит текст и скроллит к нему, Tab доводит фокус до элементов внутри, и во всех случаях блок рендерится по дороге. А вот content-visibility: hidden действительно делает содержимое недоступным ни поиску, ни фокусу.Зато есть другой, менее очевидный побочный эффект. Пока блок за экраном, его стили не вычислены, поэтому вложенные элементы, которые мы прячем через
display: none или visibility: hidden, браузер пока считает обычными и показывает в дереве доступности. Если там лежит что-то служебное, его стоит закрывать через aria-hidden="true", а не только через CSS.Поддержка у
content-visibility: auto с сентября 2024 года, а в браузерах без неё свойство просто игнорируется и страница рендерится как раньше, так что фоллбэки не нужны.