frontendhubvk | Unsorted

Telegram-канал frontendhubvk - Frontend VK Hub

-

Комьюнити VK для фронтендеров. Кто и что стоит за интерфейсами, которыми пользуются миллионы пользователей, — от Почты Mail до VK Teams — рассказываем здесь 🤘

Subscribe to a channel

Frontend VK Hub

History API создавался для полных перезагрузок страниц. SPA-роутеры годами строили поверх него абстракции: popstate не стреляет при pushState, клики по ссылкам нужно перехватывать вручную, для хеша нужен отдельный слушатель, а history.length даёт только число вместо доступа к стеку.

Navigation API решает это единым событием navigate на window.navigation. К нему приходят клики по ссылкам, сабмиты форм, back/forward и программные переходы — один обработчик вместо россыпи слушателей.

➡️ Роутер на History API:

window.addEventListener("click", (e) => {
const link = e.target.closest("a");
if (!link) return;
e.preventDefault();
history.pushState({}, "", link.href);
render(link.href);
});

window.addEventListener("popstate", () => {
render(location.pathname);
});


➡️ Тот же роутер на Navigation API:
navigation.addEventListener("navigate", (e) => {
if (!e.canIntercept) return;

e.intercept({
async handler() {
const data = await loadRoute(new URL(e.destination.url));
render(data);
e.scroll();
},
});
});


intercept() отключает перезагрузку страницы — DOM обновляет роутер. Условие !canIntercept отсекает переходы, которые нельзя перехватить. Браузер показывает нативный лоадер, пока промис из handler не зарезолвится. e.scroll() восстанавливает прокрутку при back/forward без ручного сохранения координат.

Стек истории

history.length — просто число. Navigation API открывает стек через navigation.entries():
const prev = navigation
.entries()
.slice(0, navigation.currentEntry.index)
.findLast((e) => new URL(e.url).pathname.startsWith("/list"));

if (prev) navigation.traverseTo(prev.key);


Код находит последний /list в стеке и переходит к нему. На History API для этого нужен параллельный стек на глобальных переменных.

У каждой записи два идентификатора:
🔵id – для привязки кэша, уникальный, не переиспользуется
🔵key – для навигации по стеку, переиспользуется при replace

Состояние записи читается через getState() — оно иммутабельно, для обновления нужен updateCurrentEntry().

Отмена переходов встроена. Если пользователь нажал stop или начался новый переход до завершения текущего, e.signal отменяет незавершённый fetch:
e.intercept({
async handler() {
const data = await fetch(url, { signal: e.signal });
if (e.signal.aborted) return;
render(data);
},
});


Новый API поддерживается в Chrome 102+, Firefox 147+, Safari 26.2+. Полифилл — @virtualstate/navigation. React Router и TanStack Router пока остаются на History API, но оба уже обсуждают переход.

#frontendvk #javascript #navigationapi

Читать полностью…

Frontend VK Hub

Google Search сократил HTML с 107 kB до 60 kB для вернувшихся пользователей. Etsy, Amazon, eBay экономят до 96% на передаче данных.

➡️ Compression Dictionary Transport (RFC 9842) — стандарт HTTP, который переиспользует загруженные ответы как словари сжатия.

#frontendvk #compressiondictionarytransport #http

Читать полностью…

Frontend VK Hub

Разбираем State of HTML 2025, в котором поучаствовали ~6200 респондентов. Главная боль — не нехватка модных API, а невозможность стилизовать <select> и <input type="date">.

#frontendvk #stateofhtml

Читать полностью…

Frontend VK Hub

Делимся результатами ежегодного опроса Devographics о трендах CSS — State of CSS 2025.

Более 5500 респондентов и 50 CSS-фич. :has() — самая используемая (80.4%) и самая любимая (51.5%) фича.

#frontendvk #stateofcss

Читать полностью…

Frontend VK Hub

Разбираем новый отчет от Devographics — ежегодный независимый опрос экосистемы State of React 2025. Данные собирали с ноября 2025 по январь 2026, участие приняли около 3760 разработчиков.

