Pull to refresh
2665.92
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Ленивая загрузка изображений средствами браузера

Reading time 9 min
Views 95K
Original author: Addy Osmany
Автор материала, перевод которого мы сегодня публикуем, Эдди Османи из Google, говорит, что уже в Chrome 75 вполне может появиться поддержка нового атрибута элементов <img> и <iframe> loading. Это означает, что данные элементы будут поддерживать стандартные возможности по так называемой «ленивой загрузке» данных.

image

Если вам не терпится узнать о том, как использование нового атрибута выглядит в коде, то взгляните на этот пример:

<img align="center" src="celebration.jpg" loading="lazy" alt="..." />
<iframe src="video-player.html" loading="lazy"></iframe>

Сейчас мы поговорим о том, как будет работать атрибут loading.

Предварительные сведения


Веб-страницы часто включают в себя множество изображений, что влияет на размер страниц, приводит к его чрезмерному увеличению, и влияет на скорость загрузки страниц. Многие из изображений, выводимых на страницах, находятся за пределами их видимой области. Для того чтобы увидеть подобные изображения, пользователю нужно прокрутить страницу.

Исторически сложилось так, что для того чтобы ограничить воздействие на время загрузки страниц изображений, расположенных за пределами видимой области страниц, программистам приходилось использовать JavaScript-библиотеки (вроде LazySizes). Эти библиотеки позволяют отложить загрузку подобных изображений до того момента, когда пользователь, прокручивая страницу, не подберётся к ним достаточно близко.


Страница, загружающая 211 изображений. Версия страницы, при создании которой ленивая загрузка изображений не используется, сразу загружает 10 Мб графических данных. Та же страница, использующая ленивую загрузку (с помощью LazySizes) предварительно загружает лишь 250 Кб графической информации. Всё остальное подгружается по мере продвижения пользователя по странице. Подробности об этом эксперименте можно посмотреть на webpagetest.org.

Что если бы браузер мог бы помочь программисту избежать загрузки изображений, которые находятся за пределами видимой области страниц? Это благотворно сказалось бы на скорости загрузки данных в видимой области страницы, снизило бы, на маломощных устройствах, общий объём передаваемых по сети данных, уменьшило бы потребление памяти. Скоро всё это будет возможно благодаря новому атрибуту элементов <img> и <iframe> loading.

Атрибут loading


Атрибут loading позволяет браузеру откладывать загрузку содержимого элементов <img> и <iframe>, находящихся за пределами видимой области страницы, до тех пор, пока пользователь, прокручивая страницу, не окажется достаточно близко к этим элементам. Этот атрибут поддерживает три значения:

  • lazy: указывает на материалы, которые являются хорошими кандидатами на ленивую загрузку.
  • eager: материалы в элементах с таким значением атрибута нужно загрузить без промедления.
  • auto: браузер самостоятельно примет решение о том, применять ли к материалам с этим значением атрибута ленивую загрузку.

Если значение атрибута loading не указывать — это будет равносильно установке его в значение auto.


В настоящее время работа над атрибутом loading для элементов <img> и <iframe> ведётся в рамках стандарта HTML

Примеры


Атрибут loading работает с элементами <img> (в том числе с атрибутом srcset и внутри элемента <picture>), а также с элементами <iframe>.

<!-- Выполнить ленивую загрузку изображения, находящегося за пределами видимой области страницы, в тот момент, когда пользователь прокрутит страницу близко к этому изображению -->
<img align="center" src="unicorn.jpg" loading="lazy" alt=".."/>

<!-- Не выполнять ленивую загрузку, загрузить изображение немедленно -->
<img align="center" src="unicorn.jpg" loading="eager" alt=".."/>

<!-- Решение о том, применять ли ленивую загрузку при работе с изображением, примет браузер -->
<img align="center" src="unicorn.jpg" loading="auto" alt=".."/>

<!-- Выполнить ленивую загрузку изображений в <picture>. За загрузку изображений отвечает элемент <img>, в результате элемент <picture> и атрибут srcset на это не влияют -->
<picture>
  <source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x">
  <source srcset="small.jpg 1x, small-hd.jpg 2x">
  <img align="center" src="fallback.jpg" loading="lazy">
</picture>

<!-- Выполнить ленивую загрузку изображения, для которого задан атрибут srcset -->
<img align="center" src="small.jpg"
     srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
     sizes="(min-width: 36em) 33.3vw, 100vw"
     alt="A rad wolf" loading="lazy">

<!-- Выполнить ленивую загрузку содержимого элемента <iframe> в тот момент, когда пользователь прокрутит страницу так, что её видимая область окажется поблизости от этого элемента -->
<iframe src="video-player.html" loading="lazy"></iframe>

