Браузерная ленивая загрузка изображений (атрибут loading) +15





Поддержка встроенной ленивой загрузки изображений и iframe пришла в веб!
Начиная с Chrome 76 версии, вы можете использовать новый атрибут loading для ленивой загрузки ресурсов без необходимости писать для этого дополнительный код или использовать стороннюю JavaScript-библиотеку. Давайте рассмотрим детали.

Примечание от переводчика
Большая просьба снисходительно отнестись к замеченным ошибкам в переводе, грамматике или пунктуации, и сообщить о них для исправления.
Спасибо


Это видео демонстрирует пример этой функции:


Почему встроенная ленивая загрузка?


Согласно HTTPArchive, изображения являются наиболее востребованным типом ресурсов на большинстве сайтов и обычно отнимают больше пропускной способности канала, чем любые другие. На 90-м процентиле, сайты отправляют около 4.7 МБ изображений на десктопы и мобильные устройства. Достаточно много фотографий с кошками.

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

В данный момент существует два способа отложить загрузку изображений и фреймов, расположенных за пределами экрана:


Любой из вариантов может позволить разработчикам включить функционал отложенной загрузки, и многие создали сторонние библиотеки, чтобы предоставить абстракции, которые использовать еще проще. При наличии поддержки ленивой загрузки непосредственно в браузере, не возникнет потребности в сторонней библиотеке. Встроенная ленивая загрузка также гарантирует, что отложенная загрузка изображений и фреймов продолжит работать, даже если JavaScript отключен на стороне клиента.

Атрибут loading


Сегодня Chrome уже загружает изображения с разным приоритетом, в зависимости от того, где они расположены относительно области просмотра устройства. Изображения ниже области просмотра загружаются с меньшим приоритетом, но всё ещё загружаются, как можно быстрее.

В Chrome 76 вы можете использовать атрибут loading, чтобы окончательно отложить загрузку изображений и фреймов за пределами экрана, до которых можно дойти прокруткой:

<img src="image.png" loading="lazy" alt="…" width="200" height="200">
<iframe src="https://example.com" loading="lazy"></iframe>

Поддерживаемые значения атрибута loading:

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

Эта функция продолжит обновляться, пока не будет запущена в стабильной версии (не раньше Chrome 76). Но вы можете опробовать её, активировав следующие флаги в Chrome:

  • chrome://flags/#enable-lazy-image-loading
  • chrome://flags/#enable-lazy-frame-loading

Порог расстояния загрузки


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

Расстояние, при котором начинается загрузка, не фиксировано и изменяется в зависимости от нескольких факторов:


Вы можете найти значения по умолчанию для разных типов эффективных соединений в Chromium source. Эти показатели и даже подход загрузки при достижении определенного расстояния от области просмотра, могут меняться в ближайшем будущем, так как команда Chrome улучшает эвристику, чтобы определить, когда начинать загрузку.

В Chrome 77 вы можете экспериментировать с этими различными пороговыми значениями путем замедления скорости соединения в DevTools. Во время этого вам потребуется переопределить эффективный тип соединения в браузере с помощью флага chrome://flags/#force-effective-connection-type.

Загрузка изображений


Атрибут loading влияет на фреймы иначе, чем на изображения, в зависимости от того, является ли фрейм скрытым (скрытые фреймы часто используются для задач аналитики или общения). Chrome использует следующие критерии, чтобы определить, является ли фрейм скрытым:

  • ширина и высота фрейма 4px или меньше
  • применяются свойства display: none или visibility: hidden
  • фрейм расположен за пределами экрана с помощью отрицательного позиционирования по осям X или Y

Если фрейм соответствует любому из этих условий, Chrome считает его скрытым и не будет загружать в отложенном режиме в большинстве случаев. Фреймы, не являющиеся скрытыми, будут загружены только тогда, когда попадут в пределы порога загрузки. Для фреймов, которые все еще загружаются в режиме отложенной загрузки, отображается плейсхолдер

FAQ


Есть ли планы расширить эту функцию?


Есть планы изменить режим отложенной загрузки браузера по умолчанию, чтобы автоматически отображать в таком режиме любые изображения и фреймы, загрузку которых можно отложить, если включен Lite mode в Chrome для Android.

Можно ли изменить расстояние до изображения или фрейма, при котором запускается отложенная загрузка?


Эти значения жестко закодированы и не могут быть изменены через API. Однако, они могут измениться в будущем, так как команда Chrome экспериментирует с разными пороговыми расстояниями и переменными.

Могут ли изображения, заданные через CSS-свойство background, получить атрибут loading?


Нет, в данный момент он может использоваться только тегами