🔵Самая ожидаемая фича: React Compiler
🔵Vite впервые обошёл webpack по использованию
🔵shadcn/ui вплотную приблизился к MUI
🔵Next.js удерживает лидерство по использованию, но теряет удовлетворённость
🔵React Foundation лидирует по позитивным оценкам сообщества

#frontendvk #react #stateofreact

Читать полностью…

Frontend VK Hub

Popover API

Каждый попап на сайте — это исторически минимум 30 строк JS: открыть, закрыть по клику снаружи, поймать Escape, не дать фокусу уйти за пределы, поднять z-index выше всего остального. Popover API делает это нативно. С января 2025 он в Baseline — работает во всех современных браузерах без полифилов.

#frontendvk #javascript #popoverapi

Читать полностью…

Frontend VK Hub

State of JavaScript 2025

Недавно был опубликован State of JS 2025 — ежегодный опрос экосистемы JavaScript от Devographics. В этом году его прошли почти 13 000 разработчиков. Собрали самое важное в карточках.

🔵Самый быстрорастущий инструмент: Vitest и Playwright (+14% год к году)
🔵Самая высокая удовлетворенность: Vite (98% положительных оценок)
🔵Наивысший интерес: Vitest (83%)
🔵Next.js — самый обсуждаемый и самый поляризующий проект

#frontendvk #javascript

Читать полностью…

Frontend VK Hub

@layer — каскадность без !important

Специфичность в CSS всегда была проблемой. Один сторонний компонент с высокой специфичностью, и ты пишешь !important, потом !important поверх !important. @layer делает все это проще.

#frontendvk #css #layer

Читать полностью…

Frontend VK Hub

🔵Chrome 145: column-height и column-wrap
Новые свойства для multi-column layout, которые позволяют строить 2D-потоки с вертикальным заполнением. Пока только Chrome 145+.

🔵focusgroup — нативная клавиатурная навигация
Новый HTML-атрибут focusgroup позволяет делать arrow-key навигацию без ручного управления tabindex — браузер сам перемещает фокус внутри контейнера.

🔵Intl API — форматирование без зависимостей
Intl форматирует даты, время, числа, списки и текст с учётом локали прямо в браузере. Никаких лишних килобайт в бандле — всё из коробки.

🔵Сравнение JS-минификаторов
Бенчмарк популярных минификаторов (SWC, oxc-minify, esbuild, terser, uglify-js) по размеру выходного файла и скорости. Полезно при выборе инструмента для production-сборки.

🔵CSS-анимации как state-машина
Запоминание прошедших состояний интерфейса через CSS-анимации: например, был ли элемент в hover. Значение записывается в CSS-переменную через keyframes.

🔵 Диапазон дат на чистом CSS
Подсветка диапазона между двумя датами через :nth-child(N of selector) и :has. Вся визуализация на CSS, JS нужен только для обработки кликов.

📌 Новая статья от инженеров VK на Хабр:
Как мы пережили цветовой кризис в RuStore и нашли путь к тёмной стороне темы

#дайджест #frontendvk

Читать полностью…

Frontend VK Hub

CSS :has() — не parent selector, а условная логика прямо в CSS

:has() часто объясняют как «наконец-то parent selector» — можно стилизовать родителя в зависимости от дочернего элемента. Это правда, но это самый скучный способ его использовать. Интереснее то, что :has() по сути добавляет в CSS условную логику, которую раньше можно было выразить только через JavaScript.

В январе 2025 :has() получил статус Baseline Newly Available после исправления бага в iOS Safari — теперь работает во всех современных браузерах. По State of CSS 2025 — один из самых используемых и любимых CSS-селекторов года наравне с Grid и нативным нестингом.

➡️ Блокировка скролла без JS. Классическая задача при открытии модалки — запретить скролл на <body>. Обычно это две строчки JS: добавить класс при открытии, убрать при закрытии. С :has():

body:has(dialog[open]) {
overflow: hidden;
}
<dialog> открыт - скролл заблокирован. Закрыт - разблокирован. Ни строчки JS.


➡️ All-but-me hover. Эффект, когда при наведении на один элемент все остальные затемняются — раньше требовал JS-обработчика на каждый элемент. Теперь:
.gallery:has(.card:hover) .card:not(:hover) {
opacity: 0.5;
filter: grayscale(0.3);
}


