Уже многие годы JavaScript остаётся «рабочей лошадкой» веба. Если вам нужно сделать то, что невозможно реализовать средствами HTML и CSS, то обычно найти решение помогает JS. И это замечательно! JS помог расширить возможности пользователей, а также стимулировал прогресс HTML и CSS!

Но время идёт, функции HTML и CSS расширяются, поэтому мы должны начать заменять старые и привычные решения на JS новыми, требующими меньше JS.

Я ничего не имею против JS, но у него есть иные задачи, кроме как управление аккордеонами и внеэкранными меню навигации... Кроме того, JS нужно скачивать, распаковывать, обрабатывать, после чего он ещё часто тратит память на мониторинг и поддержку фич. Если мы сможем перенести какую-то функциональность JS в нативный HTML или CSS, тогда пользователям придётся скачивать меньше данных, а оставшийся JS сможет уделить внимание более важным задачам, с которыми (пока) не справляются HTML и CSS.

В этой статье я приведу несколько примеров; сможете придумать свои?

Аккордеоны/раскрывающиеся панели с контентом

Описание:

HTML-элементы details и summary позволяют заменить типичный JS-аккордеон одним HTML:

Examples of HTML  element expanding and contracting

Сценарии использования:

  • Сокрытие/отображение контента

  • Развёртывание разделов контента

Базовая реализация:

<details>
  <summary>Initially closed, click to open</summary>
  Content is initially hidden, but can be revealed by clicking the summary.
</details>

Если добавить атрибут open, то по умолчанию контент будет «открыт»:

<details open>
  <summary>Initially open, click to close</summary>
  Content is initially visible, but can be hidden by clicking the summary.
</details>

Если использовать атрибут name для всех соответствующих details (например, радиокнопок), то одновременно будет открыта только одна панель:

<details name="foo" open>
  <summary>Initially open, clicking others will close this</summary>
  Content is initially visible, but can be hidden by clicking the summary; only one panel can be open at a time.
</details>
<details name="foo">
  <summary>Initially closed, clicking will open this, and close others</summary>
  Content is initially hidden, but can be revealed by clicking the summary; only one panel can be open at a time.
</details>
<details name="foo">
  <summary>Initially closed, clicking will open this, and close others</summary>
  Content is initially hidden, but can be revealed by clicking the summary; only one panel can be open at a time.
</details>

Можно также настроить внешний вид элементов при помощи CSS и выполнять открытие/закрытие через JS.

Подробнее об элементе details можно узнать в опубликованном ранее посте «For the Love of <details>».

Ресурсы:

Совместимость с браузерами:

Поле ввода с раскрывающимся меню рекомендаций автофильтра

Описание:

Скомбинировав HTML-элементы input и datalist, можно создать раскрывающееся меню вариантов, выполняющее автоматическую фильтрацию в процессе ввода:

Examples of HTML  and  providing autofilter dropdown

Сценарии использования:

  • Поиск по сайту

  • Поиск или фильтр товаров

  • Фильтрация любого списка данных

Базовая реализация:

<label for="browser">Browser</label>
<input type="text"
       list="browsers"
       id="browser" name="browser"
       size="50"
       autocomplete="off" />
<datalist id="browsers">
  <option value="Arc"></option>
  <option value="Brave"></option>
  <option value="Chrome"></option>
  <option value="DuckDuckGo"></option>
  <option value="Firefox"></option>
  <option value="Microsoft Edge"></option>
  <option value="Opera"></option>
  <option value="Safari"></option>
  <option value="Tor"></option>
  <option value="Vivaldi"></option></option>
</datalist>

Также можно использовать другие input type:

<label for="quantity">Quantity</label>
<input type="number" 
       list="quantity-options"
       id="quantity" name="quantity" />
<datalist id="quantity-options">
  <option value="1"></option>
  <option value="2"></option>
  <option value="5"></option>
  <option value="10"></option>
  <option value="20"></option>
  <option value="50"></option>
</datalist>

<label for="appointment">Appointment</label>
<input type="time" 
       list="appointments"
       id="appointment" name="appointment" />
