Създаваме ъглова директива, използвайки API за наблюдение на Intersection, за да отложим зареждането на изображенията, докато не са необходими, и да добавим някакъв блестящ ефект, за да подобрим UX.

Тази публикация е публикувана за първи път в Adrobit Technologies Blog

Прекарваме много време в създаване на нови приложения, било то Single Page App (SPA) или Progressive Web Application (PWA) или уебсайтове, използващи React, Vue или Angular. Едно такова приложение беше тежко за изображения на началната страница. Изображенията със сигурност подобряват естетическата привлекателност на уебсайта, но увеличават драстично времето за зареждане на сайта. Браузърът трябва да извлече всички изображения от техния източник, за да завърши зареждането на страницата. За съжаление, браузърът ще зареди и онези изображения, които са „под видимата на екрана част от страницата“, т.е. не в изгледа на потребителя.

Извличането на всички изображения при първото зареждане на сайта води до бавно зареждане на сайта. Ако сайтът не се зареди или стане използваем за кратък период от време, вашите потребители може просто да си тръгнат, да, да напуснат сайта ви и никога повече да не се върнат.

Средното време, необходимо за пълното зареждане на средната мобилна целева страница, е 22 секунди. Проучването обаче също така показва, че 53% от хората ще напуснат мобилна страница, ако зареждането й отнеме повече от 3 секунди.
– статистика на Google

Как да решим проблема с времето за зареждане и без да премахваме изображенията?

Мързеливото зареждане на изображения се отнася до набор от техники, които отлагат зареждането на изображения на страница за по-късен момент, когато тези изображения действително са необходими, вместо да ги зареждат предварително. Тези техники помагат за подобряване на производителността, по-добро използване на ресурсите на устройството и намаляване на свързаните с това разходи.

Поздравления за мързеливо зареждане!
Мързеливо, но в крайна сметка свършва работата!

Уебсайт, който бавно зарежда изображения, ще отложи зареждането на ресурсите, докато те не са в изгледа на потребителя.. Вместо това ще ги зареди веднага щом потребителят превърти и изображението влезе в прозореца за изглед. Техниката на отложено зареждане може да се приложи към почти всички ресурси на страницата, но в момента ние се грижим само за нашите „изображения“!

Нашето решение

Нашият трик зад отложеното зареждане е да не задаваме атрибута src на вашия елемент img, вместо това да съхраняваме url адреса на изображениетона друго място, за да го поставим в src лениво, когато е приложимо.

Ние съхраняваме URL адреса на изображението в атрибута на набора от данни, да речем data-src=”https://my-image-url”. По-късно, когато потребителят превърти до изображението, ние ще настроим img.src на img.dataset.src

  • Вземете оригиналния URL адрес на img и го поставете в data-src набор от данни
  • Уверете се, че атрибутът src е празен, в противен случай ще задейства извличане на изображение
  • Използвайте API на Intersection Observer, за да изчакате и наблюдавате за обратно извикване, когато елементът на изображението е в прозореца за изглед
  • Обратното извикване взема всички URL данни, налични в dataset.src, и ги поставя в img.src, като по този начин задейства извличане.
  • Добавяме и някакъв фантастичен блестящ ефект към img div, така че да изглежда страхотно, докато нашето изображение се извлича

Строго погледнато, наблюдателите на кръстовището не са абсолютно необходими за решаването на този проблем. Ето начин да го направите в обикновен Javascript, като вместо това използвате clientBoundingRect:

Цитат от Mozilla Developers Network:

Прилагането на откриване на пресичане в миналото включваше манипулатори на събития и цикли, извикващи методи като Element.getBoundingClientRect() за изграждане на необходимата информация за всеки засегнат елемент. Тъй като целият този код се изпълнява в основната нишка, дори един от тях може да причини проблеми с производителността. Когато един сайт е зареден с тези тестове, нещата могат да станат направо грозни.

Ето го „The“ Intersection Observer!

Intersection Observer API предоставя начин за асинхронно наблюдение на промените в пресичането на целеви елемент с предшестващ елемент или с прозорец за изглед на документ от най-високо ниво. По-долу имаме друго решение, в JavaScript с помощта на Intersection Observers:

Това прави магията. Всеки път, когато наблюдателят види, че наблюдаваното изображение се пресича с прозореца за изглед, той задейства обратното извикване, което задава src на елемента на изображението към dataset.src.

Решихме да направим крачка напред и да изградим това в ъглова директива за лесна употреба в SPA/PWA. Приложението, където имахме нужда от него, беше Ionic/Angular SPA!

Следващият фрагмент показва как може да бъде изградена директива Angular за отложено зареждане на изображение с помощта на API на Intersection Observer

Сега използването на горната директива е доста лесно:

Имаме още един проблем за решаване! Когато изображението се зарежда лениво, в зависимост от размера на изображението, може да отнеме известно време, за да бъде изтеглено и показано. Искаме да покажем някакъв хубав контейнер през това време за добро потребителско изживяване. Решаваме го с помощта на базиран на CSS блестящ ефект, който стана доста популярен в наши дни.

CSS блестящ фрагмент за контейнер за изображение:

Просто увийте изображението си в div и поставете класа shimmer върху този div.

Като добавим всички части, имаме изображения с първоначален блестящ фон. Когато се пресича с прозореца за изглед, src се променя и се инициира извличане на реално изображение. Дотогава изображението блести и по-късно се заменя с оригинално изображение. Така имаме уебсайт, който се зарежда гладко и изглежда страхотно!

Поддръжка на браузър

За съжаление, не всички браузъри поддържат този страхотен API. В нашия код по-горе ние просто спасяваме и зареждаме изображението веднага, ако браузърът не поддържа API на Intersection Observer.

Поддръжката на браузъра за Intersection Observer може да бъде намерена тук.

Ако искате решението да работи и на неподдържани браузъри, можете да използвате polyfill: тук.