Читается буквально: «если галерея содержит hovered card — все card которые не hovered получают opacity 0.5».

➡️ Quantity queries. Стилизовать контейнер в зависимости от количества дочерних элементов:
/* Grid с одной колонкой если элемент один */
.grid:has(> :nth-child(1):last-child) {
grid-template-columns: 1fr;
}

/* Две колонки если элементов два */
.grid:has(> :nth-child(2):last-child) {
grid-template-columns: repeat(2, 1fr);
}

/* Три и больше - три колонки */
.grid:has(> :nth-child(3)) {
grid-template-columns: repeat(3, 1fr);
}


Адаптивный layout в зависимости от контента — без медиазапросов и без JS.

➡️ Форм-стейты без JS. Подсветить поле ввода и его label, когда значение невалидно:
.field:has(input:user-invalid) label {
color: var(--error);
}

.field:has(input:user-invalid) input {
border-color: var(--error);
background: var(--error-bg);
}


:user-invalid срабатывает только после того, как пользователь взаимодействовал с полем, а не при загрузке. В связке с :has() — визуальная валидация формы только на CSS.

👆 Одно предостережение по производительности: не использовать :has() с широкими селекторами вроде body:has(*:hover) или *:has(.active). Браузеру нужно пересчитывать такой селектор при каждом изменении DOM. Чем конкретнее якорный элемент — тот, что стоит до :has(), тем дешевле пересчёт.

#frontendvk #css #selectors

Читать полностью…

Frontend VK Hub

CSS Anchor Positioning: позиционирование тултипов без JS

Каждый тултип или дропдаун на странице — это исторически JavaScript.

Popper.js, Floating UI, собственные хелперы на getBoundingClientRect. Причина одна: CSS не умел позиционировать элемент относительно другого произвольного элемента, особенно если они в разных частях DOM. С 2025 года это умеет браузер.

CSS Anchor Positioning работает в Chrome 125+, Firefox 134+ и Safari 18.2+. Для старых браузеров есть полифил от OddBird.

Идея простая: один элемент объявляется якорем через anchor-name, другой привязывается к нему через position-anchor и position-area.


.button {
anchor-name: --my-btn;
}

.tooltip {
position: absolute;
position-anchor: --my-btn;
position-area: top center;
margin-bottom: 8px;
}


position-area — сетка 3×3 вокруг якоря. top center — над якорем по центру. bottom span-right — под якорем с выравниванием вправо. Никакого calc(), никакого getBoundingClientRect.

Главная проблема старых JS-решений в том, что тултип выходит за края экрана. Anchor Positioning решает это нативно через position-try-fallbacks:

.tooltip {
position: absolute;
position-anchor: --my-btn;
position-area: top center;
position-try-fallbacks: bottom center, right span-top, left span-top;
}


Браузер последовательно пробует fallback-позиции, пока тултип не вписывается в viewport. Раньше все это требовало сотен строк JS с обработкой ресайза и скролла.

В связке с Popover API получается полностью декларативный тултип — без единой строки JavaScript:

<button popovertarget="tip" style="anchor-name: --btn">
Наведи
</button>
<div id="tip" popover style="position-anchor: --btn; position-area: top center">
Подсказка
</div>


Одно ограничение: поведение при overflow немного отличается между Chrome и Safari (открытый баг в Chromium). Для продакшена стоит тестировать оба браузера и использовать @supports (anchor-name: --test) для feature detection.

#frontendvk #css #anchorpositioning

Читать полностью…

Frontend VK Hub

Moment.js, Day.js и date-fns суммарно скачивают больше 100 миллионов раз в неделю. Три библиотеки, которые существуют только потому, что встроенный Date не справляется с базовыми задачами.

В марте 2026 Temporal достиг Stage 4 и вошёл в ES2026. Теперь это стандарт и вопрос только в том, когда все браузеры догонят.

В чём проблема Date

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

Как устроен Temporal