Как работает атрибут loading с изображениями, которые находятся в области видимости, но не видны (например, карусель)?


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

Что, если я уже использую стороннюю библиотеку или скрипт для отложенной загрузки изображений или фреймов?


Атрибут loading не должен влиять на код, который в отложенном режиме загружает данные, но важно учитывать некоторые важные моменты:

  1. Если ваш сторонний загрузчик в отложенном режиме пытается загрузить изображения или фреймы раньше, чем их будет загружать Chrome в обычном режиме, то есть, на расстоянии, превышающем порог расстояния загрузки браузером, они все еще будут отложены и загружены по правилам обычного поведения браузера
  2. Если ваш сторонний загрузчик использует более короткое расстояние, чтобы определить, когда загружать конкретное изображение или фрейм, чем браузер, то поведение будет соответствовать настройкам вашего загрузчика

Одна из важных причин продолжить использовать стороннюю библиотеку параллельно с loading=«lazy» заключается в предоставлении полифила для браузеров, не поддерживающих данный атрибут.

Другие браузеры поддерживают встроенную отложенную загрузку?


Атрибут loading можно рассматривать, как прогрессивное улучшение. Браузеры, которые поддерживают его, могут загружать изображения и фреймы в отложенном режиме. Те, что не поддерживают — пока что загружают изображения как обычно. С точки зрения кроссбраузерной поддержки, атрибут loading поддерживается в Chrome 76 и любых браузерах, основанных на базе Chromium 76. Также существует открытый баг про реализацию данной функции в Firefox.

Похожее API было предложено и использовалось в IE и Edge, но оно было сфокусировано на понижении приоритетов загрузки вместо полного её откладывания.

Как поступить с браузерами, которые еще не поддерживают встроенную отложенную загрузку?


Создайте полифил или используйте стороннюю библиотеку, чтобы загружать изображения на сайте в отложенном режиме. Свойство loading может быть использовано для определения, поддерживается ли функционал в браузере:

if ('loading' in HTMLImageElement.prototype) {
  // supported in browser
} else {
  // fetch polyfill/third-party library
}

Например, lazysizes — популярная JavaScript библиотека для ленивой загрузки. Вы можете определить поддержку атрибута loading, чтобы загрузить эту библиотеку только, когда loading не поддерживается. Это работает следующим образом


<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt="…">

<!-- Let's lazy-load the rest of these images -->
<img data-src="unicorn.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="cats.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="dogs.jpg" alt="…" loading="lazy" class="lazyload">

<script>
  if ('loading' in HTMLImageElement.prototype) {
    const images = document.querySelectorAll('img[loading="lazy"]');
    images.forEach(img => {
      img.src = img.dataset.src;
    });
  } else {
    // Dynamically import the LazySizes library
    const script = document.createElement('script');
    script.src =
      'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.8/lazysizes.min.js';
    document.body.appendChild(script);
  }
</script>

Демонстрация работы. Испробуйте это в таким браузерах, как Firefox или Safari, чтобы увидеть фолбек в действии.

Библиотека lazysizes также обеспечивает плагин встроенной загрузки, который использует встроенную отложенную загрузку, когда это возможно, и задействует функционал библиотеки, когда в этом есть потребность.

Как отложенная встроенная загрузка влияет на рекламу на странице?


Вся реклама, представленная в виде изображений или фреймов, также загружается в отложенном режиме, как любые другие изображения или фреймы.

Как изображения обрабатываются, если веб-страницу распечатать?


Хотя функционала нет в Chrome 76, существует открытая проблема, обеспечивающая немедленную загрузку всех изображений и фреймов при печати страницы.

Заключение


Использование встроенной поддержки ленивой загрузки изображений и фреймов может существенно облегчить повышение производительности веб-страниц.