Надо отметить, что мы используем тут формулировки наподобие следующей: «когда пользователь прокрутит страницу так, что её видимая область окажется поблизости от элемента». Точный момент начала загрузки изображения браузер определяет самостоятельно. В целом мы можем надеяться на то, что браузер начнёт загрузку материалов, загрузка которых была отложена, за некоторое время до того, как область страницы, содержащая их, окажется видимой пользователю. Это увеличит шансы того, что загрузка и вывод соответствующих материалов завершатся к тому моменту, когда пользователь их увидит.

Обратите внимание на то, что я предложил, чтобы атрибут, о котором идёт речь, назвали бы именно loading, так как такой подход к его именованию соответствует тому, что использовался при выборе имени для атрибута decoding. Предыдущие предложения, наподобие lazyload, не подошли, так как нужно было, чтобы этот атрибут поддерживал бы несколько значений (lazy, eager и auto).

Проверка поддержки атрибута loading браузерами


Мы принимали во внимание важность возможности применения JavaScript-библиотек для организации ленивой загрузки материалов (для кросс-браузерной поддержки этой возможности). Проверить, поддерживает ли браузер атрибут loading, можно так:

<script>
if ('loading' in HTMLImageElement.prototype) { 
    // Браузер поддерживает `loading`.
} else {
   // Иначе - загрузить и применить полифилл или JavaScript-библиотеку для 
   // организации ленивой загрузки материалов.
}
</script>

Обратите внимание на то, что атрибут loading можно использовать для прогрессивного расширения возможностей страницы. Браузеры, которые поддерживают этот атрибут, смогут организовать ленивую загрузку материалов при использовании loading=lazy, а браузеры, которые эту возможность не поддерживают, будут просто, как и прежде, загружать эти материалы.

Кросс-браузерная ленивая загрузка изображения


Если важна кросс-браузерная поддержка ленивой загрузки изображений, тогда недостаточно просто определить то, поддерживает ли браузер эту возможность, и, если это не так, воспользоваться соответствующей библиотекой, если при описании изображения в разметке используется конструкция наподобие <img align="center" src=unicorn.jpg loading=lazy />.

В разметке нужно использовать что-то наподобие <img data-src=unicorn.jpg /> (а не src, srcset или <source>) для того чтобы избежать срабатывания обычной загрузки изображения браузерами, которые не поддерживают новый атрибут. Для того чтобы менять подобные атрибуты на те, которые нужно использовать при поддержке браузером атрибута loading, или для загрузки соответствующей библиотеки в том случае, если этот атрибут не поддерживается, можно использовать возможности JavaScript.

Вот пример того, как это может выглядеть:

<!-- Загрузим это изображение, находящееся в видимой области страницы, как обычно -->
<img align="center" src="hero.jpg" alt=".."/>

<!-- Работая с остальными изображениями, применим методику ленивой загрузки -->
<img data-src="unicorn.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="cats.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="dogs.jpg" loading="lazy" alt=".." class="lazyload"/>

<script>
(async () => {
    if ('loading' in HTMLImageElement.prototype) {
        const images = document.querySelectorAll("img.lazyload");
        images.forEach(img => {
            img.src = img.dataset.src;
        });
    } else {
        // Динамически импортируем библиотеку LazySizes
        const lazySizesLib = await import('/lazysizes.min.js');
        // Инициализируем LazySizes (читаем data-src & class=lazyload)
        lazySizes.init(); // lazySizes применяется при обработке изображений, находящихся на странице.
    }
})();
</script>

Рассмотрим некоторые особенности этого кода:

  • Изображения, которые видны пользователю сразу после загрузки страницы, описаны с помощью обычных тегов <img>. Использование атрибута data-src без src приведёт к тому, что изображения, сразу после загрузки страницы, показаны не будут, поэтому, настраивая те изображения, которые должны быть видны сразу же после загрузки страницы, мы должны указывать атрибут src.
  • При описании изображений, которые, сразу после загрузки страницы, пользователю не видны, мы используем атрибут data-src. Делается это для того чтобы предотвратить их обычную загрузку в браузерах, не поддерживающих атрибут loading. Если браузер этот атрибут поддерживает, мы меняем data-src на src.
  • Если атрибут loading не поддерживается, мы загружаем вспомогательную библиотеку (lazySizes) и инициализируем её. Здесь мы используем class=lazyload для того чтобы указать библиотеке LazySizes на изображения, с которыми мы хотим работать, используя методику ленивой загрузки.

Демонстрационный пример


Тут можно посмотреть на пример страницы, на которой выполняется ленивая загрузка 100 изображений кошек. А вот, если интересно, видео загрузки этой страницы.

