Ленивая загрузка с "отзывчивыми" изображениями (неизвестная высота)

Я использую сетку CSS, которая основана на процентах. У меня есть сетка с 4 столбцами, каждая 25% общей ширины страницы. Я выводил свои теги изображений внутри каждой "25% -ной ячейки" следующим образом:

<img src="foo.jpg" style="max-width:100%" />

По мере изменения размера браузера изображения также изменяются, чтобы заполнить 100% каждой ячейки 25%. Браузер выбирает высоту, как если бы я поместил "height: auto" (что неявно, когда опущено).

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

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

<img src="foo.jpg" style="max-width:100%" data-aspect="1.7742" />

Затем, когда событие "готово к документу", я просматриваю каждое изображение и устанавливаю фиксированное значение высоты в пикселях до ленивой загрузки:

$('img').each(function() {
        var img = $(this);
        var width = img.width();
        var ratio = img.data('aspectratio');
        var height = width / ratio;
        $(this).css('height', height+'px');
    });

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

Однако похоже, что это может вызвать новые проблемы, такие как изображения, растянутые по мере изменения размера браузера. Я должен был бы переключить "высоту" на "авто", когда обратный вызов срабатывает для завершения ленивой загрузки. Это позаботится о изображениях, которые видит пользователь, но изображения под слоем все равно будут иметь неправильное значение "высота" при изменении размера браузера. Каждый раз, когда размер браузера изменяется, мне придется выполнять итерацию всех изображений, которые были ранее под слоем, измерять их обновленную ширину, читать их соотношение сторон и обновлять новую высоту, а затем перезапускать ленивую загрузку, чтобы обрабатывать все, что сейчас находится выше фолд. Если я этого не сделаю, загрузка может быть вызвана слишком рано или слишком поздно из-за того, что изображения имеют неправильное значение высоты.

Мой вопрос: есть ли другие способы ленивых изображений загрузки с неизвестными высотами, кроме точного метода, который я описал здесь, и какие последствия это имеет? Есть ли недостатки в моем методе, кроме того, что это боль для программирования?

Ответ 1

Недавно у меня была аналогичная проблема, сочетающая Isotope с Lazy Загрузите в ответном макете. Изотоп определяет макет, основанный на ширине и высоте изображений при загрузке страницы, поэтому изначально элементы были перекрывающимися, потому что изотоп не вычислял правильный размер.

Чтобы убедиться, что элементы-заполнители сохраняли пространство, я использовал трюк подстановки: http://thisisthat.co.uk/notebook/2013-10-07-lazy-loading-responsive-images (хотя он может это не был точный пост.) Здесь моя разметка:

    <article class="portfolio-item">
        <a class="portfolio-link" href="img/gallery/thumb90.jpg" style="padding-bottom: 66.2%">
            <div class="portfolio-image-wrapper">
                <img class="portfolio-image" data-original="img/gallery/thumb90.jpg" width="1000" height="662">
            </div>
            <div class="portfolio-text">
                <h1 class="portfolio-item-name">
                    <span href="#" class="icon" data-icon="e"></span>
                    <span class="portfolio-item-tags">Bridals</span>
                </h1>
            </div>
        </a>
    </article>

Это, вероятно, более сложное, чем вам нужно (поскольку весь div.portfolio-text - это наложение, которое имеет довольно много стиля). Реальный ключ был просто в вычислении нижней надстройки на основе ширины и высоты изображения (что я сделал в шаблоне с PHP) и установки этого в качестве нижней части элемента, который я хотел сохранить.

Ответ 2

Еще более чистый:

  • Установить высоту и ширину изображений на произвольно большое число (например, 2000px x 1000px)
  • Примените следующий CSS для каждого из желаемых изображений (возможно, через общий класс):
    max-width: 100% и height: auto
  • Улыбка широко:)

Кредит для этого подхода относится к пользователю Github dryabove, указанному в этой проблеме Github

Ответ 3

Здесь более элегантное решение, из комментариев. Он по-прежнему требует записи стороны сервера формата, но с оберткой div:

<div class="lazy"><img src="foo.jpg" style="max-width:100%" data-aspect="0.75" /></div>

Затем с JS я даю обертку div a padding-bottom:

$('div.lazy').livequery(function() {
    var c = $(this);
    var r = c.data('ar');
    c.css('padding-bottom', r * 100 + '%');
});

Это дает div точные размеры, которые в конечном итоге потребляет img. Затем я использую следующий LESS для загрузки изображения в области, в которой padding потребляет:

div.lazy {
  max-width:100%;
  position:relative;
  img {
    position:absolute;
    width:100%;
    height:100%;
  }
}