Завантаження зображень «по запиту» за допомогою CSS

16

Від автора: мозок – це м’яз, і як всі м’язи, вимагає регулярних вправ для збереження гостроти, ось чому я вирішив взяти дуже стару, але дієву методику веб-оптимізації та виконати її новим, божевільним способом. Ви напевно чули про завантаження зображень (та інших ресурсів) за запитом – що є не тільки розсудливим рішенням, але і хорошим спосіб прискорити вихідну завантаження сторінки. Зазвичай він виконується за допомогою JavaScript, але сьогодні я поділюся з вами, як добитися того ж ефекту з допомогою чистого CSS.

Проблема

Спочатку визначимо походження проблеми. Уявіть собі, що у нас є набір зображень для показу користувачеві, але лише деякі з них стануть видні після початкового завантаження сторінки. Решта будуть сидіти під нижньою межею видимої області, куди, можливо, ви ніколи не прокрутить сторінку. Тому має сенс завантажувати ці зображення після того, як він почне прокручувати сторінку вниз.

Запобіжите завантаження зображень

Перша проблема, яку треба вирішити – як перешкодити браузеру завантажити всі зображення. Я випробував кілька методів, і єдиний, хто підійшов мені – це визначити як фонові зображення для деяких елементів div і встановити їх батьківський елемент на display: none. Майже всі сучасні браузери достатньо розумні, щоб не завантажувати фонові зображення для прихованих елементів. Коли ми вирішимо, що пора показати зображення, встановимо батьківський елемент на display: block.

Коли починати завантаження зображень?

Далі давайте подумаємо про те, які стилі або селектори CSS змінюються по мірі прокручування, щоб визначити, як вловити момент початку запиту на певне зображення. Моїм першим підходом було застосування position: sticky, тому що воно веде себе всередині свого батьківського елемента як position: relative до того, як зустрінеться з даними офсетним порогом у вікні перегляду (іншими словами, коли користувач прокрутив до певного місця). Після цієї точки елемент стане вести себе, як position: fixed. На жаль, навколишні елементи не помічають зміни і зберігають своє розташування і стилі.

Потім я звернув увагу, що курсор користувача за час прокручування сторінки проходить над різними елементами. А що, якщо ми встановимо на сторінці кілька елементів div шириною на всю сторінку (з класом .hoverer) і почнемо завантажувати зображення при проведенні над ним мишею? Це може спрацювати, але не можна гарантувати, що користувач проведе мишею над усіма елементами div першої сторінки, щоб ми змогли завантажити зображення з другої сторінки. Це наштовхнуло мене на таку думку – що, якщо з самого початку завантажувати всі зображення перших двох сторінок і встановлювати div.hoverer зверху зображень другої сторінки. Як тільки користувач проведе над ним мишею – ми завантажимо зображення для третьої сторінки. Третя сторінка точно так само буде містити div.hoverer для четвертої сторінки, і так далі.

Завантаження зображень «по запиту» за допомогою CSS

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

Залишайте зображення видимими, коли курсор прибраний

Ось проблема: навіть якщо ми показуємо/завантажуємо зображення при проведенні мишею над пов’язаним div.hoverer, зображення зникає, коли користувач прибирає курсор div.hoverer. Як зберегти стан проведення мишею? Спочатку я вирішив: треба, щоб елементи div.hoverer перекривали один одного з тим, щоб при розташуванні курсору над одним елементом, він розташовувався над усіма елементами, над якими ми вже проводили мишею. Але стан проведення мишею не поширюється над елементами, і тільки верхній з них зможе його отримати. Навіть pointer-events: none не допоможе нам в цій ситуації.

Що, якщо просто відкласти появу display: none на батьківському елементі зображення? Я намагався застосувати анімацію ключового кадру, але у мене не вийшло. На щастя, перехід робить в точності те, що мені потрібно. Замість ще одного абзацу з поясненнями – подивіться демо-приклад.

Ще одна проблема – ми не можемо відстрочити стан display: block, так як це властивість CSS не піддається анімації, а переходи працюють лише з тими властивостями, які можна анімувати. Ще один глухий кут? Не зовсім.

Я роблю перехід ширини елемента і застосовую до нього медиазапрос. У медиазапросе можна встановити відношення між шириною елемента і його видимістю. Ой, але ж не можна встановлювати медиазапрос до окремого елементу HTML; їх можна застосовувати тільки до вікна перегляду. Це означає, що нам потрібно помістити зображення в окремі вікна перегляду (тобто интракадры). Можна застосувати iframe.srcdoc для того, щоб для кожного відображуваного нами зображення не потрібен був окремий URL.

Результати і коментарі

Ось наш остаточний результат (зробіть висоту вікна перегляду дорівнює п’яти гарбузам, щоб отримати найкраще враження). Через необхідність підтримки iframe.srcdoc демо-приклад працює лише в WebK’е, але можна змусити його працювати кроссбраузерно, якщо помістити актуальне джерело интракадров в різні файли.

Завантаження зображень «по запиту» за допомогою CSS

Це – досить довгий шлях до частково працює рішенням. Рекомендую я його застосовувати в експлуатації? Ні в якому разі. Це безумовно не найкращий метод, але цікаве завдання, і деякі її частини можуть виявитися придатними до справжнім мережевим додаткам. Сподіваюся, працюючи над цим питанням, ви отримали таке ж задоволення, що і я. Якщо у вас є ідеї щодо поліпшення цього підходу – будь ласка, не соромтеся зв’язатися зі мною.

Оновлення:

Схоже, що спосіб вирішення проблеми перших двох екранів. Можна взяти елемент div з розміром вікна перегляду (використавши height: 100vh;). Цей елемент буде містити набір зображень, обгорнутих в iframe, як мій демо-приклад. Набір повинен бути достатньо великим для того, щоб заповнити перші два екрани, і у мене буде набір медиазапросов для показу різних під наборів зображень в залежності від висоти вікна перегляду.