Temporal разделяет эти смыслы на отдельные типы, все объекты иммутабельны:
🔵 Temporal.Instant — точный момент с наносекундной точностью, без зоны и календаря;
🔵 Temporal.PlainDate — календарная дата без времени, подходит для дней рождения и дедлайнов;
🔵 Temporal.ZonedDateTime — дата-время с IANA-зоной и календарём, корректно обрабатывает переходы на летнее время.

Типичный сценарий — прибавить две недели:

// Date — мутирует объект
const d = new Date();
d.setDate(d.getDate() + 14);


Передали такой объект в функцию и исходная дата изменилась без предупреждения.
// Temporal — возвращает новый объект
const now = Temporal.Now.plainDateISO();
const inTwoWeeks = now.add({ days: 14 });


now остался нетронутым, при этом valueOf() у Instant и ZonedDateTime бросает TypeError, т.к. неявное сравнение больше не работает молча.

Арифметика и DST

Арифметика длительностей тоже стала чище. Вместо деления миллисекунд:
// Date — считать руками
const diffMs = endDate - startDate;
const days = Math.floor(diffMs / 86400000);
const hours = Math.floor((diffMs % 86400000) / 3600000);

// Temporal — готовый Duration
const duration = start.until(end, { largestUnit: "day" });
duration.days; // 1
duration.hours; // 8
duration.total("hours"); // 32


Duration не балансирует автоматически — 100 секунд остаётся PT100S, а не PT1M40S. Если нужна нормализация, то вызывайте .round({ largestUnit: 'hour' }). Это сознательное решение: разработчик видит ровно то, что задал.

DST обрабатывается явно. При переходе часов вперёд локальное время может не существовать — час просто пропускается. Temporal даёт стратегию: earlier, later, compatible или reject. Для календарей, бронирований и напоминаний это закрывает целый класс багов.

Что учесть при миграции
🔵dayOfWeek следует ISO 8601: понедельник — 1, воскресенье — 7, а не 0 и 6 как в Date.getDay()
🔵Сравнение дат — только через Temporal.PlainDate.compare(), операторы > и < молча возвращают false
🔵Chrome 144+, Firefox 139+, Edge 144+ поддерживают нативно но Safari пока отстаёт: там доступен только через Technology Preview
🔵Для продакшена с широким охватом — полифилл @js-temporal/polyfill, но он добавляет вес в бандл

Temporal заставляет выбирать правильный тип под задачу. Ментальную модель придётся перестраивать, но взамен фронтенд получает работу с датами, которая не ломается на часовых поясах и арифметике.

#frontendvk #temporal

Читать полностью…

Frontend VK Hub

Сегодня знакомимся с Андреем Едуновым, фронтенд-техлидом RuStore. Он пришёл в IT ещё во времена модемного интернета, успел из него уйти, пропустить несколько технологических революций и вернуться, чтобы строить крупнейший российский магазин приложений.

➡️ С чего началась твоя карьера в IT?

Как только у меня появился первый компьютер, я сразу в него залип. Тогда только развивался интернет по модему и первые чаты. Помню, увидел, как кто-то пишет цветным текстом, — и подумал: «А что, так можно было?»

Так я узнал про HTML, купил книжку и написал свой первый сайт — максимально простой, конечно. И понял: это моё. Моя первая должность называлась «программист-курьер». Я кодил сайт, а потом на дискетке вёз его деплоить на сервер. Вот такой у меня был пайплайн. Возможно, я был первым в мире девопсом.

➡️ С каким образованием можно стать фронтендером?

У меня высшее геодезическое. Вообще мимо IT. Тогда даже слова «фронтенд» не было — была «вёрстка», а верстальщиков называли недопрограммистами. И я как раз из таких. Но это не помешало мне дорасти до руководителя отдела дизайна и вёрстки в EPAM.

Потом я решил сменить сферу и ушёл из IT на 8 лет. Пока меня не было, в индустрии произошло несколько революций: jQuery, прототипы, Backbone, React, Node.js, сборщики, современные архитектурные подходы. Всё это пришлось догонять практически с нуля.

Возвращение было жёстким: несколько месяцев я буквально жил на JavaScript курсах, чтобы просто вернуться в форму. Дальше — отечественный финтех, зарубежные стартапы, крипта и, конечно, вишенка на торте — RuStore.

