Vkontakte
+7 (499) 705-13-20
skype: kuzma.feskov

Адаптивные изображения (responsive images)

Автор: Кузьма Феськов, 1 апреля 2015

Всё началось с того, что наши проекты встали на тропу адаптивного дизайна (responsive design – а то некоторые пишут неправильно adaptive design).

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

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

Основной особенностью моего решения можно назвать то, что оно работает не только с тегом IMG, но и позволяет проводить манипуляции также с background: url(), что значительно упрощает жизнь нашему верстальщику.

Примеры адаптивной вёрстки изображений

 <div class="resp"
     img-array="{
                 800:'images/banner_large.jpg',
                 500:'images/banner_medium.jpg',
                   0:'images/banner_small.jpg'
                }"></div>

<img class="resp2"
     src="filename"
     img-array="{
                 800:'images/banner_large.jpg',
                 500:'images/banner_medium.jpg',
                   0:'images/banner_small.jpg'
                }" />

В данных примерах в DIV изображения помещены в виде CSS стиля background: url(), а у IMG, соответственно, мы используем атрибут SRC, как и положено.

Атрибут img-array содержит в себе альтернативные URL изображений для разных разрешений. Количество альтернативных изображений не ограничено тремя, количество их вы можете легко менять.

Как работает подмена изображений

$(document).ready(function () {
    $(window).resize(function () {
        $('.resp').responsibleImages({isImg: false, retinaPrefix: '@2x'});
        $('.resp2').responsibleImages({isImg: true, retinaPrefix: '@2x'});
    });

    $('.resp').responsibleImages({isImg: false, retinaPrefix: '@2x'});
    $('.resp2').responsibleImages({isImg: true, retinaPrefix: '@2x'});
});

Во-первых, вешаем вызов нашей функции на событие resize окна браузера. Это нужно для того, если кто-то решит поиграться размером окна и посмотреть на динамически меняющиеся изображения.

Во-вторых, вызываем функцию для проставления текущих изображений.

Как видно из примера, функцию мы вызываем дважды:

  • для DIV элементов, для которых изображения прописаны в CSS файле как background: url();
  • для IMG элементов, где будет подменяться атрибут SRC.

Контрольные точки описываются в виде JSON объекта. Где ключ – это контрольная точка, а значение – путь до файла и его название. Контрольная точка 0 должна быть всегда – она управляет значением по-умолчанию. Порядок следования значений не важен, функция отсортирует массив в нужном ей порядке.

Количество контрольных точек и их значение вы выбираете сами.

Перейдём к рассмотрению непосредственно кода jQuery плагина, управляющего адаптивными изображениями в SRC или CSS.

jQuery плагин для адаптивных изображений

Github репозиторий: https://github.com/kvf77/responsibleImages

 /**
 * Responsible Images.
 * http://www.sesmikcms.ru/blog/read/adaptivnye-izobrazhenija-responsive-images/
 *
 * Use:
 * change background: url():
 * <div class="resp"
 *      img-array="{
 *                  800:'images/banner_large.jpg',
 *                  500:'images/banner_medium.jpg',
 *                  0:'images/banner_small.jpg'
 *                 }">
 * </div>
 * $('.resp').responsibleImages({isImg: false, retinaPrefix: '@2x'});
 *
 * change img src:
 * <img class="resp2"
 *      src="filename"
 *      img-array="{
 *                  800:'images/banner_large.jpg',
 *                  500:'images/banner_medium.jpg',
 *                  0:'images/banner_small.jpg'}" />
 * $('.resp2').responsibleImages({isImg: true, retinaPrefix: '@2x'});
 *
 * options: {
 *     isImg : true|false, - true - change src, false - change background:url()
 *     retinaPrefix: {string} - this prefix will be added to the image
 *                              name before dot, if detected retina screen.
 * }
 *
 * @author        Kuzma Feskov <kfeskov@gmail.com>
 * @copyright     Copyright (c) 2015, Kuzma Feskov
 */
(function ($) {
    jQuery.fn.responsibleImages = function (options) {
        var data = eval('(' + $(this).attr('img-array') + ")");
        var arr = [];

        jQuery.each(data, function (key, val) {
            arr.push(key);
        });

        arr.sort(function (a, b) {
            return b - a
        });

        img = '';
        jQuery.each(arr, function (key) {
            if (img == '' && $(window).width() > arr[key]) {
                img = data[arr[key]];
            }
        });

        if ('devicePixelRatio' in window && window.devicePixelRatio >= 2) {
            img = img.replace(/\.(png|jpg|gif)+$/i, options['retinaPrefix'] + '.$1');
        }

        if (false !== options['isImg']) {
            $(this).attr('src', img);
        } else {
            $(this).css('background', 'url(' + img + ') no-repeat');
        }
    };
})(jQuery);

Обратите внимание на финальные строки функции. Именно они занимаются подменой URL изображения. Соответственно, вы можете расширить её возможности, добавляя нужные вам варианты работы с HTML или CSS.

Адаптивные изображения для retina-подобных экранов

Собственно, в своей работе функция опирается на значение 'devicePixelRatio'. Если это значение больше или равно 2, то мы делаем вывод, что у пользователя retina-подобный экран.

Определив это, функция добавляет к полученному URL изображения префикс, который вы указываете при вызове. В нашем примере URL image/banner_small.jpg превратится в image/banner_small@2x.jpg. То есть префикс дописывается к названию изображения перед расширением.

В комментариях к статье отвечу на любые вопросы и выслушаю пожелания к доработкам функции.