Любой медиа-запрос можно выполнить в реальном времени с помощью 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();
}
}());
}
Полный код модуля доступен на Гитхабе.
Коментарии к заметке
Коллега недавно реализовал «style-detector» через counter-reset с идентификатором в качестве значения. Получилось красиво, можно задавать осмысленные имена и детектить их
Сергей, да, идея годная. Технически, можно использовать любые свойства, которые не меняют размеров блока (он должен оставаться 0×0, чтобы не влиять на соседей) и легко определяются. Так например, цвет не очень подходит из-за того, что он может быть записан в разных форматах.
Кстати, я попробовал в Хроме:
В итоге мне вернулась строка
"test 0". Получается, что точного сравнения с именем сделать не выйдет? Можно где-нибудь глянуть вашу реализацию?Еще один более «семантический» способ, использовать
content.sladex, с Иешечкой будут проблемы. Чтение свойств псевдо-элементов через
getComputedStyleпоявилось только в IE11.Я спутал мнение с фактом :) Полез в код, там оказался jQuery.css()