➡️ Над чем ты работаешь сейчас?

Я пришёл в RuStore на один внутренний проект, а в итоге успел поработать, кажется, везде. Год провёл в core-команде, где были нестандартные и сложные задачи.

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

Сейчас я в RuStore Консоли — это инструмент, через который разработчики загружают приложения и управляют ими в Store. И именно там я сейчас занимаюсь фичами, которые наши паблишеры давно ждут. Одной из таких фичей стала тёмная тема, про которую я подробно рассказал в статье.

➡️ Чем ты занимаешься вне работы?

На удалёнке начинаешь работать больше, чем в офисе, поэтому без хобби не обойтись. Катаюсь на сноуборде.

А на прошлый день рождения в мою жизнь снова вошла гитара — я играл в детстве, но петь не умел. Сейчас попробовал вновь пойти на вокал — занимаюсь почти год и даже выступил в клубе «16 тонн» на Арбате. Теперь это уже не просто хобби, а отдельная часть жизни.

#frontendvk #команда

Читать полностью…

Frontend VK Hub

🔵Navigation API — теперь кросс-браузерный
Navigation API становится новой основой клиентского роутинга: можно подписываться на изменения URL и перехватывать навигацию через event.intercept, делая адресную строку единым источником состояния без ручной работы с History API.

🔵Новый HTML-атрибут `focusgroup`
Microsoft Edge и Chromium уже поддерживают focusgroup, который нативно управляет клавиатурной навигацией внутри контейнеров — стрелки, пропуск disabled-элементов и восстановление фокуса теперь можно реализовывать без JS-логики.

🔵Claude нашёл 14 критических уязвимостей в Mozilla Firefox
Команда Anthropic использовала Claude для анализа исходников Firefox и обнаружила ранее неизвестные критические баги безопасности — важный сигнал о том, как LLM начинают реально применяться в аудитах сложных кодовых баз.

🔵CodePen 2.0 — переход к новой архитектуре платформы
CodePen готовит обновление с новым компилятором, расширяемой системой блоков и возможной интеграцией AI-инструментов — это может изменить привычный workflow прототипирования интерфейсов прямо в браузере. Обсуждение можно послушать в новом выпуске CodePen Radio.

🔵Opera получила 4 награды iF Design Award за интерфейс браузера
Opera стала самым награждаемым браузером в категории цифровых интерфейсов — заметный тренд на конкуренцию браузеров уже не только на уровне движков, но и UX-слоя вокруг них.

📌 Новые статьи от инженеров VK на Хабр:
🔵О специфике разработки приложений под Smart TV: личный опыт перехода от веба к ТВ
🔵От события до дашборда в облаках: практика по созданию потоковой платформы на Kubernetes

#дайджест #frontendvk

Читать полностью…

Frontend VK Hub

using — JS умеет закрывать ресурсы сам

Каждый раз, когда открываешь соединение, файл или WebSocket — где-то в коде появляется finally. Не потому что хочется, а потому что без него ресурс утечёт, если между открытием и закрытием бросит исключение.


const conn = db.connect();
try {
return conn.query('SELECT ...');
} finally {
conn.close(); // без этого будет утечка при любой ошибке выше
}


ES2026 добавляет using. Работает как const, но при выходе из блока автоматически вызывает [Symbol.dispose]() на объекте, даже если вылетело исключение.


class DbConnection {
[Symbol.dispose]() {
this.conn.close();
}
}

function processData() {
using db = new DbConnection();
return db.query('SELECT ...');
// conn.close() вызовется здесь автоматически
}


Для асинхронных ресурсов — await using с [Symbol.asyncDispose]():

async function writeLog() {
await using handle = await openFile('log.txt');
await handle.write('done');
// файл закроется после строки выше, не нужен finally
}


Это удобно в тестах. Раньше mock-сервер или тестовое соединение закрывали в afterEach, и это отдельный блок, который легко забыть или написать неправильно. С using ресурс живёт ровно столько, сколько длится тест:

