Как атрибуты width и height у картинок ускорят сайт на 12% и сделают его комфортнее?
Во время загрузки сайта тег IMG занимает нулевой размер на странице. Затем при загрузке самого файла, блок раздвигает все элементы вокруг себя и занимает нужный размер. В этот момент, когда элементы страницы «толкаются» в стороны, происходит пересчёт макета в браузере.
Это требует времени центрального процессора на обсчёт новых позиций и размеров блоков и создаёт визуальный дискомфорт: страница дёргается, прыгает и скачет во время загрузки страницы. Также текст на странице начинает убегать вниз из-за появляющихся изображений, заставляя пользователя «ловить» строчку текста, которую он уже начал читать.
Эта статья — актуализация статьи англоязычного автора 2020 года и её расширение с учётом последних обновлений браузеров. Также материал структурирован от простого к сложному с более наглядными примерами, чтобы было увлекательней читать. Внутри есть интерактивные примеры, которые можно исследовать самостоятельно в браузере с помощью профайлера браузера.
Скачущие изображения, как они появляются?
Возьмём простую страницу с таким кодом:
<h1>Заголовок страницы</h1>
<p>Первый параграф страницы.</p>
<img src="jumping-image.jpg" />
<p>Второй параграф. Остальное текстовое содержимое страницы.</p>
Во время загрузки такой страницы вы увидите следующую картину: после загрузки HTML кода страницы отобразится весь текст, затем загрузится картинка и второй параграф резко сместится вниз, освобождая место под появившуюся картинку.
Этот резкий скачок текста, вызванного появлением изображения, и называется «прыгающим изображением». Потому что резкое перестраивание структуры страницы и смещение крупных блоков выглядит как прыжок.
Чем они вредны скачущие изображения?
Скачущие изображения вредны по следующим причинам:
- Масштабное смещение блоков требует от браузера пересчитывать структуру страницы. Эта операция может занимать сотни миллисекунд. На мобильных устройствах с их медленными процессорами эта проблема особенно актуальна. Страница может содержать десятки скачущих изображений, и тогда, из-за многократных пересчётов структуры страницы, суммарное время задержки может составлять секунды.
- Визуальные рывки при загрузке страницы выглядят отталкивающе. Это подсознательно настраивает пользователя быть менее внимательным при изучении страницы или начать торопиться, что уменьшает вовлечённость пользователей. Плавная загрузка всегда предпочтительней.
- Пользователи могут начать читать текст и по мере загрузки картинок весь текст начинает резко убегать вниз. Каждый был в такой ситуации, особенно на мобильных устройствах с их медленным интернетом. Ловить нужную строку текста, когда она от тебя убегает вниз экрана — то ещё удовольствие.
Основное решение проблемы
Наша задача - заранее зарезервировать место под будущую картинку. Для этого нужно просто указать у тега <img /> аттрибуты height и width. В CSS свойствах для этого элемента указываем width: 100%, а height: auto. Вот полный код:
<style>
img {
width: 100%;
height: auto;
}
</style>
<h1>Заголовок страницы</h1>
<p>Первый параграф страницы.</p>
<img src="nit-jumping-image.jpg" width=800 height=600 />
<p>Второй параграф. Остальное текстовое содержимое страницы.</p>
При таком коде происходит следующее:
- Загружается HTML страница.
- Согласно CSS свойству, ширина изображения растянется до 100% блока, в котором оно находится. При этом будут сохранены пропорции изображения 800х600 пикселей, указанные аттрибутах width и height.
Таким образом, не дожидаясь загрузки самой картинки, браузер сразу выделит то пространство, которое в будущем займёт изображение после загрузки. Страница не будет дёргаться, перестраиваться и прятать строки текста вниз во время загрузки.
Для тега <picure> аттрибуты width и height нужно указывать для тегов <source> (было внедрено в 2021–2022 годах) вот так:
<picture>
<source width="400" height="600" srcset="./img-mobile.jpeg" media="(max-width: 1024px)" />
<source width="800" height="600" srcset="./img-desktop.jpeg" />
<img />
</picture>
Альтернативные решения проблемы
Данные решения стоит применять лишь в очень специфических случаях, либо ради реализации совместимости со старыми браузерами. С точки зрения простоты понимания и дальнейшей поддержки кода, решение с аттрибутами width и height выигрывает во всём.
Трюк через padding-bottom (плохой вариант)
Этот трюк позволяет задать блок с заранее известным соотношением сторон. Изображение будет умещено в него.
.img-container {
position: relative;
padding-bottom: 56.25%; /* соотношение сторон 16:9 */
height: 0;
overflow: hidden;
}
.img-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Трюк довольно старый, но использовать его не нужно, потому что:
- Управление соотношением сторон изображения проходит сразу в нескольких местах: HTML коде, в нескольких местах CSS кода (когда нужно задавать разные картинки для разных экранов). Чем сильней разбросаны участки кода, выполняющих одну задачу — тем сложнее с ними работать.
- Новички в веб-разработке могут не понять, суть техники и принцип её работы. Управлять высотой элемента через указание внутреннего отступа снизу может быть для них не очевидно.
- CSS код имеет тенденцию к наращиванию, а не к переписыванию. В случае каких-либо визуальных правок или замены изображения специалист не осмелится менять существующее свойство padding-bottom, так как это может затронуть другие страницы сайта. Скорее всего, программист просто добавит новый класс для редактируемой картинки, переопределяющий свойство padding-bottom. Таким образом, кода будет становиться больше.
Свойство aspect-ratio (тоже плохой вариант)
Тут мы задаём соотношение сторон для изображения через специальное CSS свойство aspect-ratio.
img {
width: 100%;
height: auto;
aspect-ratio: 16/9;
}
Вариант лучше предыдущего только краткостью. Но все проблемы остаются такими же.
Экзотика через aspect-ratio: attr(width) / attr(height);
Опция задаёт соотношение сторон на основе аттрибутов width и height элемента.
img {
aspect-ratio: attr(width) / attr(height);
}
Опция вызвала бурные обсуждения: 100+ сообщений в Git и множество упоминаний в других темах, официальную дискуссию на 200+ сообщений представителями W3C, есть публикации на эту темы блогерами-экспертами, в том числе видео.
По факту оно работает так же, как аттрибуты width и height, но на чей-то вкус считается более «элегантным» с точки зрения красоты кода.
Для нас — прикладных программистов это означает только одно: нам просто надо знать ещё +1 способ решения задачи прыгающих изображений, чтобы не запутаться при встрече такой строчки кода.
Другие медиа компоненты: <video>, <iframe>, <canvas>, <object>
Теги <video>, <iframe>, <canvas>, <object> также поддерживают указание пропорций блока через аттрибуты width и height.
Неочевидные детали
- Некоторые сайты скрывают содержимое до полной загрузки страницы, показывая лоад бар. Несмотря на то, что визуально мы не видим страницу, она всё равно отрисовывается браузером и на переобсчёт позиционирования блоков тратится процессорное время.
- При использовании grid отображения все блоки в сетке подгоняются под один размер высоты и ширины. В таких случаях переобсчёт происходит только после загрузки 1 изображения в ячейке, а не каждого. Поэтому потери времени при переобсчёте страницы не так чувствительны в каталоге товаров интернет-магазинов, где элементы с картинками отображены с помощью техники grid.
- Раз уж мы завели разговор о трате процессорного времени на пересчёт структуры страницы, то важно упомянуть, что подгрузка шрифтов вызывает самые большие всплески использования ЦПУ, поэтому подгружайте их как можно раньше, через директиву <preload>. Так, страница будет обсчитана только 1 раз, а не после каждой загрузки файла шрифта (если их несколько).
Протестируйте сами
Наглядную демонстрацию разницы между скачущими изображениями и фиксированными можно увидеть здесь.
Здесь доступен более нагруженный пример, демонстрирующий разницу в быстродействии. На медленных компьютерах будет заметен подлаг при появлении каждой картинки.
Рекомендуем самостоятельно замерить возросшее быстродействие страницы с помощью инструментов peformance аналитики браузера. Делается это следующим образом:
- Открываете инструменты разработчика браузера клавишей F12.
- Открываете вкладку профайлер.
- Нажимаете кнопку «Записать и перезапустить» или сочетание клавиш Ctrl+Shift+E.
- Ждёте загрузки страницы и нажимаете кнопку «Остановить».
- Получаете детальную перфоманс аналитику.
[Вот так выглядит отчёт. Кнопка «Записать и перезапустить» третья слева во второй строке с иконкой перезагрузки.]
Сервисы для проверки
Site Alarm — проверяет не только заполненность тегов width и height у картинок, а именно наличие скачущих изображений. Это значит, что он обнаружит неверные значения width и height, а также определит ситуации, когда отсутствие width и height не вызывает переобсчёт структуры страницы. Например, маленькие иконки редко нуждаются в width и height.
Google PSI — проверяет только заполненность тегов width и height. Грешит ложноположительными срабатываниями, так как проверяет только HTML код, а не отрисовку страницы.
Тарифные планы для работы с сервисом
Проба сервиса
Разовая проверка
Подписка
Доп. страницы
Дополнительные страницы для тарифа «Подписка».
Пополнение через личный кабинет.
*Цена зависит от активной подписки. Чем дороже тариф — тем дешевле дополнительные страницы.