🔵 Chrome 156: IndexedDB на SQLite и random() в CSS 20 октября вышел Chrome 156. IndexedDB перевели с LevelDB и плоских файлов на SQLite без изменения API. В CSS появилась random(), а загрузку модуля после сетевого сбоя можно повторить через import(). В релиз вошли 353 исправления безопасности, шесть из них критические. 🔵 TypeScript 7.1 Beta: API компилятора и content mappers 20 октября вышла бета TypeScript 7.1 с API typescript/sync и typescript/async для разработчиков инструментов. Плагины content mappers позволяют подключать форматы вроде .vue и .svelte к проверке типов. Для запуска через tsc нужен --runExternalCode. В бенчмарке на mui-docs с --noEmit и четырьмя потоками проверка заняла 11,9 с против 22,2 с в TypeScript 7.0. 🔵 Chrome DevTools: Anchor Positioning и память замыканий 20 октября команда Chrome описала обновления DevTools для Chrome 155 и 156. В Elements появился визуальный редактор position-area, а Memory теперь находит неиспользуемые переменные, которые замыкания удерживают в памяти. Инструмент get_css_styles позволяет AI-агентам читать вычисленные стили и применённые CSS-правила. 🔵 Node.js: десять исправлений безопасности 21 октября вышли патчи 26.12.1, 24.22.1 и 22.23.4. В декодере Brotli закрыли уязвимость: распаковка вредоносных данных через node:zlib могла привести к повреждению памяти и удалённому выполнению кода. Проблема затрагивала все три ветки. 🔵 Safari 27.1: API для складного экрана за флагами 23 октября в Safari 27.1 на iPhone Duo появились экспериментальные Device Posture API и Viewport Segments API. Первый позволяет реагировать на частичный сгиб экрана, второй описывает области по обе стороны сгиба. Оба API доступны за флагами. 🔵 Safari 27.2: финальный релиз и правки Grid Lanes 26 октября вышел Safari 27.2. В кастомном <select> можно стилизовать отображаемое значение через ::field-content без <selectedcontent>. В Grid Lanes свойство flow-tolerance переименовали в fit-tolerance, старое имя временно работает как устаревший алиас. 🔵 Firefox 159: анимации по скроллу и реестры веб-компонентов 27 октября в Firefox 159 включили по умолчанию анимации, привязанные к скроллу. Появились scoped custom element registries: у shadow-дерева может быть свой реестр элементов. Одинаковые имена элементов из разных библиотек в таких реестрах не конфликтуют. 🔵 Next.js: запланирован security-релиз 27 октября команда Next.js анонсировала патчи для семи уязвимостей средней критичности. Релиз запланирован на 3 ноября, затронутые версии и инструкции по обновлению опубликуют вместе с исправлениями. 🔵 Node.js 26: LTS до апреля 2029 года 28 октября Node.js 26.13.0 перевёл ветку 26.x в LTS под именем Lithium. Поддержка продлится до конца апреля 2029 года. При переходе со старых LTS проверьте наличие libatomic в Linux-образах. Статьи от инженеров VK: ➡️ Прежде чем работать с AIDL: разбираемся, как устроен IDL ➡️ От AJAX до React: как мы полностью изменили архитектуру разработки фронтенда ВКонтакте #frontendvkhub #дайджест
Открыть в TelegramПосты канала Frontend VK Hub
overflow: auto clip в Chrome 156: липкая шапка таблицы в обёртке с горизонтальной прокруткой ➡️ Chrome 156 от 20 октября разрешил делать элемент контейнером прокрутки только по одной оси: элемент с overflow: auto clip прокручивается по горизонтали, а по вертикали обрезает содержимое. Раньше браузер заменял clip в паре с auto на hidden, и элемент становился контейнером прокрутки по обеим осям. Теперь getComputedStyle возвращает auto clip, а липкий элемент привязывается к контейнеру прокрутки отдельно по каждой оси. Базовый случай — таблица с липкой шапкой и липкой первой колонкой внутри обёртки с overflow-x: auto. У такой обёртки браузер заменяет overflow-y: visible на auto, и она становится контейнером прокрутки по обеим осям. Шапка с top: 0 липнет к обёртке и уезжает вместе со страницей, потому что по вертикали обёртка не прокручивается. В нашем тесте обёртка была шириной 400 px, таблица — 1 200 px, страница прокручена на 600 px. С overflow-x: auto шапка в Chrome 141, Chrome 156 и Firefox 158 уехала на 500 px за верхний край окна, а с auto clip в Chrome 156 осталась у края. .table-wrap { overflow-x: auto; } @supports named-feature(single-axis-scroll-container) { .table-wrap { overflow: auto clip; } } .table-wrap thead th { position: sticky; top: 0; } .table-wrap :is(th, td):first-child { position: sticky; left: 0; } Почему не @supports (overflow: auto clip)? Все актуальные браузеры принимают это значение, и CSS.supports возвращает true даже в Firefox 158, где поддержки нет. В блоге Chrome советуют named-feature(single-axis-scroll-container), и в нашем тесте это условие выполнилось только в Chrome 156. Без проверки браузеры без поддержки превратят auto clip в auto hidden, и всё, что выходит за нижний край обёртки, обрежется. У clip по второй оси есть побочные эффекты. По этой оси элемент не прокручивается и программно: после scrollTop = 150 свойство по-прежнему возвращает 0, а scrollIntoView прокручивает окно вместо обёртки. Выпадающий список, который выходит за нижний край, обрезается без возможности прокрутки, хотя scrollHeight обёртки показывает полную высоту, 380 px. Во flex-контейнере с flex-direction: column у элемента с overflow: auto clip начинает действовать min-height: auto, минимальная высота по содержимому. В нашем тесте в Chrome 156 такой элемент в контейнере высотой 200 px вырос до 600 px, а в Chrome 141 и Firefox 158 сохранил высоту 200 px. В Safari поддержки тоже нет, и там работает запасной overflow-x: auto. Сам auto clip ставим только на обёртку, которой нужна липкость по двум осям, и только внутри проверки named-feature. Выпадающие списки внутри такой обёртки выносим в верхний слой через popover и привязываем к кнопке через anchor positioning, а flex- и grid-элементам задаём min-height: 0, если clip стоит по вертикали, и min-width: 0, если по горизонтали. А как вы сейчас делаете липкую шапку у широких таблиц? #frontendvkhub #chrome #таблицы
Открыть в TelegramДинамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 145 |
| 34 ч | 170 |
- Всего сейчас170
Динамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 167 |
| 34 ч | 194 |
| 57 ч | 228 |
| 70 ч | 235 |
- Всего сейчас235
Динамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 167 |
| 34 ч | 193 |
| 57 ч | 227 |
| 70 ч | 234 |
- Всего сейчас234
Динамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 166 |
| 34 ч | 191 |
| 57 ч | 226 |
| 70 ч | 233 |
- Всего сейчас233
Динамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 165 |
| 34 ч | 189 |
| 57 ч | 220 |
| 70 ч | 226 |
- Всего сейчас226
Динамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 165 |
| 34 ч | 189 |
| 57 ч | 220 |
| 70 ч | 226 |
- Всего сейчас226
IndexedDB на SQLite в Chrome 156: транзакции, место на диске и тесты Chrome 156 от 20 октября начал переводить IndexedDB с LevelDB на SQLite. Web API не меняется, и в chromestatus переход отмечен как изменение, которого разработчик не увидит. Пока SQLite получают только сайты, для которых в профиле ещё нет хранилища IndexedDB, и только у пользователей из группы эксперимента. Перенос существующих баз запланирован на следующий этап. Разницу всё же видно. На LevelDB две readwrite-транзакции к разным хранилищам одной базы идут в Chromium параллельно, а на SQLite вторая ждёт, пока завершится первая. Спецификация это разрешает, и Firefox 158 в нашем тесте ведёт себя так же. ➡️ В карточках разбираем, кому уже включили SQLite, а также оцениваем транзакции, место на диске, скорость и надёжность записи. #frontendvkhub #sqlite #chrome
Открыть в TelegramДинамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 10 ч | 171 |
| 34 ч | 197 |
| 57 ч | 230 |
| 70 ч | 236 |
- Всего сейчас236
Импорт текста через with { type: 'text' }: что делает браузер и почему в Vite он не работает 🤖 С Chrome 155 от 6 октября текстовый файл можно импортировать как модуль: import tpl from './card.html' with { type: 'text' }. Firefox поддерживает такой импорт с версии 153 от 21 июля, в Safari он есть начиная с Technology Preview 251, а в стабильной версии пока нет. Экспорт default содержит текст файла строкой, так что шаблоны, шейдеры и SVG можно подключать без fetch и без плагина сборщика. Браузер не проверяет MIME-тип ответа. В нашем тесте Chrome 156 и Firefox 158 вернули строкой и .js-файл, и ответы с text/html и application/octet-stream. Байты браузер всегда декодирует как UTF-8: кириллица из файла в cp1251 превращается в символы U+FFFD, а BOM в начале отбрасывается. Запрос уходит в режиме cors с Accept: text/plain,*/*;q=0.5 и Sec-Fetch-Dest: text, поэтому ответу с другого origin нужен заголовок Access-Control-Allow-Origin. Какую директиву CSP проверяет браузер? connect-src: при default-src 'none'; script-src 'self' импорт блокируется, а с добавленным connect-src 'self' проходит. Карта модулей различает записи по паре «URL и тип», поэтому файл, импортированный и как JS, и как текст, загружается дважды. Статический импорт в браузере без поддержки ломает весь модуль. Chromium 141 выдаёт TypeError: "text" is not a valid module type., и код модуля не выполняется. Пока Safari такой импорт не поддерживает, в коде без сборки оставляем динамический импорт с запасным fetch: async function importText(url) { try { return (await import(url, { with: { type: 'text' } })).default; } catch (e) { if (!(e instanceof TypeError)) throw e; const res = await fetch(url); if (!res.ok) throw new Error(`${res.status} ${url}`); return res.text(); } } Перехватываем только TypeError: эту ошибку import() выдаёт при неизвестном типе модуля. Сбой сети тоже даёт TypeError, и тогда fetch запрашивает файл повторно. URL передаём абсолютным, например new URL('./card.html', import.meta.url).href: import() отсчитывает относительный путь от URL модуля, а fetch — от URL документа. В Vite 8.3 атрибут не работает. Известные ему ассеты вроде .txt и .svg он молча превращает в URL: файл меньше 4 KiB становится data URL, остальные уходят в /assets/…. Шаблоны .html, .md и шейдеры Vite разбирает как JS, и сборка падает с MISSING_EXPORT или PARSE_ERROR. esbuild 0.28 и webpack 5.112 учитывают атрибут и встраивают содержимое строкой. TypeScript 7 без declare module '*.txt' выдаёт TS2307 (Cannot find module). В проектах со сборкой синтаксис можно писать уже сейчас, если сборщик его понимает, а для Vite нужен суффикс ?raw или плагин, который переписывает такие импорты на ?raw. Без сборки нативный импорт берём, только когда его поддерживают все целевые браузеры, а до тех пор подключаем файлы через importText. #frontendvkhub #chrome #vite
Открыть в TelegramДинамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 11 ч | 143 |
| 32 ч | 174 |
| 68 ч | 184 |
- Через 24 часа174
- Всего сейчас184
JPEG XL вернулся в Chrome: что с ним делать фронтенду У любого большого сервиса есть терабайты старых JPEG, которые никто не трогает. Пережимать их в AVIF жалко: каждое сжатие с потерями добавляет новые артефакты к старым, а оригинал потом не вернуть. Вот они и лежат, и каждый день уезжают к пользователям в исходном весе. JPEG XL умеет перепаковывать JPEG без потерь. Файл становится в среднем на 20% легче, а если понадобится, из него можно собрать исходный JPEG байт в байт: cjxl photo.jpg photo.jxl djxl photo.jxl restored.jpg Если на входе JPEG, cjxl перепаковывает его без потерь по умолчанию — флаги не нужны. Долго от этого было мало толку. Chrome перестал поддерживать формат в 2023 году, в версии 110, а без самого популярного браузера возиться с JXL никто не хотел. 6 октября Chrome 155 включил JPEG XL обратно, на этот раз с декодером jxl-rs на Rust. 13 октября формат включил и Firefox 158, а Safari поддерживает JXL ещё с версии 17. Правда, «поддерживает» в случае Safari — громко сказано. Он показывает только статичные картинки, без анимации и прогрессивной отрисовки, поэтому большой hero появится целиком и только после полной загрузки. В Edge и Samsung Internet формата нет вовсе, так что без запасного варианта не обойтись: <picture> <source srcset="/img/hero.jxl" type="image/jxl"> <source srcset="/img/hero.avif" type="image/avif"> <img src="/img/hero.jpg" width="1600" height="900" alt=""> </picture> Здесь важен порядок source. Если JXL стоит первым, Safari выберет его вместо AVIF и покажет hero только после полной загрузки. Для LCP-картинки такой порядок может оказаться хуже, чем AVIF на первом месте, так что оба порядка лучше замерить на реальных страницах, чем гадать. С анимацией решение проще: в JXL через <picture> её не отдаём совсем. Атрибут type не отличает анимацию от статики, поэтому Safari честно выберет файл, который не сможет проиграть. Отдавать формат по заголовку Accept тоже можно, но удовольствие сомнительное. Понадобится Vary: Accept, и кеш CDN раздробится. К тому же браузеры перечисляют форматы в разном порядке. Firefox, например, ставит image/jxl после image/avif, и сервер, который берёт первый тип из списка, разным браузерам отдаст разные форматы. Тем, кто обрабатывает картинки в Node, стоит знать ещё одну деталь: в готовых сборках sharp нет libjxl, а вывод в JXL там помечен как экспериментальный. Проще вызывать cjxl напрямую или переложить конвертацию на CDN. Начинать лучше с архива. Старые JPEG перепаковываем без потерь и отдаём через <picture> с JPEG в запасе: качество не страдает, трафик падает сразу. Для новых картинок JXL стоит сравнить с AVIF на своём контенте. Google и сам советует пробовать оба формата и отмечает, что JPEG XL полезнее всего при высоком качестве и при сжатии без потерь. А у вас старые JPEG так и лежат как есть? #frontendvkhub #jpeg #chrome
Открыть в TelegramДинамика просмотровСкрыть динамику
Рост просмотров
Часов после публикации
Показать таблицей
| Часов после публикации | Просмотры |
|---|---|
| 0 ч | 0 |
| 1 ч | 99 |
| 9 ч | 159 |
| 36 ч | 190 |
| 54 ч | 226 |
| 69 ч | 234 |
- Через 1 час99
- Всего сейчас234
ES2026: что из нового стандарта можно брать в код уже сейчас ECMAScript обновляется раз в год, и к моменту утверждения стандарта его новинки обычно уже работают в браузерах. 30 июня 2026 года Ecma International утвердила ES2026, семнадцатую редакцию языка. Интересного синтаксиса в ней нет, зато закрыты мелкие задачи, ради которых годами тянули зависимости или писали свои утилиты: 🔵Base64 из байтов 🔵точная сумма чисел 🔵Map со значением по умолчанию 🔵большие числа в JSON Почти всё это уже доступно в свежих версиях браузеров. #frontendvkhub #ecmascript
Открыть в TelegramFrame-sizing в Chrome 154: iframe сам подстраивает высоту под контент Виджет комментариев, форма оплаты или дашборд во фрейме почти всегда упираются в высоту. Хост не знает, сколько места нужно странице внутри, поэтому она меряет себя сама и шлёт размер через postMessage, а родитель ловит сообщение и меняет высоту фрейма. Этот мост каждая команда пишет заново, и пока первое сообщение не пришло, фрейм стоит с фиксированной высотой и прокруткой внутри. Chrome 154, вышедший 22 сентября, справляется без скриптов. Нужны две вещи: CSS-свойство frame-sizing на стороне хоста и метатег с согласием в документе внутри фрейма. .embed { width: 100%; height: 500px; /* для браузеров без поддержки */ } @supports (frame-sizing: content-height) { .embed { height: auto; frame-sizing: content-height; max-height: 80vh; } } Встраиваемая страница должна разрешить это явно, иначе хост её размер не получит: <meta name="responsive-embedded-sizing" content="allow-origins=https://publisher.example"> Решение принимает встраиваемая сторона: в allow-origins через пробел перечисляются домены, которым можно сообщать размер, либо ставится *. Схема работает и для фреймов с другого домена и дополняет frame-ancestors из CSP. Тег должен быть в документе с самого начала, добавить его скриптом после загрузки не выйдет. Кроме content-height, у свойства есть content-width, логические content-inline-size и content-block-size, а также auto, которое оставляет прежнее поведение. Для виджетов, растущих вниз, подходит content-height. Размер браузер берёт после загрузки и дальше за каждым изменением вёрстки не следит. Если содержимое поменялось, например подгрузились новые комментарии, документ сам просит пересчитать размер: if ("requestResize" in window) { window.requestResize(); } Вызывать его лучше после того, как все изменения внесены, а не на каждом шаге, чтобы не уйти в цикл пересчётов. За удобство платят сдвигом вёрстки: фрейм вырастает уже после загрузки встроенной страницы и тянет вниз всё, что под ним, поэтому в первом экране такой виджет ухудшит CLS. Старый мост на postMessage пока выбрасывать рано, потому что в Firefox и Safari поддержки нет. Зато метатег во встраиваемые страницы можно добавлять уже сейчас, а на хосте включать frame-sizing под @supports и оставить прежний код запасным путём. А вы сейчас подгоняете высоту iframe через postMessage или живёте с фиксированной? #frontendvkhub #chrome #css
Открыть в TelegramVite+ — не новая версия Vite и не его замена. Это отдельная утилита, которая объединяет инструменты вокруг Vite в один CLI: Vite 8, Vitest 5, Oxlint, Oxfmt, Rolldown и tsdown. 28 сентября VoidZero выпустила первый стабильный релиз. Разбираемся вместе с Петром Гилевичем, руководителем веб-разработки контентных сервисов ВКонтакте, как там всё устроено. В чём идея Фронтенд-проект требует набор инструментов: сборщик, тесты, линтер, форматтер, сборка npm-пакетов. Каждый обновляется сам по себе, у каждого своя конфигурация, а локальное окружение и CI расходятся — привет, worked on my machine. Заявленные кратные ускорения касаются линтинга и нового ядра сборки в Vite 8. Версии всех инструментов подобраны и протестированы вместе, обновляются одной командой и гарантированно работают в связке. Как устроено Глобальная утилита vp — отдельная программа, ставить через npm не нужно. Она смотрит, какая версия Node.js нужна проекту, скачивает её и переключает при переходе между проектами. В самом проекте вместо отдельных Vite, Vitest и Oxlint в зависимостях остаётся один пакет vite-plus — версии инструментов зашиты в него. Есть нюанс: если доставить какой-то инструмент отдельно, можно случайно получить вторую его копию и сломать связку — документация предупреждает об этом. Vite Task в монорепозитории и кеширование сборки Если вы разрабатываете несколько пакетов в одном репозитории, рутину — прогоны тестов и другие пайплайны — берёт на себя движок Vite Task. Он умеет то, ради чего раньше отдельно ставили Turborepo. Во-первых, он видит, какой пакет от какого зависит, и запускает сборки в правильном порядке: сперва библиотека, потом зависящее от неё приложение. Внутри одной сборки порядок модулей и так определяет сборщик — а вот очерёдность сборок между пакетами одного репозитория как раз зона ответственности Vite Task. Во-вторых, он кеширует сборки: vp run build --cache снимает fingerprint зависимостей модуля. Запустите команду снова, не меняя код, — сборка полностью пропустится, и результат мгновенно вернётся из кеша. Пока кеш хранится локально, но у Vite+ в планах удалённый — как у конкурентов, в том числе для использования на CI. Как Vite+ стал открытым Изначально Vite+ планировали сделать платным. Но до публичного релиза от платной модели отказались: код открыли под MIT. Почему передумали — в секции MIT License на сайте VoidZero прокомментировали: «Мы устали спорить, какие функции должны быть платными и как их ограничивать». Летом 2026 Cloudflare купила VoidZero — инструменты остаются открытыми. Что в итоге Получаем управление всей экосистемой вокруг Vite одной командой: один апгрейд вместо синхронизации пяти инструментов. Из коробки есть миграция: vp migrate пытается влить все конфигурации — линтера, форматтера, тестов — в один vite.config.ts, переписывает скрипты package.json на vp-команды и перед изменениями показывает план. Миграция рассчитана на свежие Vite 8+ и Vitest 4.1+; прехуки на Husky (утилита для Git-хуков) остаются как были — их подключают к Vite+ вручную. Отдельный CLI — знак того, что проект растят как целую экосистему для JS-проектов без привязки к пакетному менеджеру и предустановленному Node. Можно предположить, что дальше мы увидим поддержку других сред выполнения и возможность миграции между ними, но обещаний нет. Старт мощный: 2,4 млн скачиваний в неделю на начало октября, мейнтейнер с мировым именем. Небольшим проектам, которые уже на Vite, пробовать можно. Крупным, вероятно, надо повременить: недавно Vite сменил ядро сборки на Rolldown, и это был очень серьёзный апдейт. Непонятно, будут ли подобные обновления в ближайшие год-два. Экспериментальный Bundled Dev Mode может быть причиной новых мажорных изменений — тогда мигрировать придётся не один раз. #frontendvkhub #vite #что_нового
Открыть в Telegram🔵STP 252: @supports научился проверять сами условия 11 сентября в Safari Technology Preview 252 добавили CSSConditionRule.supports и named-feature() в @supports — проверку поддержки фич без детектируемого синтаксиса, например anchor positioning. Заодно распрефиксовали user-select — теперь это стандартное свойство без -webkit-. 🔵Safari 27 — новые возможности CSS и HTML 14 сентября вышел Safari 27 с кастомизацией <select>, псевдоклассом :heading, sizes="auto" и расширениями color-mix(). WebKit также обновил загрузчик ES-модулей, улучшив поддержку top-level await. 🔵Node.js 26.9 — быстрые Worker Threads и FFI 16 сентября Node.js ускорил запуск Worker Threads до 2 раз и снизил их потребление памяти. Экспериментальный node:ffi теперь включён по умолчанию — вызывать функции нативных библиотек можно без отдельного модуля C++. 🔵Chrome 154: браузер переходит на двухнедельный релиз-цикл 22 сентября вышел Chrome 154 — первый релиз по новому двухнедельному расписанию вместо прежнего четырёхнедельного. Из фич для вёрстки: • scroll-marker-group получил режимы links/tabs, которые задают фокус-порядок и ARIA-семантику для ::scroll-marker-group • iframe теперь можно сделать самоподстраивающимся под контент через frame-sizing: content-height — без ручного измерения высоты и postMessage 🔵Next.js: серия security-апдейтов закрывает критическую уязвимость в апстриме 22 сентября Vercel выпустил внеплановый патч 16.3.6 и 15.5.26 из-за критической уязвимости в сторонней зависимости. А 30 сентября — плановый сентябрьский security-релиз 16.3.8 и 15.5.27, закрывающий ещё 7 уязвимостей: 1 высокой степени критичности, 5 средних и 1 низкую. Если вы ещё не обновили проект на Next.js — не откладывайте это. 🔵Safari Technology Preview 253: sibling-index() добрался до @container 23 сентября в STP 253 sibling-index() и sibling-count() стало можно использовать прямо в условиях @container. То есть раскладка контейнера теперь может зависеть не только от его размера, но и от позиции элемента среди соседей. WebKit также обновил безопасное выравнивание (safe/unsafe) для абсолютно позиционированных боксов, чтобы они не вылетали за пределы исходного содержащего блока. #frontendvkhub #дайджест
Открыть в TelegramCSS в 2026 году: где JavaScript уже не обязателен Открыть поповер, подсветить карточку с выбранным чекбоксом, растянуть textarea под текст — раньше на каждую такую мелочь заводился скрипт, состояние и подписка на события. За два года CSS забрал у JavaScript целый пласт таких задач, и часть фич уже прошла порог Baseline. Максим Кузнецов из команды веб-версий ВКонтакте разобрал, что из этого можно брать в продакшен прямо сейчас, что подключать осторожно, а за чем пока просто следить. ➡️В карточках — короткая версия с актуальными статусами поддержки. А подробнее читайте на Хабре. #frontendvkhub #css
Открыть в TelegramURLPattern: маршруты, которые не нужно переписывать в регулярки В любом приложении со своей маршрутизацией рано или поздно заводится файл с регулярками. /^\/users\/(\d+)\/posts\/([\w-]+)$/ работает, но читается тяжело, номера групп приходится помнить наизусть, а проверка домена и протокола живёт отдельным условием рядом. Обычный выход состоит в том, чтобы притащить path-to-regexp и получить ещё одну зависимость ради разбора адреса. Разбирать адреса умеет сама платформа. URLPattern принимает шаблон в знакомом по роутерам синтаксисе и сопоставляет с ним URL целиком, а не только путь: const route = new URLPattern({ pathname: "/users/:id/posts/:slug" }); route.test("https://app.example.com/users/42/posts/hello"); // true const match = route.exec("https://app.example.com/users/42/posts/hello"); match.pathname.groups; // { id: "42", slug: "hello" } Группы именованные, так что возиться с их порядком не нужно. Кроме :name, доступны звёздочка для любого остатка, модификаторы ? и +, фигурные скобки для необязательных кусков пути и собственные регулярки прямо внутри шаблона: /v:version(\\d+)/ поймает только числовую версию. Шаблон покрывает все части адреса сразу, и на этом удобно строить таблицу маршрутов в Service Worker или в edge-функции: const routes = [ [new URLPattern({ pathname: "/api/v:v(\\d+)/*" }), handleApi], [new URLPattern({ hostname: "cdn.example.com" }), handleAssets], ]; self.addEventListener("fetch", (event) => { const route = routes.find(([pattern]) => pattern.test(event.request.url)); if (route) event.respondWith(route[1](event.request)); }); Главная разница между двумя формами записи проявляется как раз тут. В объектной форме всё, что не указано, считается звёздочкой: шаблон выше совпадёт с любым протоколом и любой строкой запроса. В строковой форме, new URLPattern("https://example.com/books/:id"), пропущенные части приравниваются к пустой строке, поэтому адрес с параметрами мимо такого шаблона пройдёт, пока не дописать ?*#* вручную. Дальше идёт мелочёвка. Двоеточие внутри литерала экранируется обратным слешем, иначе парсер примет его за начало группы. Юникод в регулярных группах придётся кодировать процентами самостоятельно: автоматически платформа этого не делает. Регистр по умолчанию учитывается, а выключается опцией ignoreCase. С сентября 2025, когда поддержку закрыл Safari 26, API считается Baseline и работает в том числе в воркерах. Для старых браузеров есть официальный полифилл urlpattern-polyfill, он же закрывает Node без экспериментальных флагов. Смысл переезжать есть там, где роутер только сопоставляет адреса и достаёт из них параметры: слой регулярок или path-to-regexp в этом случае удаляется целиком. Если поверх маршрутизации навешаны вложенные layout-компоненты, middleware и ленивые импорты, URLPattern занимает нижний уровень, а остальное остаётся вашим кодом. #frontendvkhub #javascript #urlpattern
Открыть в Telegram