test('sends request', async () => {
await using server = createMockServer();
// server.close() сам вызовется в конце теста
});


TypeScript поддерживает using с версии 5.2. Для браузеров нужен таргет ES2026 или полифил через Symbol.dispose.

#frontendvk #javascript #typescript

Читать полностью…

Frontend VK Hub

jQuery 4.0 — первый за 10 лет мажорный апдейт легендарной библиотеки

jQuery — общеизвестная библиотека, первая версия которой вышла ещё в 2006 году. На протяжении многих лет она являлась первым выбором веб-разработчика для упрощения работы на клиенте.

Ключевые изменения

🔵Удалена поддержка старых браузеров, остались только IE11 и 3-5 последних версий современных браузеров.
🔵Оптимизирован размер бандла. Появилась slim-сборка размером всего 19.5 КБ в gzip.
🔵Появился tree-shaking за счет добавления поддержки ES-модулей.
🔵Поддержка Trusted Types и использование <script> тега для загрузки модулей для предотвращения CSP ошибок.

Сами разработчики jQuery выделяют то, что хотели сделать уже очень давно, а именно удаление:
🔵незадокументированных функций;
🔵внутренних переменных;
🔵устаревших API.

Так были удалены поддержанные в современном JS 13 deprecated-утилит, включая:
🔵jQuery.isArrayArray.isArray();
🔵jQuery.isNumeric → нативные проверки;
🔵jQuery.trimString.prototype.trim();
🔵jQuery.parseJSONJSON.parse().

Еще в этой версии jQuery отказались от собственного определения порядка фокуса элементов, которое ранее было необходимо для консистентности в удалённых из поддержки браузерах.

Актуальность

Несмотря на возраст, пакет jQuery по-прежнему получает десятки миллионов загрузок в месяц (70+ млн по npm). А по данным W3Techs он до сих используется более чем на 70% всех веб-сайтов. Особенно явно jQuery оставил свой след в enterprise-сегменте и CMS-решениях (в частности Wordpress).

Как тебе такое, Кирилл?

«Услышав об этом событии, я был искренне удивлен. В весомой части проектов использование jQuery принято избегать и упоминать о библиотеке разве что в контексте мема. Тем не менее сложно отрицать повсеместную распространенность библиотеки, а потому и новость о таком обновлении не видится исключительно смешной и не обоснованной. Более того, вместе с выпуском 4.* версии, разработчики сразу частично охарактеризовали и последующий 5.* апдейт.

Если говорить про характер изменений, то их можно описать, как глобальный рефакторинг с клинкодом, багофиксингом и адаптацией под современные стандарты (esm, csp), которые де факто являются таковыми уже не год и не два. Поэтому возникает вопрос: “Почему только сейчас?”.

Допускаю, что разработчики ждали прохождения своеобразного трешхолда по уменьшению присутствия старых браузеров в мире веба, на что намекает их аккуратный подход по внедрению изменений со словами из описания выпущенного ими релиза: “мы ожидаем, что большинство юзеров смогут обновиться с минимальными изменениями в их коде”. Но разве не разумно оставлять выбор о необходимости поддержки старых браузеров потребителям и параллельно делать то, что делают успешные проекты, а именно активно и своевременно адаптировать инструменты под потребности своего сообщества?

Оценивая потенциальный эффект от обновления, думаю, что это обновление хоть и несколько развязывает руки по использованию jQuery в современных реалиях, но оно НЕ запустит массовую работу над заблокированном техдолгом, потому что если >70% сайтов до сих пор мирится с наличием у себя jQuery, четверть из которых вообще имеет 1 или 2 версию, то вопрос - откуда должна взяться мотивация на переход к 4.* версии, когда разворачивание React/Svelte/Vue/etc в формате SPA и микро-фронтов — это шаблонно и привычно, а отличное от удаления прикосновение к jQuery в отдельных проектах не иначе как моветон​», — рассказал Кирилл Радыгин, ​руководитель Web платформы Одноклассников.


А что думаете вы — как в 2026 году видите применимость jQuery в проектах, в которых уже есть React/Svelte/Vue?

#frontendvk #jquery

Читать полностью…
Subscribe to a channel