9 нативных API браузера вместо npm-пакетов
Если вы привыкли ставить npm-пакет под каждую мелочь — вот 9 вещей, под которые давно существует нативный API браузера. Кода меньше, багов меньше, бандл легче.
Если вы привыкли ставить npm-пакет под каждую задачу — вот девять вещей, под которые давно существует нативный API браузера. Кода меньше, багов меньше, бандл легче. Статья польской разработчицы Sylwia Łask собрала самые показательные примеры — перевели и адаптировали для русскоязычного читателя.
Что внутри
requestIdleCallback— запустить фоновую задачу, когда браузер простаивает:focus-within— стилизовать родителя, внутри которого есть элемент в фокусеnavigator.onLine+ событияoffline/online— детектировать пропажу интернетаrequestAnimationFrame— плавная анимация без рывков- Container queries — адаптив относительно размеров контейнера, а не viewport
crypto.getRandomValues— криптографически стойкие случайные ID без коллизий<dialog>— нативный модал с доступностью из коробки- Web Speech API — распознавание речи без библиотек (только Chromium)
@supports— CSS feature detection без костылей
1. «Запустим это потом» → requestIdleCallback
Хотите собирать аналитику, предзагружать данные или генерировать что-то в фоне, не конкурируя с рендером 200 компонентов? requestIdleCallback запускает ваш код в те моменты, когда браузер простаивает. На первый взгляд это кажется узкоспециальной фичей, но на практике кейсов много: сбор аналитики о поведении пользователя, несрочная фоновая обработка картинок, предварительная подготовка данных, которые пригодятся позже.
Поддержка: современные браузеры. В Safari исторически отсутствовал, так что fallback на setTimeout всё ещё полезен.
2. «Почему мой input не подсвечивается?» → :focus-within
Стилизовать элемент с фокусом — просто. А как стилизовать родителя, внутри которого какой-то элемент получил фокус, — задача, которую обычно решают сорока строками JavaScript со слушателями focus и blur. Всё это не нужно: :focus-within делает то же самое одной CSS-строкой.
Поддержка: везде, где это хоть сколько-нибудь важно.
3. «Покажем офлайн-режим» → navigator.onLine
Вечная боль любого PWA — что делать, когда у пользователя пропал интернет (он уехал в лес или зашёл в лифт). Можно писать сложные if-ы — а можно просто слушать события offline и online. На offline складываем данные в IndexedDB, на online отправляем на сервер.
Поддержка: широкая. Одна оговорка: «онлайн» не равно «ваш бэкенд доступен». Это проверка уровня сетевого соединения, а не доступности конкретного сервиса.
4. «Плавная анимация, но проклятая» → requestAnimationFrame
Хотите, чтобы анимация не дёргалась на слабых ноутбуках, а батарея садилась медленнее? Привычка «60 fps = setInterval каждые 16 мс» — плохая идея, и вот почему. Классика, которую все видели:
Интуитивно понятно, что это плохая идея. Лагает. К счастью, есть requestAnimationFrame — он синхронизирован с циклом перерисовки браузера, поэтому анимация действительно плавная.
Поддержка: везде.
5. «Карточка должна адаптироваться, но только здесь» → container queries
Одну и ту же карточку можно положить в узкий сайдбар, в основную ленту или в лайтбокс — и чтобы она корректно подстраивалась под каждое место без знания о том, на каком она экране. Раньше media queries были привязаны к размеру viewport, то есть «ко всей странице». Container queries позволяют применять стили в зависимости от размера конкретного контейнера. Компонент становится самодостаточным: куда положили — под то и подстроился.
Поддержка: современные браузеры. Если целитесь в старые — добавьте fallback через обычные media queries.
6. «Случайный ID, что может пойти не так?» → crypto.getRandomValues
Именно так рождаются баги:
Выглядит как «достаточно случайная» криптография с AliExpress — и работает, пока не перестаёт. Во-первых, всё зависит от реализации движка, мы не знаем, что происходит под капотом. Во-вторых, определённые паттерны вполне возможны, а при большом количестве ID вы фактически напрашиваетесь на коллизии.
К счастью, есть нативное решение. Не серебряная пуля, но crypto.getRandomValues заметно лучше: больше энтропии, нет странных паттернов, вероятность коллизий резко снижается. Браузер просто делает это правильно. А если вам нужен не произвольный набор байтов, а именно UUID, в современных браузерах есть ещё короче: crypto.randomUUID() выдаёт готовый UUID v4 одной строкой — тоже криптографически стойко и без ручной возни с байтами.
Поддержка: широкая.
7. «Нам нужен модал» → dialog
Больше не нужно ставить 12-килобайтную библиотеку ради модального окна, которое так любят пользователи. Нативный <dialog> даёт клавиатурную навигацию, фокус-трап и корректную работу со скринридерами прямо из коробки — всё то, что в самописных модалах обычно забывают или делают криво.
Поддержка: современные браузеры.
8. «Голосовой ввод был бы крутой фичей» → Web Speech API
Собирались ставить transformers.js, потому что понадобилось распознавание речи? У браузера для этого уже есть Web Speech API. Chromium-браузеры поддерживают его напрямую, Safari — через префиксную версию webkitSpeechRecognition (код ниже как раз это учитывает), в Firefox поддержки нет. Для демо и ассистивных фич — отлично, в проде лучше иметь запасной план на случай Firefox.
Поддержка: Chromium и Safari (через webkit-префикс), в Firefox до сих пор нет.
9. «Не сломает ли это CSS?» → @supports
Хотите выкатить backdrop-filter или :has() и при этом не сломать вёрстку в браузере, где фича ещё не поддерживается? Оборачиваем в @supports — и спокойны: браузер, который знает фичу, получит красивую версию, остальные — дефолтный fallback.
Поддержка: очень хорошая.
Когда всё-таки нужна библиотека
Библиотеки — это отлично, и иногда они действительно необходимы. Но иногда вы ставите зависимость на то, что браузер решил годы назад. Перед npm install полезно спросить себя (или поискать в MDN): «А браузер не умнее меня в этом вопросе?» Иногда ответ — да. И это нормально.
Источник: Sylwia Łask — 9 things you're overengineering: the browser already solved them.