Альтернативний метод прихованої завантаження зображень технікою прогресивного поліпшення

365

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

Курка чи яйце

JavaScript не може гарантувати стовідсоткове приховування HTML-зображень до їх завантаження: якщо скрипт буде виконаний не вчасно, користувач може помітити спалахи на екрані – зображення завантажується і тільки потім ховається за допомогою JS. Якщо ж зображення завантажуються виключно через JS, а скрипти відключені або не спрацювали, тоді користувач побачить голу сторінку.

Зазвичай для вирішення цієї проблеми використовують комбінацію старих та нових технік: прозорий фільтр у форматі GIF розміром 1х1 px розміщується в атрибуті src, а справжнє зображення data – атрибуті.

Потім JS замінює старе значення на нове, часто це робиться за події прокрутки:

var lazy = document.getElementsByClassName(‘lazy’);
for(var i=0; iОднак проблема блокування JS досі не вирішена. Для її рішення можна помістити даний зображення в тег noscript:

Контент всередині тега noscript відображається лише у випадку, якщо JS не підтримується. Якщо JS працює, то GIF фільтри замінюються нормальними зображеннями, а контент noscript ігнорується. Тим не менш, у цього підходу є два мінуси:

Контент на сторінці повторюється два рази (перший в атрибуті data-src, другий в тезі noscript), що ускладнює роботу з кодом.

Немає фолбэка на випадок якщо JS підтримується, але в коді є помилка: контент noscript відображатися не буде, а зображення не заміняться на нормальні, т. е. сторінка залишиться порожня.

Інший спосіб

На вихідних я придумав інший спосіб. Він відмінно працює з одним припущенням, якщо браузера підтримує CSS анімацію. Я завантажував зображення на сторінку, але залишав їх невидимими, якщо JS був активний.

Зображення на сторінці розміщуються як зазвичай: у нашому випадку я обернув їх у блок DIV з двома класами; атрибут alt я залишив порожнім для спрощення коду:






Зображень встановлено властивість opacity 0:

.shuffle img {
width: 33%;
opacity: 0;
}

До зображень також причеплена анімація, яка зробить прозорість рівною 1 через 1 секунду: недостатньо, щоб хтось помітив, але достатньо, щоб JS підхопив роботу:

@keyframes reveal {
to {
opacity: 1;
}
}
.reveal img {
animation: reveal 1s 1s forwards;
}

Анімацію можна зробити більш витонченою, додавши послідовне плавне поява в CSS:

.reveal img:nth-child(1) { animation-delay: .5s; }
.reveal img:nth-child(2) { animation-delay: 1s; }
.reveal img:nth-child(3) { animation-delay: 1.5 s; }

JavaScript

Скрипт знаходить елементи з класом reveal за допомогою querySelector і видаляє їх з допомогою методу classList. Після цього анімація не спрацює:

var reveal = document.querySelector(“.reveal”);
reveal.classList.remove(“reveal”);

Зображення в посиланнях все ще доступні скрипту:

var revealedImages = reveal.querySelectorAll(“img”),

…тобто зображення завантажуються, але приховано, поки їх не покажуть з допомогою JS. В теорії можна не задавати opacity:0 через CSS, а робити зображення невидимими безпосередньо з JS:

Array.prototype.forEach.call(revealedImages, function(photo) {
photo.style.display = “none”;
})

Цей підхід трохи ризикований. Для його роботи ніщо не повинно блокувати JavaScript.

Результат

Якщо JS не підтримується, або не спрацював код, зображення з анімацією плавно з’являться через секунду – від JS версії майже не відрізняється (поява можна зробити послідовним, якщо додати CSS). Якщо JS працює, зображення будуть приховані до тих пір, поки скрипт не змінить їх.

Я тестував демо з допомогою інструменту зниження швидкості з’єднання до 2G, код працював відмінно. Єдине, що мені не подобається в CSS, це те, як він вибирає час: якщо хоч щось завадило виконанню JavaScript, анімація буде запущена відразу ж. Тим не менш, веб-сторінки, спроектовані за сучасними стандартами продуктивності, повинні нормально працювати. Сподіваюся, даний метод був вам корисний.