Работаем с медиа-запросами через JavaScript
Перевод статьи: Marko Ilic — Working with JavaScript Media Queries
Что в первую очередь приходит на ум, когда вы думаете о медиа-запросах? Может быть, что-то типа такого в файле CSS:
body { background-color: plum; } @media (min-width: 768px) { body { background-color: tomato; } }
Медиа-запросы CSS — ключевой компонент любого адаптивного дизайна. Это отличный способ применить разные стили к разным контекстам, будь то на основе размера области просмотра, предпочтительной цветовой схемы, определенных взаимодействий и, черт возьми, даже определенных устройств, таких как принтеры, телевизоры и проекторы, и многих других.
Но знаете ли вы, что у нас есть медиа-запросы и для JavaScript? Это так! Возможно, мы не так часто видим их в JavaScript, но определенно есть варианты их использования, которые я на протяжении многих лет считаю полезными для создания адаптивных плагинов, таких как слайдеры. Например, при определенном разрешении вам может потребоваться перерисовать и пересчитать элементы слайдера.
Работа с медиа-запросами в JavaScript сильно отличается от работы с ними в CSS, хотя концепции схожи: сопоставьте некоторые условия и примените некоторые вещи.
Использование matchMedia()
Чтобы определить, соответствует ли документ строке медиа-запроса в JavaScript, мы используем метод matchMedia()
. Несмотря на то, что он официально является частью спецификации модуля представления объектной модели CSS, находящейся в статусе рабочего проекта, его поддержка браузером великолепна начиная с Internet Explorer 10 с глобальным охватом 98,6%.
Эти данные о поддержке браузера взяты из Caniuse, в котором есть более подробная информация. Число означает, что браузер поддерживает эту функцию в этой версии и выше.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
9 | 6 | 10 | 12 | 5.1 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
85 | 79 | 3 | 5.0-5.1 |
Использование почти идентично медиа-запросам в CSS. Мы передаем строку медиа-запроса в matchMedia(), а затем проверяем свойство .matches
.
// Define the query const mediaQuery = window.matchMedia('(min-width: 768px)')
Определенный медиа-запрос вернет объект MediaQueryList
. Это объект, который хранит информацию о медиа-запросе, и нам нужно ключевое свойство .matches. Это логическое свойство только для чтения, которое возвращает true, если документ соответствует мультимедийному запросу.
// Создаем медиа условие, проверяющее viewports на ширину не менее 768 пикселей. const mediaQuery = window.matchMedia('(min-width: 768px)') if (mediaQuery.matches) { alert('Media Query Matched!') }
Это базовое использование для сопоставления условий медиа запросов в JavaScript. Мы создаем условие соответствия (matchMedia()), которое возвращает объект (MediaQueryList), проверяем его (.matches), а затем делаем что-то, если условие оценивается как true.
Но это еще не все. Например, если бы мы изменим размер окна, ничто само по себе не обновиться в отличии от CSS. Это потому, что .matches идеально подходит для одноразовых мгновенных проверок, но оно не может постоянно проверять наличие изменений. Значит, нам нужно что то еще…
Отслеживание изменений
MediaQueryList имеет метод addListener() (и последующий removeListener()), который принимает функцию обратного вызова (представленную событием .onchange), которая вызывается при изменении статуса медиа-запроса. Другими словами, мы можем запускать дополнительные функции при изменении условий, что позволяет нам «реагировать» на обновленные условия. Пример использования:
const mediaQuery = window.matchMedia('(min-width: 768px)') function handleTabletChange(e) { if (e.matches) { console.log('Media Query Matched!') } } mediaQuery.addListener(handleTabletChange) handleTabletChange(mediaQuery)
Один-два шага matchMedia() и MediaQueryList дают нам такую же возможность не только соответствовать условиям медиа-запроса, которые предоставляет CSS, но и активно реагировать на обновленные условия.
Когда вы регистрируете слушатель событий с помощью addListener(), он изначально не запускается. Нам нужно вызвать функцию обработчика событий вручную и передать медиа-запрос в качестве аргумента.
Старый способ
Ради справки — и немного ностальгии — я хотел бы осветить старый (хотя все еще популярный) способ выполнения «медиа-запросов» в JavaScript. Наиболее распространенный подход — привязка слушателя событий изменения размера, который проверяет window.innerWidth или window.innerHeight.
Вы все еще можете столкнуться с таким кодом:
function checkMediaQuery() { if (window.innerWidth > 768) { console.log('Media Query Matched!') } } window.addEventListener('resize', checkMediaQuery);
Поскольку событие изменения размера вызывается при каждом изменении размера браузера, это дорогостоящая операция! Глядя на влияние пустой страницы на производительность, мы можем увидеть разницу.
Еще более простой способ увидеть разницу — с помощью журнала консоли.
Даже если не обращать внимания на проблемы с производительностью, изменение размера является ограничительным в том смысле, что не позволяет нам писать расширенные медиа-запросы для таких вещей, как печать и ориентация. Таким образом, хотя он и имитирует поведение «медиа-запроса», позволяя нам согласовывать ширину области просмотра, он не способен сопоставить большую часть чего-либо еще — и мы знаем, что настоящие медиа-запросы способны на гораздо большее.
Заключение
В этой статье мы рассмотрели медиа-запросы в JavaScript! Мы узнали о matchMedia(), которое позволяет нам определять условия медиа запросов, и рассмотрели объект MediaQueryList, который позволяет нам выполнять одноразовые (.matches) и постоянные (addListener()) проверки условий, чтобы мы могли реагировать на изменения (.onchange) вызывая соотвествующие функции.
Мы также рассмотрели «старый» способ, отслеживая события изменения размера в окне. Хотя он по-прежнему широко используется и является вполне обычным способом реагировать на изменения размера window.innerWidth, он не может выполнять проверки расширенных условий медиа запросов.
В завершение статьи приведем полезный пример, который невозможно реализовать по-старому. С помощью медиа-запроса проверю, находится ли пользователь в ландшафтном режиме. Этот подход распространен при разработке игр HTML5, и его лучше всего просматривать на мобильном устройстве.
https://codepen.io/rema/pen/xxVqarV
Спасибо за перевод.
Ранеше его использовал, но не знал что можно повесить на него обработчик.
И на MDN сказано, что лучше использовать
addEventListener
иremoveEventListener
вместоaddListener
иremoveListener
соответственно.