Если замечаете любое необычное поведение при включении этой функции в Chrome, сообщите об ошибке.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (11):

  1. demimurych
    /#20548445 / +3

    Появление этого атрибута прекрасная иллюстрация к поговорке — хотели как лучше, а получилось как всегда.

    В текущей его реализации, это абсолютно бесполезная технология и вот почему:

    1. Атрибут не работает с любым изображением содержащим srcset и sizes — а это сейчас стандарт по умолчанию.
    2. Атрибут не дает возможности контролировать свою работу. СОВСЕМ. Он вещь в себе, которая делает то, что ему хочется. Параметры активации прибиты гвоздями в коде браузера
    3. В текущей реализации, вне зависимости от того где изображение, браузер все равно создаст запрос к серверу и скачает около 2 килобайт, для того чтобы определить его размеры. И повлиять на это нельзя


    Как итог, выпускается обрубок, который не работает даже со всеми валидными вариантами верстки того же IMG, не говоря уже о том, чтобы послушать людей которые работают с подобной технологией по 15 лет, для которых она как бы и должна была быть создана.

    Обрубок, который кардинально НИКАК не повлияет на производительности страницы, потому что в любом случае создает соединение на каждое изображение и нагружает канал.

    Полезен будет только той категории людей, которые до сих пор изображения верстают как
    <IMG src=  >

    и по каким то своим причинами использовать чужой код не хотят, а свой написать не могут, но при этом доросли до того, чтобы перевестать до
    <IMG src=  loading="lazy">


    Все же, кто использовал Lazyload не как игрушку, как использовали свой код, так и будут продолжать использовать.

    • lowtechomega
      /#20548623

      Полностью и абсолютно с вами согласен — свой lazyload код в разы более гибкий, да и реализаций немало. Вряд ли сий тег будет кто импользовать кроме начинающих.

    • Sabubu
      /#20549273

      Спасибо, ценная информация. Но я не люблю сторонние библиотеки lazyload, по таким причинам:


      • они не обратно-совместимы, то есть старый браузер (если инвалиды-авторы библиотеки используют ES6 или ES5) или браузер без JS ничего не покажет с ними
      • они могут использовать события вроде scroll, что негативно влияет на производительность
      • они могут быть не совместимы с опцией отмены загрузки страницы по нажатию Esc
      • они раздувают объем JS-кода
      • они часто используют анимации, которые сильно нагружают браузер при одновременной загрузке нескольких картинок

    • Shugich
      /#20549427

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

    • MaximChistov
      /#20550345

      Атрибут не дает возможности контролировать свою работу. СОВСЕМ. Он вещь в себе, которая делает то, что ему хочется. Параметры активации прибиты гвоздями в коде браузера

      Так Хром потихоньку стал новым осликом) Двигает свои стандарты не советуясь ни с кем, шантажирует владельцев сайтов несовместимостью с их браузером и тд… Думаю, лет через 5-10 история с IE6 повторится

      • Shugich
        /#20554397

        Новый ослик — это, скорее, Сафари, который плохо поддерживает стандарты и в целом медленно развивается.

    • Eirik
      /#20550519

      Сегодня проверял scrset — работает, правда у меня он реализован через picture. Лишний запрос к серверу и минимальные размеры картинок действительно нивелирут преимущества. Например для 100к картинки, первые 2кб грузятся столько же по таймингу как все 100 при хорошем коннекте, при плохом несколько секунд TTFB на первый запрос. В целом поддерживаю — атрибут бесполезен.

      Есть еще один интересный еффект — для больших картинок, первый заброс на 2к при плохом соединении иногда отменяется. Кто-то понял почему?

    • unel
      /#20550747

      Атрибут не дает возможности контролировать свою работу. СОВСЕМ.

      Не дают контроллировать свою работу программисту, но добавляют возможность (хотя бы теоретическую) управлять этим пользователю.

      Все же, кто использовал Lazyload не как игрушку, как использовали свой код, так и будут продолжать использовать.

      И в итоге те, кому этот lazyload нахрен не впился будут страдать, и обходить каждую из подобных «своих кодов» по разному: где-то по быстрому прокрутив страницу, где-то открыв диалог печати…

    • acklamterrace
      /#20551187

      Для далеких от фронтенда — а что не так с тегом img?

  2. BlackStar1991
    /#20550697

    Как-то все тут уперлись в loading=«lazy». Ребята, а как же значение eager? Это же должно быть очень круто, лично я замахался на первом экране, когда ставишь большее фоновое изображение сначала понижать его качество, а потом колдовать что б из какахи делать конфету… надо тестить

  3. grishkaa
    /#20550957

    Меня одного lazy loading бесит как таковой? Как пользователь, я ожидаю, что любая не интерактивная по своей природе страница полностью загружена на момент пропадания прогрессбара в интерфейсе браузера. Lazy loading это ломает. У меня было слишком много случаев, когда я что-то прогрузил заранее, чтобы прочитать при плохом/отсутствующем интернете, а потом оказывалось, что не прогрузил и вместо картинок размазня. Спасибо, что сэкономили мне мой безлимитный трафик, чёрт возьми.

    Вынести это в браузер — идеологически очень правильное решение, потому что тогда либо в самом браузере можно будет сделать настройку, либо кто-нибудь сделает расширение, чтобы пользователь мог этим поведением управлять для всех сайтов в соответствии со своими предпочтениями. В конце концов, браузер не просто так называется user agent.