В этой статье мы поговорим о том, как адаптировать наши сайты в зависимости от типа устройства: есть ли у него указатель или нет, и насколько он точен. Чтобы адаптировать наш сайт к возможностям этих устройств, мы поговорим о том, как правильно использовать специальные медиа-запросы hover
, pointer
, any-hover
и any-pointer
.
Интернет полон интерактивности, и чаще всего, чтобы показать, что с данным элементом можно взаимодействовать, мы используем псевдокласс :hover
. В конце концов, разве не будет лучшим показателем интерактивности элемента, если при наведении курсора на этот элемент, он будет немного видоизменяться?
Основная проблема с таким подходом заключается в том, что необходимо учитывать огромное количество устройств, которые могут использоваться для просмотра веб-страниц: вы можете читать эту статью на мобильном телефоне, планшете или даже на смарт-телевизоре!
Обычно это не является серьезной проблемой, потому что потеря некоторой интерактивности не оказывает критического влияния на восприятие контента. Но в некоторых случаях, если не учитывать всего разнообразия устройств, которые используют люди, то это может создать определенные трудности с удобством использования и доступностью вашего сайта.
Однако, благодаря CSS мы можем обнаружить все эти нюансы, используя четыре медиа-запроса (или, если быть более точным, медиа-функции): hover
, pointer
, any-hover
и any-pointer
. В этой статье мы подробно расскажем о каждом из них и покажем несколько примеров того, как использовать эти медиа-запросы для адаптации ваших сайтов к различным устройствам, доступным сегодня.
Медиа-запрос hover: Распознавание механизма наведения
Медиа-запрос hover
позволяет определить, может ли основной механизм ввода пользователя наводить курсор на элементы. Для него есть два значения:
none
- срабатывает, когда основной механизм ввода не может навести курсор, как на большинстве мобильных телефонов и планшетов.hover
- срабатывает, когда основной механизм ввода может наводить курсор на элементы (например, настольные компьютеры, ноутбуки и смартфоны со стилусом).
Имейте в виду, что, хотя в мобильном телефоне нет механизма ввода, который может наводить курсор на элементы, он может эмулировать эту функцию с помощью длительного нажатия, что может быть неудобно и создавать некоторые проблемы с удобством использования.
С учетом сказанного давайте приведем небольшой пример, демонстрирующий, как можно использовать этот медиа-запрос на практике.
Предположим, у нас есть кнопка, и мы хотим изменить ее цвет и размер при наведении на нее, но мы хотим, чтобы это происходило только на устройствах, поддерживающих наведение. В этом случае единственное, что нам нужно будет сделать, это поместить стиль .button:hover
внутри медиа-запроса hover:
<style>
.button {
padding: 0.5em 1em;
font-size: 1.125rem;
border-radius: 0.6em;
background-color: coral;
font-weight: bold;
border: 1px solid transparent;
transition: background-color 200ms ease-in-out;
}
@media (hover: hover) {
.button:hover {
background-color: hotpink;
}
}
</style>
<button class="button">Наведи на меня</button>
Это очень простой пример, который не влияет на удобство использования на устройствах без наведения курсора.
Теперь давайте посмотрим на более комплексный пример, где в определенный момент удобство использования может пострадать. Давайте взглянем на такую карточку.
И для нее нам нужно добавить следующие анимации:
- Изначально будет виден только заголовок (без подчеркивания).
- Когда пользователь наводит курсор на карточку, она смещается вверх, освобождая пространство для остального содержимого.
- Также, размер карточки немного увеличивается, а изображение на заднем плане тоже становится больше.
- После этого слева появляется подчеркивание и вытягивается до конца заголовка.
- Когда анимация подчеркивания закончится, текст и кнопка исчезают.
Помня об этих требованиях, давайте добавим разметку и таблицу стилей для такой карточки без анимации.
<article class="card">
<img
class="card__background"
src="https://i.imgur.com/QYWAcXk.jpeg"
alt="Photo of Cartagena's cathedral at the background and some colonial style houses"
width="1920"
height="2193"
/>
<div class="card__content | flow">
<div class="card__content--container | flow">
<h2 class="card__title">Colombia</h2>
<p class="card__description">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rerum in
labore laudantium deserunt fugiat numquam.
</p>
</div>
<button class="card__button">Read more</button>
</div>
</article>
@import url("https://fonts.googleapis.com/css2?family=Lato:wght@400;700&family=Montserrat:wght@700&display=swap");
:root {
/* Colors */
--brand-color: hsl(46, 100%, 50%);
--black: hsl(0, 0%, 0%);
--white: hsl(0, 0%, 100%);
/* Fonts */
--font-title: "Montserrat", sans-serif;
--font-text: "Lato", sans-serif;
}
/* СБРОС НАСТРОЕК */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Убираем отступы по умолчанию */
body,
h2,
p {
margin: 0;
}
/* ГЛОБАЛЬНЫЕ СТИЛИ */
body {
display: grid;
place-items: center;
height: 100vh;
}
h2 {
font-size: 2.25rem;
font-family: var(--font-title);
color: var(--white);
line-height: 1.1;
}
p {
font-family: var(--font-text);
font-size: 1rem;
line-height: 1.5;
color: var(--white);
}
.flow > * + * {
margin-top: var(--flow-space, 1em);
}
/* КОМПОНЕНТ КАРТОЧКИ */
.card {
display: grid;
place-items: center;
width: 80vw;
max-width: 21.875rem;
height: 31.25rem;
overflow: hidden;
border-radius: 0.625rem;
box-shadow: 0.25rem 0.25rem 0.5rem rgba(0, 0, 0, 0.25);
}
.card > * {
grid-column: 1 / 2;
grid-row: 1 / 2;
}
.card__background {
object-fit: cover;
max-width: 100%;
height: 100%;
}
.card__content {
--flow-space: 0.9375rem;
display: flex;
flex-direction: column;
justify-content: space-between;
align-self: flex-end;
height: 55%;
padding: 12% 1.25rem 1.875rem;
background: linear-gradient(
180deg,
hsla(0, 0%, 0%, 0) 0%,
hsla(0, 0%, 0%, 0.3) 10%,
hsl(0, 0%, 0%) 100%
);
}
.card__content--container {
--flow-space: 1.25rem;
}
.card__title {
position: relative;
width: fit-content;
width: -moz-fit-content; /* С префиксом для Firefox */
}
.card__title::after {
content: "";
position: absolute;
height: 0.3125rem;
width: calc(100% + 1.25rem);
bottom: calc((1.25rem - 0.5rem) * -1);
left: -1.25rem;
background-color: var(--brand-color);
}
.card__button {
padding: 0.75em 1.6em;
width: fit-content;
width: -moz-fit-content; /* С префиксом для Firefox */
font-variant: small-caps;
font-weight: bold;
border-radius: 0.45em;
border: none;
background-color: var(--brand-color);
font-family: var(--font-title);
font-size: 1.125rem;
color: var(--black);
}
.card__button:focus {
outline: 2px solid black;
outline-offset: -5px;
}
Теперь, если мы добавим стили анимации как обычно, то начальное состояние карточки на всех устройствах будет таким:
Это не будет проблемой для устройств с возможностью наведения курсора, но на устройствах без такой возможности пользователю придется нажать на карточку, чтобы увидеть всю информацию, а это может быть неудобно и неинтуитивно для такого типа устройств. Лучший способ решить эту проблему - поместить все связанные с анимацией стили в медиа-запрос hover следующим образом:
@media (hover: hover) {
.card__content {
transform: translateY(62%);
transition: transform 500ms ease-out;
transition-delay: 500ms;
}
.card__title::after {
opacity: 0;
transform: scaleX(0);
transition: opacity 1000ms ease-in, transform 500ms ease-out;
transition-delay: 500ms;
transform-origin: right;
}
.card__background {
transition: transform 500ms ease-in;
}
.card__content--container > :not(.card__title),
.card__button {
opacity: 0;
transition: transform 500ms ease-out, opacity 500ms ease-out;
}
.card:hover,
.card:focus-within {
transform: scale(1.05);
transition: transform 500ms ease-in;
}
.card:hover .card__content,
.card:focus-within .card__content {
transform: translateY(0);
transition: transform 500ms ease-in;
}
.card:focus-within .card__content {
transition-duration: 0ms;
}
.card:hover .card__background,
.card:focus-within .card__background {
transform: scale(1.3);
}
.card:hover .card__content--container > :not(.card__title),
.card:hover .card__button,
.card:focus-within .card__content--container > :not(.card__title),
.card:focus-within .card__button {
opacity: 1;
transition: opacity 500ms ease-in;
transition-delay: 1000ms;
}
.card:hover .card__title::after,
.card:focus-within .card__title::after {
opacity: 1;
transform: scaleX(1);
transform-origin: left;
transition: opacity 500ms ease-in, transform 500ms ease-in;
transition-delay: 500ms;
}
}
Так, с помощью этого медиа-запроса мы можем решить проблемы удобства использования, но это не все, что мы можем сделать. Определение того, имеет ли устройство механизм наведения курсора или нет, может помочь нам охватить некоторые сценарии, но иногда нужно проверить, насколько точен указатель, что является нюансом, который не может обнаружить медиа-запрос hover. Именно здесь появляется наш следующий медиа-запрос, который помогает нам решить довольно распространенную проблему доступности.
Медиа-запрос ponter: Распознавание точности указателя
Иногда недостаточно определить, есть ли у устройства указатель. В некоторых случаях важно определить, насколько он точен. Здесь на сцену выходит наш следующий медиа-запрос. Медиа-запрос pointer
помогает определить, насколько точным является основное указательное устройство. Этот медиа-запрос имеет три значения:
none
- срабатывает, когда основной механизм ввода не имеет указательного устройства (например, сотовые телефоны);coarse
- срабатывает, когда основной механизм ввода имеет указательное устройство с ограниченной точностью (например, пульт дистанционного управления Smart TV или некоторых игровых приставок);fine
- срабатывает, когда основной механизм ввода имеет точное указательное устройство (например, мышь, сенсорные панели или стилус).
Этот медиа-запрос может помочь нам решить некоторые распространенные проблемы с доступом, которые возникают, если забыть о том, что с некоторыми элементами на сайте может быть сложно взаимодействовать, если у вас нет точного указателя. Давайте посмотрим это на примере.
Давайте создадим и оформим стилями небольшую форму, чтобы посмотреть, что может произойти у пользователя с устройством, у которого указатель с ограниченной точностью:
<form action="post">
<fieldset>
<legend>Which programming languages do you want to learn?</legend>
<div class="form-grid">
<label for="c"> <input type="checkbox" id="c" /> C </label>
<label for="c+"> <input type="checkbox" id="c+" /> C+ </label>
<label for="c++"> <input type="checkbox" id="c++" /> C++ </label>
<label for="c-sharp"> <input type="checkbox" id="c-sharp" /> C# </label>
<label for="kotlin"> <input type="checkbox" id="kotlin" /> Kotlin </label>
<label for="java"> <input type="checkbox" id="java" /> Java </label>
<label for="javascript">
<input type="checkbox" id="javascript" /> JavaScript
</label>
<label for="go"> <input type="checkbox" id="go" /> Go </label>
<label for="objective-c">
<input type="checkbox" id="objective-c" /> Objective-C
</label>
<label for="php"> <input type="checkbox" id="php" /> PHP </label>
<label for="python"> <input type="checkbox" id="python" /> Python </label>
<label for="ruby"> <input type="checkbox" id="ruby" /> Ruby </label>
<label for="rust"> <input type="checkbox" id="rust" /> Rust </label>
<label for="scala"> <input type="checkbox" id="scala" /> Scala </label>
<label for="swift"> <input type="checkbox" id="swift" /> Swift </label>
<label for="other"> <input type="checkbox" id="other" /> Another </label>
</div>
<button type="button">Submit</button>
</fieldset>
</form>
@import url("https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;700&display=swap");
body {
font-family: "Fira Sans", sans-serif;
}
fieldset {
padding: 0.6em 1em 2em;
border-radius: 1em;
border-color: #722f37;
box-shadow: 0.25rem 0.25rem 0.2rem rgba(0, 0, 0, 0.25);
}
legend {
font-size: 1.3rem;
text-align: center;
font-weight: bold;
}
form {
max-width: 53.125rem;
margin: 0 auto;
}
input[type="checkbox"] {
margin-inline-end: 0.5em;
accent-color: #722f37;
}
input[type="checkbox"]:focus {
outline: 2px solid #722f37;
outline-offset: 0.2em;
}
label {
display: flex;
align-items: center;
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
gap: 0.3em;
margin-bottom: 1.2em;
align-items: center;
}
button[type="button"] {
display: block;
margin: 0 auto;
padding: 0.3em 1em;
color: white;
font-weight: bold;
background-color: #722f37;
font-size: 1.25rem;
border: none;
border-radius: 0.5em;
}
button[type="button"]:focus {
outline: 2px solid #722f37;
outline-offset: 0.4em;
}
Эта форма отлично подходит для настольных компьютеров или ноутбуков, даже для стилуса, но если вам нужно использовать пальцы (например, на планшете), вы обнаружите, что вам будет трудно выбрать нужную опцию, и вы часто нажимаете не на то, что нужно.
На некоторых сайтах подобная ситуация происходит довольно часто, и это можно решить, если использовать медиа-запрос pointer для внесения некоторых незначительных изменений для устройств с ограниченной точностью. Давайте посмотрим на некоторые изменения, которые мы внесли в стили для этой формы, чтобы смягчить данную проблему:
@media screen and (pointer: coarse) {
.form-grid {
gap: 0.5em;
}
label {
font-size: 1.05em;
}
input[type="checkbox"] {
width: 1.625rem;
height: 1.625rem;
}
button[type="button"] {
min-height: 3rem;
}
}
Посмотрим, что же мы изменили.
- Мы увеличили отступы между опциями выбора (с 4,8 пикселей до 8 пикселей), чтобы было легче попасть. 8 пикселей - это рекомендуемое пространство между элементами, нажимаемых при помощи пальцев.
- Мы сделали больше размер элементов ввода (с 16 пикселей до 26 пикселей), поэтому их будет легче выбирать. Также был увеличен размер метки, чтобы соответствовать новому размеру элементов ввода.
- Высота кнопки отправки данных теперь будет 48 пикселей, что соответствует среднему размеру области касания. Это просто для того, чтобы упростить выбор кнопки. Кнопка и до этого была достаточно большой, но мы решили немного подстраховаться.
Как видно, благодаря нескольким простым изменениям наш сайт становится более удобным для пользователей, которые используют устройства с указателем ограниченной точности. Все это крайне полезно, но настоящая магия данных медиа-запросов проявляется, когда мы начинаем комбинировать их для проверки более конкретных сценариев.
Комбинирование медиа-запросов
Медиа-запросы hover и pointer - довольно интересные инструменты, но когда вы начнете рассматривать определенные сценарии и добавлять более сложные взаимодействия, вы заметите, что использование только одного или другого медиа-запроса может привести к неправильным выводам и, как следствие, нанести ущерб удобству использования вашего сайта. Чтобы подтвердить сказанное, давайте на мгновение вернемся к карточке из начала этой статьи. Чтобы проверить, что наш код работает, мы показали ее знакомым, и оказалось… Нам по-прежнему требуется нажать, чтобы отобразить всю информацию карточки.
Почему же? У наших знакомых был телефон Samsung Galaxy Note 9. Этот мобильный телефон оснащен стилусом в качестве основного навигационного механизма, который действует как точный указатель и механизм наведения. Мы поместили стили анимации в медиа-запроса hover со значением hover
, поэтому он все равно будет срабатывать на устройствах со стилусом.
Хотим ли мы этого для наших пользователей? Конечно, все зависит от вас, но нам все же кажется, что это неправильное поведение сайта. По статистике, даже если у мобильного телефона есть стилус, большинство людей все же для навигации чаще используют пальцы, поэтому мы считаем, что сайт стоит адаптировать с учетом этого.
Как мы можем это сделать? Давайте вспомним, что мы можем создавать сложные медиа-запросы, объединяющие два или более медиа-запросов, и в этом случае для проверки определенных устройств мы можем скомбинировать медиа-запросы hover и pointer.
После небольшого опроса знакомых, мы решили, что у нашей карточки анимация должна быть только на настольных компьютерах и ноутбуках. Давайте немного подумаем об их свойствах: компьютеры - это устройства, которые имеют механизм наведения курсора, поэтому мы должны использовать @media (hover: hover)
, и этот механизм точен, поэтому мы должны использовать @media (pointer: fine)
. Таким образом, если мы поместим все стили анимации в медиа-запрос @media (hover: hover) and (pointer: fine)
, то вся анимация будет отображаться только на компьютерах.
С учетом сказанного, какие же устройства мы можем обнаруживать с помощью этой техники? Вы можете посмотреть это в данной таблице:
Значение медиа-запроса hover | Значение медиа-запроса pointer | Устройство |
---|---|---|
none | coarse | Смартфоны, сенсорные экраны |
none | fine | Экраны на основе стилуса |
hover | coarse | Smart TV, игровые консоли |
hover | fine | Настольные компьютеры, ноутбуки |
Вы можете подумать, что это охватывает все возможные устройств, и вы были бы в основном правы, но некоторые конкретные сценарии невозможно обнаружить с помощью описанных методик, но на них все же стоит взглянуть.
Медиа-запросы any-hover и any-pointer
Давайте посмотрим на следующие фотографии:
На первой фотографии - мобильный телефон, к которому через Bluetooth подключены клавиатура и мышь. Хотя основным устройством ввода этого мобильного телефона является сенсорный экран, подключение мыши добавляет к нему точный указатель.
На второй фотографии - беспроводная мини-клавиатура, которую можно использовать для работы со Smart TV, X-Box и даже с телевизорами, установленными в автомобилях. Устройства ввода Smart TV не очень точны, но у этой мини-клавиатуры есть сенсорная панель, которая добавляет точный указатель.
Что общего у этих двух устройств? Оба они не будут обнаружены ранее описанными медиа-запросами, потому что эти медиа-запросы обнаруживают основной механизм ввода. Как же нам обнаружить подключение подобных устройств? И здесь CSS снова предлагает нам два дополнительных инструмента: медиа-запросы any-hover
и any-pointer
.
Эти медиа-запросы принимают те же значения, что и предыдущие: hover
и none
для any-hover; и none
, coarse
и fine
для any-pointer. Разница в том, что вместо определения основного механизма ввода они определяют, соответствует ли хотя бы один из механизмов ввода указанному условию.
Например, с помощью медиа-запроса (any-pointer: coarse)
мы можем обнаруживать устройства с сенсорным экраном, но он также обнаружит его, если у указанного устройства также будет мышь. Это позволит нам отработать больше сценариев, вроде описаных в начале этого раздела.
Мы даже можем объединить все эти 4 медиа-запроса. Например, мы могли бы использовать @media (pointer: fine) and (any-pointer: coarse)
, чтобы проверить, имеет ли основной механизм ввода устройства точный указатель, и одновременно с этим есть ли у него механизм ввода с указателем с ограниченной точностью. Это касается таких устройств, как смартфоны со стилусом или настольные компьютеры/ноутбуки с сенсорным экраном. Это может быть полезно для адаптации интерактивных элементов, таких как элементы ввода и кнопки, под взаимодействие через сенсорный экран, в случае, если пользователь не хочет использовать точный указатель и предпочитает использовать сенсорный экран.
Хотя комбинирование этих медиа-запросов может быть полезным, нужно быть осторожным с чем-то конкретным: сочетание браузеров и указательных устройств может приводить к некоторым неожиданным багам. Как показывают данные, собранные Патриком Х. Лауке, некоторые взаимодействия между оборудованием и браузерами приводят к неправильным результатам, что в некоторых конкретных случаях может вводить в заблуждение. Приведенные данные уже немного устарели, тем не менее, они показывают нам проблему, о которой стоит упомянуть. Что же в таком случае мы можем сделать, чтобы избежать как можно большего количества проблем, возникающих при использовании этих медиа-запросов?
На наш взгляд, ответ на этот вопрос заключается в том, чтобы учитывать саму философию CSS. Как говорит Мириам Сюзанн в своем видео "Почему CSS такой странный?":
"На самом деле мы разрабатываем дизайн для неизвестного бесконечного холста, и мы не знаем все его переменные. Вместо того, чтобы разрабатывать дизайн с полным контролем над конечным результатом, мы разрабатываем дизайн под изменения, движения и адаптацию."
"Итак, как дизайнер, я больше не контролирую вывод, я только предлагаю возможное решение. И именно поэтому CSS является декларативным языком. Это означает, что вместо описания шагов, которые необходимо предпринять для получения нужного результата, как мы делаем в JavaScript, я описываю цель, к которой я стремлюсь. К чему я стремлюсь? Что я продвигаю? И здесь я пытаюсь предоставить браузеру как можно больше значимой информации, подтекста и последствий, чтобы браузер мог принять разумные решения о том, что делать с этими стилями."
Почему мы должны принимать это во внимание? Потому что то, как пользователь решает перемещаться по нашему сайту, является одной из многих вещей, которые мы не можем контролировать. Наверное у пользователя может быть ноутбук с сенсорной панелью, и он обычно использует комбинацию сенсорная панель/мышь, но, возможно, в какой-то момент пользователь захочет использовать только сенсорную панель, и если ваш сайт не адаптирован для этой ситуации, это может создать проблему с удобством использования.
В таком случае, как мы можем учесть как можно больше возможных сценариев? Нам кажется, что ответ заключается в том, что вместо применения набора конкретных правил для конкретных сценариев мы могли бы использовать то, что мы узнали, чтобы дать некоторые директивы нашему сайту, чтобы он учитывал все на основе философии дизайна, которая включает в себя как можно больше пользователей.
На наш взгляд, хороший набор практик, которые мы должны учитывать для адаптации наших сайтов к многочисленным механизмам ввода, используемых при просмотре веб-страниц, должен включать:
- Приоритетное внимание сенсорным интерфейсам.
Просмотр с мобильных устройств - это новая реальность по умолчанию, и об этом нужно помнить при разработке сайтов. Проверка того, что интерактивные элементы, такие как элементы ввода или кнопки, имеют достаточный размер для использования на данных устройствах (что можно сделать с помощью медиа-запроса
any-pointer: coarse
), могут очень помочь сделать адаптивный сайт. - Не полагайтесь только на
pointer
иhover
.Пользователь вашего сайта не обязательно будет выбирать указатель в качестве основного механизма ввода. Однако вы можете использовать оба эти запроса, чтобы адаптировать свой интерфейс к конкретным устройствам, как мы уже видели в предыдущем разделе. Это хороший подход, но используйте его осторожно, потому что он может создать некоторые неверные предположения.
- Не забывайте пользователей с клавиатурой.
Конечно, тема данной статьи - устройства с указателями, но давайте не будем забывать, что это не единственный способ для навигации по сайту. Если уж вы собираетесь заставить элемент на вашем сайте реагировать сложным образом при наведении на него курсора, вы должны убедиться, что он также реагирует и на навигацию при помощи клавиатуры! Взгляните на карточку из начала статьи: она реагирует на наведение курсора, но анимация запускается при навигации с клавиатуры благодаря псевдоклассу
:focus-within
, поэтому на удобство работы с клавиатурой ничто не влияет. При необходимости элементу, недоступному с клавиатуры, вы также можете присвоить атрибутtabindex=0
. - Протестируйте свой сайт с помощью различных устройств и браузеров.
Помните, что иногда сочетание этих двух элементов может привести к неожиданному результату, поэтому, чем больше вы тестируете на разных устройствах и браузерах, тем больше у вас будет уверенности в том, что ваш сайт работает хорошо.
Использование JavaScript для обнаружения устройств с указателем
Также стоит заметить, что существуют решения этой же проблемы при помощи JavaScript. И это было оправданное решение, когда данные медиа-запросы не поддерживались так широко, как сейчас! Однако в современной среде веб-разработки эти хакерские решения не нужны и могут лишь вызвать дополнительные проблемы:
- Некоторые пользователи предпочитают отключать JavaScript по определенным причинам (например, чтобы не видеть рекламу на сайте), поэтому использование JavaScript для решения этой проблемы не всегда надежно.
- Сейчас он может обнаружить существующее сенсорное устройство, но что будет через несколько месяцев, когда на рынке появится новое устройство, которое JavaScript не сможет обнаружить? Это создало бы некоторые проблемы с удобством использования и доступностью на этих устройствах.
Даже если лучше передать эту проблему более гибкому уровню веб-разработки, такому как CSS, это не значит, что JavaScript не может участвовать в этом вопросе! В чем нам может помочь JavaScript, так это в том, что мы можем создать элемент выбора, которым может воспользоваться пользователь, чтобы выбрать, какой интерфейс он хочет использовать - для мыши или сенсорной панели (как кнопка переключения темного/светлого режима).
Резюме
Просмотр сайта - это процесс, который можно выполнить разными способами и на разных устройствах. И об этом важно всегда помнить, потому что иногда требуется, чтобы сайт адаптировался к конкретным ситуациям. В CSS есть медиа-запросы, которые могут помочь нам справиться с нашей главной задачей - предоставить пользователям самый удобный способ использования нашего сайта!