Інтро
Вам, напевно, доводилося використовувати медіа-запити для адаптації вашого сайту під різні пристрої, і ви могли писати щось на зразок:
@media only screen and (max-width: 768px) {
/* ... */
}
Але чи знали ви, що спектр можливостей @media
набагато ширший? Далі ми розберемо цікаві й незвичні способи використання @media
, але спочатку коротко згадаємо основи медіа-запитів. Якщо ви вже знайомі з основами, можете одразу перейти до незвичайних способів використання медіа-запитів.
Основи @media
і медіа-запитів
@media
і медіа-запити часто вважають одним і тим самим, але між ними є невелика відмінність:
-
@media
— це @-правило (at-rule) в CSS, яке використовується для оголошення медіа-запиту. Воно застосовує певні стилі тільки в тому випадку, якщо задані умови для медіа-запиту є правдивими. -
Медіа-запит (media query) — це умова, що міститься в
@media
і перевіряє певні параметри поточного пристрою (наприклад, ширину, висоту, орієнтацію тощо). -
@-правило (at-rule) в CSS — це команда, яка починається зі знаку
@
і використовується для керування поведінкою стилів. @-правила дозволяють CSS вказувати особливі інструкції для браузера. Крім@media
, існують й інші @-правила, наприклад:@import
— дозволяє імпортувати інші CSS-файли.@font-face
— використовується для оголошення власних шрифтів.@keyframes
— визначає анімацію з ключовими кадрами.@container
— дозволяє застосовувати стилі на основі розмірів або інших властивостей контейнера елемента.
Отже, повертаючись до нашого прикладу:
@media only screen and (max-width: 768px) {
/* ... */
}
@media
— це @-правило.only screen and (max-width: 768px)
— це медіа-запит.
Кожен медіа-запит може складатися з:
-
Медіа-типів (<media-type>) — це типи пристроїв, на які застосовуються стилі. Наприклад:
screen
: для екранів (комп’ютерів, телефонів, планшетів).print
: для друку.all
: для всіх медіа-типів.
-
Медіа-фіч (<media-feature>) — це характеристики пристрою, які перевіряються у медіа-запитах, щоб застосувати потрібні стилі. Наприклад:
width
: ширина області перегляду.height
: висота області перегляду.orientation
: орієнтація екрану (portrait
чиlandscape
).
-
Логічних операторів (Logical operators) — дозволяють комбінувати медіа-тип та медіа-фічі в одному запиті:
and
: для одночасного виконання всіх умов.or
: для виконання хоча б однієї з умов.not
: для виключення певних умов.only
: обмежує застосування стилів тільки до конкретних медіа-типів або умов, ігноруючи сумісність зі старішими браузерами.,
(кома): для об’єднання кількох медіа-запитів (аналогічно логічному “або”).
Тепер давайте розберемо медіа-запит із нашого прикладу:
@media only screen and (max-width: 768px) {
/* ... */
}
-
only
— обмежує дію стилів тільки для пристроїв із підтримкою медіа-запитів. Раніше це було актуально, оскільки старі браузери без підтримки медіа-запитів інтерпретувалиscreen and (max-width: 768px)
якscreen
, ігноруючи решту запиту, таким чином застосовуючи стилі всередині на всіх екранах. Але тут варто зазначити, що коли ми говоримо “старі браузери”, то ці браузери дійсно дуже старі. Це буквально Internet Explorer 8 і нижче. Тож у сучасному коді проonly
можна сміливо забути. -
screen
— медіа-тип, який вказує, що стилі застосовуються тільки для екранних пристроїв (наприклад, моніторів, смартфонів, планшетів). -
and
— логічний оператор, який використовується для об’єднання кількох медіа-фіч в один медіа-запит. У цьому випадку медіа-тип і медіа-фічу. -
(max-width: 768px)
— медіа-фіча, яка вказує, що стилі будуть застосовуватися тільки для екранів із шириною включно до 768 пікселів.
Отже, цей медіа-запит обмежує стилі для екранів шириною включно до 768 пікселів.
Ключове слово only
можна вважати залишком минулого, тому запит можна спростити до:
@media screen and (max-width: 768px) {
/* ... */
}
Незвичні способи використання медіа-запитів
Крім звичного використання медіа-запитів у CSS, як показано в прикладах вище, існують й інші, не менш корисні способи:
@import
Ви можете комбінувати медіа-запит із @import
для умовного завантаження CSS-файлів. Наприклад:
@import url('styles.css') screen and (min-width: 768px);
HTML
Атрибут media
можна використовувати в HTML-елементах, таких як:
<link>
<link rel="stylesheet" href="styles.css" media="screen and (max-width: 768px)" />
- У цьому випадку, якщо ширина екрану менша або дорівнює
768px
, стилі з файлуstyles.css
будуть завантажені і застосовані. - Але, якщо ширина екрану більша за
768px
,styles.css
все одно буде завантажено (без блокування візуалізації), але стилі не будуть застосовані.
Давайте ще раз:
- Якщо медіа-запит атрибуту
media
оцінюється якtrue
(у цьому випадку, якщо ширина менша або дорівнює768px
), то цей.css
файл і його вміст буде завантажено з блокуванням візуалізації, і його стилі будуть застосовані як зазвичай. - Але якщо медіа-запит оцінюється як
false
, то файл буде завантажено без блокування візуалізації, і стилі застосовані не будуть.
<style>
<style media="screen and (max-width: 768px)">
/* ... */
</style>
- Якщо медіа-запит виконується, стилі всередині
<style>
будуть застосовані, інакше — ні.
<source>
<picture>
<source srcset="image.webp" type="image/webp" media="(min-width: 768px)" />
<img
src="image.jpg"
alt="An image
"
/>
</picture>
- Якщо медіа-запит виконується, використовується
image.webp
, інакше —image.jpg
.
Атрибут sizes
Крім атрибуту media
у прикладах вище, медіа-запити також використовуються в атрибуті sizes
для вказівки розміру зображення в <img>
або <source>
. Наприклад:
<img
src="image.jpg"
alt="An image"
sizes="(max-width: 768px) 100vw, 50vw"
srcset="image-400.jpg 400w, image-800.jpg 800w"
/>
- Атрибут
sizes
вказує браузеру, якою буде ширина зображення залежно від умов медіа-запиту. - У цьому випадку, якщо ширина екрану менша або дорівнює
768px
, зображення буде шириною100vw
, інакше —50vw
.
window.matchMedia
І, нарешті, ви можете використовувати JavaScript для перевірки медіа-запитів. Для цього використовується метод window.matchMedia
, який повертає об’єкт MediaQueryList, який можна використовувати для:
- Миттєвої перевірки: визначення, чи відповідає документ заданому медіа-запиту (
.matches
). - Відстеження змін: реагування на зміни, коли документ починає або перестає відповідати медіа-запиту (
.addListener
).
Приклад використання ви зможете побачити трохи далі в секції з prefers-color-scheme
.
Незвичні медіа-фічі
Розібравшись з основами медіа-запитів і усіма способами їх використання, давайте розглянемо деякі цікаві медіа-фічі. Крім стандартних — таких як ширина, орієнтація тощо, існує ще цілий ряд медіа-фіч, які можуть стати в нагоді.
Повний список можна подивитись тут, а ми з вами розглянемо найбільш цікаві, на мою думку.
prefers-color-scheme
- Дозволяє визначити, чи віддав користувач перевагу світлій або темній темі інтерфейсу на поточному девайсі.
Нижче найпростіший спосіб використання цієї фічі:
body {
color: black;
background-color: white;
}
@media (prefers-color-scheme: dark) {
body {
color: white;
background-color: black;
}
}
Але, як правило, сайти або додатки, які підтримують темну і світлу теми, мають також можливість вибору теми користувачем. Яскравий приклад — це сайт блогу, який ви зараз читаєте.
За замовчуванням тема визначається відповідно до prefers-color-scheme
, а потім, якщо ви вирішите її змінити, вибір буде збережено в local storage
, і далі тема буде застосована на основі вашого попереднього вибору.
В коді це може виглядати так:
type Theme = 'light' | 'dark';
function getTheme(): Theme {
const localStorageTheme = localStorage.getItem('theme');
if (localStorageTheme === 'light' || localStorageTheme === 'dark') {
return localStorageTheme;
} else {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
}
Зверну вашу увагу на використання функції window.matchMedia
, про яку ми згадували раніше.
pointer
/any-pointer
pointer
і any-pointer
дозволяють визначити, чи має користувач вказівник (pointer) (наприклад, мишка або стилус), і якщо так, то наскільки точним є цей пристрій. Це дає змогу адаптувати стилі та взаємодію на сторінці відповідно до можливостей пристрою.
Можливі значення:
none
: Не має вказівника.coarse
: Вказівник з обмеженою точністю, наприклад, палець на сенсорному екрані.fine
: Точний вказівник, такий як мишка або стилус.
Але в чому ж все ж таки різниця між pointer
та any-pointer
?
А в тому, що pointer
враховує лише основний механізм введення, тоді як any-pointer
враховує будь-який.
Наприклад, у вас є планшет з підключеним стилусом, в такому випадку всі наступні три медіа-запити будуть виконані:
@media (pointer: coarse)
— тому що основний механізм введення — палець, який не відрізняється своєю точністю.@media (any-pointer: fine)
— тому що на планшеті підключений стилус, який є точним вказівником.@media (any-pointer: coarse)
— тому що, попри те, що у вас є стилус, палець все ще при вас :)
Приклад використання:
/* Стилі для точних пристроїв вказівника */
@media (pointer: fine) {
button {
padding: 10px;
}
}
/* Стилі для пристроїв з обмеженою точністю вказівника */
@media (pointer: coarse) {
button {
padding: 20px;
}
}
У цьому прикладі кнопки отримують різні відступи залежно від точності вказівника.
hover
/ any-hover
Медіа-фічі hover
і any-hover
перевіряють, чи механізм введення користувача може наводити курсор на елементи. Вона має два можливі значення:
hover
: пристрій введення підтримує hover (наприклад, миша або трекпад).none
: пристрій введення не підтримує hover.
Різниця між hover
і any-hover
аналогічна різниці між pointer
і any-pointer
. hover
враховує лише основний механізм введення, тоді як any-hover
враховує будь-який.
Наприклад, на телефоні з підключеною мишею наступні три медіа-запити будуть виконані:
@media (hover: none)
— тому що основний пристрій введення — це ваш палець, а його hover не розпізнається :).@media (any-hover: hover)
— тому що на телефоні підключена мишка, яка підтримує наведення.@media (any-hover: none)
— тому що, попри те, що у вас є миша, на телефоні все ще можна використовувати сенсорний екран.
Приклад використання:
/* Стилі для пристроїв, які не підтримують hover */
@media (hover: none) {
.tooltip {
display: none;
}
}
У цьому прикладі, якщо пристрій не підтримує hover, то елемент з класом .tooltip
буде приховано.
update
MDN Link
Дозволяє визначити, як часто пристрій може оновлювати відображення контенту після його рендерингу.
Можливі значення:
none
: пристрій не може оновлювати відображення після рендерингу. Приклад: друковані матеріали.slow
: пристрій може оновлювати відображення, але з низькою частотою, що не підходить для плавних анімацій. Приклад: електронні книги.fast
: пристрій може швидко оновлювати відображення, підтримуючи плавні анімації. Приклад: сучасні монітори.
Приклад використання:
@media (update: fast) {
.animated-element {
animation: slide 2s infinite;
}
}
@media (update: slow) {
.animated-element {
animation: none;
}
}
В даному прикладі анімація не буде відтворюватись, якщо ви будете переглядати сторінку, скажімо, на вашій електронній книзі.
Інші:
Ще є багато медіа-фіч, які можуть вас зацікавити, ви можете знайти повний список на MDN. Коротко можу ще виділити:
prefers-reduced-motion
— визначає, чи користувач бажає мінімізувати анімації.prefers-contrast
— визначає, чи користувач бажає збільшити або зменшити контрастність.display-mode
— визначає, яким чином відображається сторінка (наприклад, в окремому вікні, на повноекранному режимі тощо).
Кінець
Дякую за увагу, сподіваюсь, ця інформація була корисною.
Якщо у вас є які-небудь питання або коментарі, пишіть на будь-яку з моїх соціальних мереж, які ви можете знайти внизу сторінки.