Особенности реализации поддержки атрибута loading в Chrome


Мы настоятельно рекомендуем, прежде чем пользоваться атрибутом loading в продакшне, дождаться появления его поддержки в стабильном релизе Chrome. Если же вам не терпится испытать эту возможность, тогда, возможно, вам будет интересно то, о чём мы сейчас поговорим.

Испытание атрибута loading


Для того чтобы прямо сейчас испытать новый атрибут, перейдите к странице настройки флагов Chrome (chrome://flags), включите флаги Enable lazy frame loading и Enable lazy image loading, и перезагрузите браузер.

Настройки браузера


Реализация методики ленивой загрузки материалов в Chrome основана не только на том, насколько близко видимая область страницы находится к этим материалам, но и на скорости соединения. Пороговые значения срабатывания ленивой загрузки материалов для разных скоростей соединения жёстко заданы в коде, но эти значения можно переопределить средствами командной строки. Вот пример переопределения настроек для изображений:

canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=5000,lazyImageLoadingDistanceThresholdPxOffline=8000,lazyImageLoadingDistanceThresholdPxSlow2G=8000,lazyImageLoadingDistanceThresholdPx2G=6000,lazyImageLoadingDistanceThresholdPx3G=4000,lazyImageLoadingDistanceThresholdPx4G=3000 'https://mathiasbynens.be/demo/img-loading-lazy'

Вышеприведённая команда соответствует текущим настройкам, применяемым по умолчанию. Для того чтобы загрузка изображений начиналась бы в том случае, если позиция прокрутки страницы находится на расстоянии в 400 пикселей от изображения, все значения в этой команде нужно поменять на 400. Ниже приведён пример 1-пиксельной вариации этой команды (такая настройка используется в вышеупомянутом видео).

canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=1,lazyImageLoadingDistanceThresholdPxOffline=1,lazyImageLoadingDistanceThresholdPxSlow2G=1,lazyImageLoadingDistanceThresholdPx2G=1,lazyImageLoadingDistanceThresholdPx3G=1,lazyImageLoadingDistanceThresholdPx4G=1 'https://mathiasbynens.be/demo/img-loading-lazy'

Весьма вероятно то, что стандартная конфигурация ленивой загрузки в Chrome изменится по мере стабилизации реализации этой возможности в ближайшие недели.

Инструменты разработчика


Особенности реализации поддержки атрибута loading в Chrome заключаются в том, что браузер, при загрузке страницы, запрашивает первые 2 Кб изображений у сервера в том случае, если он поддерживает технологию range request (запрос на диапазон). В первых 2 Кб изображений, наверняка, содержатся сведения об их размерах. Это позволяет браузеру генерировать местозаполнители, имеющие размеры, соответствующие размерам изображений. Кроме того, в эти 2Кб, если речь идёт о небольших изображениях вроде значков, весьма вероятно, входит всё изображение.


Загрузка фрагментов графических файлов

Chrome загружает оставшиеся данные изображений в тот момент, когда пользователь близок к тому, чтобы их увидеть. При работе с инструментами разработчика это может привести к тому, что в панели Network может «появиться» информация о двух загрузках изображения, а в панели Resource Timing будут выведены сведения о двух запросах, выполняемых для загрузки каждого изображения.

Определение сервером поддержки браузером атрибута loading


Если бы мы жили в совершенном мире, то для того чтобы узнать о том, нужно ли, для правильного вывода страницы в некоем браузере, использовать вспомогательную библиотеку, можно было бы не полагаться на анализ браузера средствами клиентского JavaScript. При таком подходе сервер, заранее зная, нужна такая библиотека или нет, включил бы (или не включил бы) её в состав страницы, отправляемой браузеру. Подобную проверку может сделать возможной использование технологии HTTP Client Hint, благодаря которой клиент способен передавать серверу «подсказки» о своих возможностях.

Соответствующая «подсказка», касающаяся поддержки атрибута loading, находится сейчас на ранней стадии рассмотрения.

Итоги


Автор этого материала предлагает всем, кто заинтересован в использовании атрибута loading при работе с элементами <img> и <iframe>, опробовать его, и поделиться с ним впечатлениями. Особенно ему интересно узнать о том, как, с точки зрения разработчиков, выглядят предложенные здесь механизмы кросс-браузерной поддержки ленивой загрузки данных, и о том, не упустил ли он, рассказывая о таких механизмах, какие-то пограничные случаи.

Уважаемые читатели! Планируете ли вы использовать атрибут loading в своих проектах?

Tags:
Hubs:
+27
Comments 16
Comments Comments 16

Articles

Information

Website
ruvds.com
Registered
Founded
Employees
11–30 employees
Location
Россия
Representative
ruvds