Загрузка изображений «по запросу» с помощью CSS

Загрузка изображений по запросу с помощью CSS

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

Проблема

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

Предотвратите загрузку изображений

Первая проблема, которую нужно решить – как помешать браузеру изначально загрузить все изображения. Я испытал несколько методов, и единственный подошедший мне – это определить изображения как фоновые для некоторых элементов div и установить их родительский элемент на display: none. Почти все современные браузеры достаточно умны, чтобы не загружать фоновые изображения для скрытых элементов. Когда мы решим, что пора показать изображение, установим родительский элемент на display: block.

Когда начинать загрузку изображений?

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

Затем я обратил внимание, что курсор пользователя по время прокрутки страницы проходит над разными элементами. А что, если мы установим на странице несколько элементов div шириной во всю страницу (с классом .hoverer) и начнем загружать изображение при проведении над ним мышью? Это может сработать, но нельзя гарантировать, что пользователь проведет мышью над всеми элементами div первой страницы, чтобы мы смогли загрузить изображения со второй страницы. Это натолкнуло меня на следующую мысль – что, если с самого начала загружать все изображения первых двух страниц и устанавливать div.hoverer сверху изображений второй страницы. Как только пользователь проведет над ним мышью – мы загрузим изображения для третьей страницы. Третья страница точно так же будет содержать div.hoverer для четвертой страницы, и так далее.

Следующий вопрос: как определить размер страницы для того, чтобы изначально загрузить первые два экрана изображений? К сожалению, сделать это невозможно, но реально сделать их достаточно большими, чтобы они подходили под большинство экранов (предположительно, все изображения одинакового, заранее известного размера). Изучите нижеприведенную демонстрацию, чтобы получить представление о том, как это работает:

Оставляйте изображения видимыми, когда курсор убран

Вот проблема: даже если мы показываем/загружаем изображения при проведении мышью над связанным div.hoverer, изображение исчезает, когда пользователь убирает курсор с div.hoverer. Как сохранить состояние проведения мышью? Сначала я решил: нужно, чтобы элементы div.hoverer перекрывали друг друга с тем, чтобы при расположении курсора над одним элементом, он располагался над всеми элементами, над которыми мы уже проводили мышью. Но состояние проведения мышью не распространяется над элементами, и только верхний из них сможет его получить. Даже pointer-events: none не поможет нам в этой ситуации.

Что, если просто отложить появление display: none на родительском элементе изображения? Я пытался применить анимацию ключевого кадра, но у меня не получилось. К счастью, переход делает в точности то, что мне нужно. Вместо еще одного абзаца с объяснениями – посмотрите демо-пример.

Еще одна проблема – мы не можем отсрочить состояние display: block, так как это свойство CSS не поддается анимации, а переходы работают только с теми свойствами, которые можно анимировать. Еще один тупик? Не совсем.

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

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

Вот наш окончательный результат (сделайте высоту окна просмотра равной пяти тыквам, чтобы получить наилучшее впечатление). Из-за необходимости поддержки iframe.srcdoc демо-пример работает только в WebK’е, но можно заставить его работать кроссбраузерно, если поместить актуальный источник интракадров в разные файлы.

Это – довольно длинный путь к частично работающему решению. Рекомендую ли я его применять в эксплуатации? Ни в коем случае. Это определенно не лучший метод, но интересная задача, и некоторые ее части могут оказаться применимыми к настоящим сетевым приложениям. Надеюсь, работая над этим вопросом, вы получили такое же удовольствие, что и я. Если у вас есть идеи улучшения этого подхода – пожалуйста, не стесняйтесь связаться со мной.

Обновление:

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

Автор: Pavlo Pidlypenskyi

Источник: //flippinawesome.org/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии (1)