Для адаптации под различные разрешения экранов и различные устройства используют медиа-запросы в CSS. Допустим у нас заложена адаптация нашей верстки под 2 диапазона: от 0 до 479 пикселей и до 800 пикселей.
@media screen and (max-width: 800px) {
/* CSS */
}
/* И */
@media screen and (max-width: 479px) {
/* CSS */
}
Мы хотим использовать различную анимацию и/или запросы к серверу в зависимости от размера экрана. Т.е. нам необходимо параллельно срабатыванию меди-запроса из CSS реагировать в скриптах javascript. Для этого существует, как минимум, 3 способа.
Академический. Специальный метод javascript: window.matchMedia, определяющий срабатывание медиа-запроса, аналогичного CSS:
var mql = window.matchMedia('all and (max-width: 479px)');
if (mql.matches) {
// размер окна 479px или меньше
} else {
// нет, размер окна более 479px
}
Минусом данного метода считаю наличие явного указания диапазона разрешения экрана в 2-х местах: CSS и javascript. При изменении диапазона в CSS можно забыть поменять его в javascript, в результате мы получим баг в работе сайта, при определенной ширине окна верстка адаптируется, а соответствующая ей функциональность или анимация еще не подключится. Плюс существует ограничение поддержки данного метода в устаревших версиях браузеров.
Метод костыля №1. Самый простой и, наверное, очевидный метод — добавить в скрипт условие проверки текущего размера окна браузера.
К минусом данного метода относится также наличие дублирования размеров экрана в CSS и в javascript и некоторые проблемы с получением адекватных кроссбраузерных размеров окна на различных платформах.
Метод костыля №2. Теперь о методе, которым пользуюсь я. Заключается он в использовании html-флагов для каждого диапазона. В качестве флага может выступать реальная конструкция верстки, появляющаяся только в нужном нам диапазоне размеров, либо пустой однопиксельный div.
Html:
<!DOCTYPE html>
<html>
<head>
<title>Тест флагов</title>
</head>
<body>
<div class=”max_width_800”></div>
<div class=”max_width_479”></div>
</body>
</html>
CSS:
.max_width_800{
display: none;
}
.max_width_479{
display: none;
}
@media screen and (max-width: 800px) {
.max_width_800{
display: block;
}
.max_width_479{
display: none;
}
}
@media screen and (max-width: 479px) {
.max_width_800{
display: none;
}
.max_width_479{
display: block;
}
}
А в самом скрипте мы просто проверяем показан ли наш маркер:
if ($('.max_width_800').is(':visible')) {
// код jQuery
}
if ($('.max_width_479').is(':visible')) {
// код jQuery
}
В данном примере мы явно указываем диапазоны размеров экрана только в CSS и при изменении нам не нужно беспокоиться о работоспособности скриптов. Также на кроссбраузерность последнего примера влияет только поддержка браузером медиазапросов.
Идем дальше и подключаем мобильный скрипт только при условии необходимости:
var head = $('head');
includeScripts(head);
$(window).resize(function(){
includeScripts(head);
});
function includeScripts(head){
if ($('.max_width_800').is(':visible')) {
head.append('<script type="text/javascript" src="mobile-800.js" id=”script-mobile-800”></script>');
$('#script-mobile-479').remove();
}
if ($('.max_width_479').is(':visible')) {
head.append('<script type="text/javascript" src="mobile-479.js" id=”script-mobile-479”></script>');
$('#script-mobile-800').remove();
}
}
Спасибо за внимание!
Комментарии (14)
Kenya
05.01.2017 15:14Отказаться от явных идентификаторов в js и добавить явные идентификаторы в html — выгода все же сомнительная чутка
Lda
05.01.2017 15:16Вы не правильно поняли, явное указание диапазонов в моем примере есть только в одном месте — CSS, маркеры мы добавляем 1 раз, 1 раз пишем код скриптов и изменяя в будущем диапазон размера экрана не возвоащаемся ни в html ни в скрипты, все и так будет работать.
justboris
06.01.2017 00:21чтобы это было понятнее, можно классы назвать
max_width_mobile
,max_width_tablet
, а неmax_width_479
иmax_width_800
Lda
06.01.2017 00:55Можно, но я пытался сохранить связь с изначальными медиа-запросами, для сквозного понимания.
Lda
06.01.2017 01:02P.s. Нет никакой разницы для чего используются медиа-запросы, платформа может не меняться.
Mr_Boombastic
06.01.2017 01:04А что, если сделать, например, вот так:
CSS (Stylus, Rupture):
body:after display block +above('s') content 's' +above('m') content 'm' +above('l') content 'l'
JS (ES6, JQuery):
$(window).on('resize', () => { console.log(window.getComputedStyle(document.body, ':after').getPropertyValue('content')); });
Таким образом мы можем передать в js названия переменных, к которым привязан наш адаптив в css.Lda
06.01.2017 01:07Смысл сильно не меняется, как я и указал в статье, в роли маркера может выступать реальная конструкция верстки.
sashamorozov
06.01.2017 01:26Пока создавал своё небольшое решение подобной проблемы вы меня опередили :)
Но вот мой рабочий вариант: JSFiddle
Плюс, что не надо плодить и контролировать элементы в DOM, и с учетом mobile first вообще никаких проблем нет с определением min-width или max-width.Mr_Boombastic
06.01.2017 01:42+1И все-таки, узкое место в таком подходе — производительность .getComputedStyle()
Раз уж речь о переменных, то наверняка и какая-никакая система сборки имеется. В таком случае, имхо, самый роскошный вариант — подхватывать хэш, в котором хранятся диапазоны, и передавать его в тот-же webpack, например.
sashabeep
06.01.2017 14:19+1Тоже внезапно понадобилась похожая проверка изнутри скриптов, сейчас я часто использую Foundation, и там есть утилита для определения текущего значения вьюпорта, но каждый раз ее дергать расточительно, поэтому я клею класс к html
$(document).foundation(); function setBodyQuery(){ var viewport = "size-" + Foundation.MediaQuery.current; $('html').removeClass("size-xxlarge size-xlarge size-large size-medium size-small"); $('html').addClass(viewport) } //pass css viewport class on resize $(window).on('changed.zf.mediaquery', function(event, newSize, oldSize) { setTimeout(setBodyQuery(), 50) }); $(document).ready(function () { //pass css viewport class setBodyQuery(); //EODR });
И дальше в любом месте можно проверить, какой класс у html
BuccapuoH
Если я правильно понял, то вы чтобы не писать ширину экрана в двух местах (CSS, JS), решили писать ее в трёх (CSS, JS, HTML).
И даже если отбросить идентификаторы c явным указанием ширины, всеравно нужно следить за тремя местами. Это при том, что использование разных идентификаторов сделает код сложным для понимания людьми, которые его не писали.
Подход рабочий, я не спорю, но ради одного IE9 (Caniuse CSS Media Queries и Caniuse window.matchMedia) изобретать такой велосипед — ИМХО не стоит.
Lda
Да, вы правы, задействовано теперь 3 области, вместо 2-х, но целью было избавиться от явных идентификаторов (как вы правильно заметили), мне так удобнее.