Вам не нужен JavaScript
Я не ненавижу JavaScript, я люблю его. Ежедневно я пишу на нём кучу кода. Но ещё я люблю CSS и даже люблю JSX HTML. Я люблю все эти три технологии по причине, которая называется:
Правило наименьших полномочий
Это один из базовых принципов веб-разработки, означающий, что следует выбирать наименее мощный язык, подходящий для решения задачи.
В случае веба это означает, что нужно по возможности выбирать HTML вместо CSS, а затем CSS вместо JS. JS — самый универсальный язык из всех трёх, потому что на нём вы описываете, как должен вести себя браузер; но также он может ломаться, отказываться загружаться, требует дополнительных ресурсов для скачивания, парсинга и исполнения. Кроме того, при его использовании очень легко нарваться на невозможность доступа пользователей, выполняющих браузинг при помощи клавиатуры или специальных возможностей (то есть без мыши или тач-скрина).
В отличие от JS с его императивностью, HTML и CSS декларативны. Вы говорите браузеру, что делать, а не как это делать. Это значит, что браузер сам выбирает, как это делать, и может сделать это наиболее эффективным образом.
Так как функции HTML и CSS обрабатываются браузером, они могут быть более производительными, более нативными, более адаптируемыми к предпочтениям пользователя, и в общем случае будут иметь бОльшую accessibility. Это не значит, что так будет всегда (особенно когда дело касается accessibility), но когда все сложные задачи берёт на себя браузер, от этого обычно выигрывают конечные пользователи.
Возможно, вы подумаете: «Во всём, для чего я использую JS, он необходим». Это может быть правдой, но неплохо помнить о том, что разработчики браузеров и авторы спецификаций портировали в CSS и HTML большую часть функциональности, для которое ещё несколько лет назад требовался JS. Именно этому и посвящена моя статья.
Особенность веб-разработки заключается в том, что, научившись делать что-то один раз, вы больше не будете иметь никаких причин учиться делать это заново. Таков контракт, который мы заключаем: веб имеет обратную совместимость. Существуют очень незначительные исключения, но первая веб-страница по-прежнему отлично отображается во всех современных браузерах.
Ещё это означает, что найденное однажды вами решение становится частью вашего инструментария, вы продолжаете повторно реализовывать его, и оно каждый раз срабатывает. Приведённые в статье примеры полезны (поэтому я их и привожу), но я хочу донести, что даже если вы знаете о необходимости JavaScript для решения задачи, это не значит, что он по-прежнему требуется. Если вы часто будете проверять свои допущения, то сможете создавать более качественные веб-сайты.
Собственные переключатели
Мы начнём статью с того, что всем нам когда-то приходилось реализовывать — с переключателей. Вместо обычного чекбокса в дизайне иногда необходим красиво выглядящий переключатель. Мы не будем искать решение на JS с div, обработчиками onclick и внутренним состоянием, а воспользуемся обычным чекбоксом и псевдоклассом :checked. Вот HTML, который мы будем использовать:
Здесь есть элемент label, а внутри него находится чекбокс. Удобство этого в том, что браузер сам делает всё за нас. Так как наш input находится внутри label, браузер связывает их, и теперь мы можем нажать на любую точку label для переключения чекбокса, а обработчик onclick не требуется. Браузер дал нам его «бесплатно». С точки зрения функциональности мы выполнили задачу.
Разумеется, дизайнерам может не понравиться внешний вид, и вам придётся создавать красивый переключатель. Поэтому добавим немного CSS:
input {
appearance: none;
position: relative;
display: inline-block;
background: lightgrey;
height: 1.65rem;
width: 2.75rem;
vertical-align: middle;
border-radius: 2rem;
box-shadow: 0px 1px 3px #0003 inset;
transition: 0.25s linear background;
}
input::before {
content: "";
display: block;
width: 1.25rem;
height: 1.25rem;
background: #fff;
border-radius: 1.2rem;
position: absolute;
top: 0.2rem;
left: 0.2rem;
box-shadow: 0px 1px 3px #0003;
transition: 0.25s linear transform;
transform: translateX(0rem);
}
Все подробности стилизации здесь не так важны, но я бы хотел обратить ваше внимание на первое правило: appearance: none.
Элементы форм вместе с изображениями — это нечто, называемое «заменяемым контентом». Это значит, что на самом деле они не являются частью HTML, а передаются браузером. Когда браузер рендерит HTML и находит заменяемый контент, он оставляет для него прямоугольник, а затем заменяет этот прямоугольник настоящим контентом. Именно поэтому, например, изображения и элементы форм не имеют псевдоэлементов: они заменяются, когда браузер заменяет весь элемент.
appearance приказывает браузеру не делать этого. Это правило говорит браузеру: «Спасибо, но я хочу стилизовать собственный элемент управления формой». И это позволяет нам затем использовать псевдоэлемент ::before. Сам input теперь становится фоном для нашего переключателя, а псевдоэлемент ::before — это маленькая точка внутри него, выполняющая переключение.
При нажатии мы по-прежнему переключаем чекбокс, но поскольку мы заменили элемент, нам нужно самостоятельно сделать его видимым. И тут нам на помощь приходит псевдокласс :checked:
:checked {
background: green;
}
:checked::before {
transform: translateX(1rem);
}
При нажатии на чекбокс псевдокласс :checked выполняет проверку, вызывая обновление стилизации.
Итак, у нас теперь есть красивый переключатель, созданный при помощи нативных элементов HTML и доли CSS, но мы ещё не закончили. Пользователям, которые работают с мышью, понятно, с каким элементом управления формы они взаимодействуют, но для людей, работающих с клавиатуры, всё не так очевидно.
Я уверен, что вы знакомы с этой частью CSS, позволяющей избавиться от некрасивого пунктирного прямоугольного контура:
input:focus {
outline: none;
}
Знайте, что это плохая идея. Но как сделать контур красивее? В этой области браузеры тоже приготовили нам улучшения. Теперь outline следует за border-radius элемента; кроме того, мы можем сместить его в сторону или внутрь элемента:
input:focus-visible {
outline: 2px solid dodgerblue;
outline-offset: 2px;
}
Теперь если пользователь будет взаимодействовать с элементом с клавиатуры (можете попробовать нажать на пробел после нажатия на него, или добраться до него при помощи Tab), :focus-visible будет соответствовать ему (но не при использовании мыши), и пользователь получит красивый синий контур вокруг элемента.
Наконец, я хочу заменить outline: none на нечто иное:
input:focus {
outline-color: transparent;
}
Результат будет таким же: контур окажется невидимым — но не потому, что он скрыт, а потому, что он прозрачен. Однако для пользователей с включенным высококонтрастным режимом (также называемым forced colors) этот контур снова становится видимым, потому что в высококонтрастном режиме этот прозрачный цвет заменяется выбранным пользователем, помогая ему видеть, с чем он взаимодействует даже при использовании мыши.
Datalist с нативным автозаполнением
Вместо того, чтобы устанавливать $your-framework-autosuggest, попробуйте использовать в своём следующем проекте наш datalist. Datalist — это встроенный в браузеры способ отображения опций, когда пользователь что-то вводит в поле ввода.
<input list="frameworks" />
<datalist id="frameworks">
<option>Bootstrap</option>
<option>Tailwind CSS</option>
<option>Foundation</option>
<option>Bulma</option>
<option>Skeleton</option>
</datalist>
Чтобы использовать его, достаточно добавить в HTML элемент datalist с ID и списком вариантов. Не волнуйтесь, элемент будет невидимым. Затем мы используем атрибут list для поля ввода, чтобы связать их.
Если пользователь теперь будет печатать в поле ввода, то браузер отобразит datalist в виде раскрывающегося списка, автоматически фильтруя варианты при вводе. Однако так как это обычный input, пользователи всё равно могут вводить собственные значения. Также они могут просмотреть список всех вариантов, нажав на поле ввода и перемещаясь по списку при помощи клавиш со стрелками, или нажав на добавленный браузером значок раскрывающегося списка.
Инструмент для выбора цвета с дополнительными возможностями
Существует множество красивых селекторов цветов с красивыми UI и ползунками, написанные в сотнях строк JavaScript. Но знали ли вы, что есть и нативный инструмент для выбора цветов?
<label> <input type="color" /> Color </label>
Эта одна строка HTML позволяет получить селектор цветов с красивым UI и сэкономить на куче JS. Но так как его обработкой занимается браузер, мы «бесплатно» получаем дополнительную функциональность. В браузерах Chromium этот нативный селектор цветов также позволяет выбрать цвет не только со своего сайта, но и из любого места экрана. Очень удобно!
Небольшое примечание: несмотря на то, что браузеры отображают селектор цветов, пользователи могут и не увидеть его. Поэтому всё равно стоит предоставить другой способ выбора цвета (например, через обычный текстовый элемент ввода).
Аккордеоны и балалайки
Аккордеоны — отличный способ сделать страницу с большим количеством контента более структурированной и менее хаотичной; мы разбиваем контент в том порядке, в котором он понадобится пользователю. И браузеры «бесплатно» дают нам такую возможность при помощи элементов details и summary:
<details>
<summary>My accordion</summary>
<p>My accordion content</p>
</details>
По умолчанию всё, что находится внутри элемента details, скрыто, за исключением summary. Когда пользователь нажимает на элемент summary, браузер отображает остальную часть контента.
Часто бывает так, что один элемент аккордеона открыт, а другие закрыты. Это можно реализовать при помощи атрибута details open.
Если вы работаете с React, то можете посмотреть на этот код и подумать: «Отлично, теперь у него есть свойство open и он больше не закроется»; к счастью, это не так. Атрибут open — это лишь начальное состояние, оно обновляется, когда пользователь взаимодействует с аккордеоном.
Со стилизацией нам тоже поможет элемент details. Маленький треугольник (от которого дизайнер захочет избавиться, как только его увидит) — это псевдоэлемент ::marker, который можно стилизовать.
Помните, что изменение контента может влиять на то, как специальные возможности сообщают об аккордеоне. Подробнее о несогласованностях details/summary можно прочитать в статье Мануэля. Кроме того, в Safari придётся использовать псевдоэлемент ::-webkit-details-marker.
Псевдоэлемент marker нельзя стилизовать так же подробно, как другие элементы (многие свойства CSS не работают с ним, например, размещение его в совершенно другом месте), но можно заменить его контент, например, на эмодзи, или установить цвет или изображение фона, а также поменять размер шрифта.
При помощи атрибута open можно легко придать ему стилизацию, отличающуюся от стилизации закрытого состояния.
Наконец, можно сделать что-нибудь с элементом summary. На него можно нажимать, но в отличие от ссылки он не превращает курсор в указатель, а в отличие от кнопки он не выглядит как кнопка. Поэтому я думаю, нужно добавить к нему состояния hover и focus, чтобы дать понять посетителям, что на него можно нажать.
Я не буду здесь вдаваться в обсуждения темы «только у ссылок должны быть курсоры-указатели», самое главное — показать, что можно что-то сделать.