<datalist id="appointments">
  <option value="12:00"></option>
  <option value="13:00"></option>
  <option value="14:00"></option>
</datalist>

Стоит отметить, что на момент написания этого поста Firefox поддерживает только текстовые input type, поэтому пока никаких datetimerange и color...

Также учтите, что на момент написания поста существуют ограничения на мобильных платформах и сложности с accessibility.

Ресурсы:

Совместимость с браузерами:

Модальные/всплывающие окна

Описание:

Атрибуты popover и popovertarget могут заменить традиционные модальные/всплывающие окна/оверлеи на основе JS:

Examples of HTML  elements opening and closing

Сценарии использования:

  • Сокрытие/открытие боковых панелей/дополнительной информации

Базовая реализация

Всплывающее окно auto (используемое по умолчанию) можно закрывать нажатием вне его или клавишей esc. Открытие auto автоматически закрывает все другие открытые всплывающие окна auto. При повторном нажатии на button закрывается окно, которое открывалось этой кнопкой.

<button popovertarget="pop-auto">
   Toggle Popover
</button>
<dialog popover id="pop-auto">
   I'm an "auto" Popover!
</dialog>

Всплывающее окно hint тоже можно закрывать нажатием вне его или esc. При своём открытии оно не закрывает другие окна hint. При повторном нажатии на button закрывается окно, которое открывалось этой кнопкой.

<button popovertarget="pop-hint">
   Toggle Popover
</button>
<dialog popover="hint" id="pop-hint">
   I'm a "hint" Popover!
</dialog>

Стоит отметить, что на момент написания поста Firefox и все разновидности iOS не поддерживали всплывающие окна hint.

Всплывающее окно manual нельзя закрывать нажатием вне или esc. При открытии оно не закрывает другие окна manual. При повторном нажатии на button закрывается окно, которое открывалось этой кнопкой.

<button popovertarget="pop-manual">
   Toggle Popover
</button>
<dialog popover="manual" id="pop-manual">
   I'm a "manual" Popover!
</dialog>

Подробнее об открытии и закрытии диалоговых и всплывающих окон можно узнать из поста «Controlling dialogs and popovers with the Invoker Commands API».

Ресурсы:

Совместимость с браузерами:

Внеэкранная навигация/контент

Описание:

Функциональность модальных/всплывающих окон также можно использовать для создания внеэкранной навигации, не требующей JS:

Example of HTML Popover used as an offscreen navigation menu

Сценарии использования:

  • Сокрытие/отображение меню навигации

Базовая реализация:

<button popovertarget="menu">
   Toggle Menu
</button>
<nav popover id="menu">
   Nav Content
</nav>
#menu {
  margin: 0;
  height: 100vh;
  translate: -100vw;
}
#menu:popover-open {
  translate: 0;
}

Для придания семантического значения я использую элемент nav, но можно использовать любой другой HTML-элемент (divsectionaside и так далее).

Согласно User Agent Stylesheet, для popover по умолчанию используется position: fixed, оно просто выталкивается из экрана при закрытии и возвращается на экран при открытии. Обратите внимание, что для переопределения center-alignment User Agent обязательно использовать margin: 0.

При нажатии вне меню оно закрывается. Можно принудительно оставить панель открытой, чтобы она требовала закрытия вручную, при помощи popover="manual".

Также можно добавить псевдоэлемент backdrop и стилизовать его:

#menu::backdrop {
  background: rgb(190 190 190 / 75%);
}

Ресурсы:

Совместимость с браузерами:

Заключение

Все мы любим ту мощь и гибкость, которую даёт нам JS, но также нам стоит уважать его и наших пользователей, ограничивая его только тем, что он должен делать.

За последние годы изменилось очень многое, в том числе появилось и множество областей, в которых теперь достаточно CSS. Если вам хочется большего, то прочитайте мою статью, в которой рассказывается и об этом: https://aarontgrogg.com/blog/2023/05/31/replace-js-with-no-js-or-lo-js-options/.