Заметки с тегом «responsive»

Динамическая загрузка «отзывчивых» ресурсов

Любой медиа-запрос можно выполнить в реальном времени с помощью JavaScript. Создать экземпляр объекта, который возвращал бы результат проверки Media Query или оповещал бы об изменении этого результата, можно при помощи метода .matchMedia(). Все современные браузеры уже реализовали этот метод в объекте window. Если же вам нужна поддержка старых браузеров, то можно воспользоваться полифилом matchMedia.js.

var mql = window.matchMedia("(min-width: 720px)");
if (mql.matches) {
  // десктоп или планшет
} else {
  // мобильник
}

Теперь, когда мы знаем как организовать ветвление, основываясь на результате выполнения медиа-запроса, подгрузить «тяжелые» стили и скрипты можно только если они действительно необходимы.

var Environment = (function () {
  var _mqDesktop;

  function getDesktopMediaQuery() {
    return _mqDesktop ||
      (_mqDesktop = window.matchMedia("(min-width: 720px)"));
  }

  function isDesktop() {
    return !!(window.matchMedia && getDesktopMediaQuery().matches);
  }

  function once(mq, callback) {
    function handler() {
      mq.removeListener(handler);
      callback();
    }
    mq.addListener(handler);
  }

  return {
    /**
     * Test the environment against “desktop” media query
     */
    isDesktop: isDesktop,
    /**
     * Invoke callback when the environment becomes like “desktop”.
     */
    waitForDesktop: function (callback) {
      if (isDesktop()) {
        callback();
      } else {
        once(getDesktopMediaQuery(), callback);
      }
    }
  };

})();

Далее в коде приложения сделать вызов:

Environment.waitForDesktop(function () {
  Modernizr.load([
    "/styles/desktop.css",
    "/scripts/desktop.js"
  ]);
});

Таким образом, файл стилей /styles/desktop.css и скрипт /scripts/desktop.js загрузятся только когда ширина экрана будет больше 720 пикселей.

Из-за того, что файлы загружаются асинхронно появляется побочный эффект — нет никакой гарантии, что выполнение скрипта начнётся только после применения стилей. Например, габариты блока будут не верны или блок вообще может быть невидимым во время инициализации компоненты. Это нужно учесть и дождаться полной загрузки CSS файла с перерисовкой страницы.

Проверить, что файл стилей гарантировано применился можно с помощью специальных стилей-маркеров.

mobile.css:

.style-detector {
  z-index: 1;
}

desktop.css:

@media (min-width: 720px) {
  .style-detector {
    z-index: 2;
  }
}

А колбек обернуть в функцию, которая ожидает нужного значения свойства z-index.

function waitUntil(value, cb) {
  var body, detector = document.querySelector(".style-detector");
  if (!detector) {
    detector = document.createElement("div");
    detector.className = "style-detector";
    body = document.getElementsByTagName("body")[0];
    body.insertBefore(detector, body.firstChild);
  }

  function getStyle(el, cssProperty) {
    return (getComputedStyle !== "undefined") ?
      getComputedStyle(el)[cssProperty] : el.currentStyle[cssProperty];
  }

  var i = 100; // timeout = 25 sec
  (function loop() {
    var v = getStyle(detector, "zIndex");
    if (v != value) {
      i = i - 1;
      if (i >= 0) {
        setTimeout(loop, 250);
      } else {
        cb();
      }
    } else {
      cb();
    }
  }());
}

Полный код модуля доступен на Гитхабе.

Комментарии к заметке: 5