Telegram Web
В SPA сломано много вещей, которые нормально работают в обычных сайтах. Одна из таких вещей — переходы между страницами. Используете динамический роутинг? Оберните содержимое страниц в элемент с tabindex="-1", role="region" и aria-label="Содержимое текущей страницы", а при переходах между страницами устанавливайте фокус на эту обёртку. Эта базовая техника сделает ваше приложение немного доступнее для тех, кто пользуется кнопкой tab или экранными читалками.
Реализация такой обёртки на Реакте
Использование обёртки с Реакт-Роутером (v3)
Ваня Акулов (@iamakulov_channel) справедливо спрашивает, зачем нужна эта обёртка — я не объяснил, в чём проблема.

Представьте, что в футере вашего SPA есть ссылка на страницу «о проекте». При клике по этой ссылке совершается динамический переход на нужную страницу, но даже после перехода фокус так и остаётся на ссылке. Из-за этого пользователи экранных читалок даже не узнают, что страница поменялась — для них это воспринимается так, будто никакого перехода и не было. Поэтому нужно после динамических переходов переносить фокус на контейнер страницы — тогда экранная читалка после клика по ссылке не будет молчать, а озвучит что-то вроде «Содержимое страницы, 5 элементов». Ну и если вы после динамического перехода нажмёте tab, фокус перейдёт на первый интерактивный элемент внутри страницы, а не на то, что располагалось после кликнутой ссылки.
Определяем видимость элемента с IntersectionObserver

IntersectionObserver это новый браузерный API, позволяющий асинхронно следить за степенью пересечения элемента с вьюпортом или другим элементом. С его помощью можно определить, виден ли элемент на экране, если виден, то насколько (целиком или частично), а также когда именно он оказался виден. Пример того, где это может потребоваться — модуль для ленивой загрузки картинок.

Недавно на работе была задача залогировать событие просмотра блока на сайте. Я как представил, что нужно подписываться на событие скролла и вручную считать, входит ли элемент целиком во вьюпорт... А затем вспомнил про IntersectionObserver, прочитал документацию и обрадовался, потому что с ним задача решается гораздо проще и красивее:

const observer = new IntersectionObserver(handleIntersection, {
root: null, // отслеживаем пересечение с вьюпортом, а не с элементом, поэтому null
threshold: 1 // порог видимости, при котором сработает обзёрвер; 1 означает полную видимость, 0.5 означало бы 50% видимости
});

observer.observe(document.getElementById('target'));

function handleIntersection(entries) {
// Обзёрвер срабатывает в том числе когда элемент скрывается из вьюпорта, поэтому нужна дополнительная проверка
if (entries[0].intersectionRatio === 1) {
logBlockView();
}
}


IntersectionObserver поддерживается в последних версиях Chrome, Edge и Firefox, для остальных браузеров есть полифил (6.6 КБ в минифицированном виде). Подробнее об IntersectionObserver на MDN.
У Эстонии есть собственная дизайн-система — https://brand.estonia.ee/
А ребята из http://gov.design теперь пилят единый навигатор по государственным сайтам и услугам — https://gov.gosuslugi.ru/
На собеседованиях иногда просят назвать способы отправки запроса на сервер. Помимо очевидных fetch/XMLHttpRequest и прочих джаваскриптовых штук есть более экзотические способы вроде <img src="...">.

Вчера узнал о ещё более экзотическом и извращённом способе отправки запроса на сервер с помощью CSS:


body::after {
content: url('...');
}


Этот способ может использоваться для аналитики и трекинга пользователей, у которых отключен JS. Можно отследить клики по ссылкам, ввод текста в инпуты, клики по чекбоксам, длительность ховера на каком-либо элементе; также можно приблизительно определить браузер и операционную систему пользователя. Подробности — https://github.com/jbtronics/CrookedStyleSheets

Защититься от этого можно только отключив CSS. Параноикам пора переходить на текстовые браузеры :–)
У TC39 (технический комитет, разрабатывающий стандарт ECMAScript) появился логотип — https://github.com/tc39/logo
Как амперсанд эволюционировал из латинского et (тот же «и») в отдельный символ
Шпаргалка по основным командам перемещения и удаления текста в терминале (для тех, кто устал от стрелочек или кому было лень специально это гуглить)
Выкатил очередной редизайн своего сайта: http://andrew-r.ru
Главной целью был отказ от Эгеи (движок для ведения блога) и переход на что-то попроще. В итоге пока что использую Jekyll, дальше будет видно, насколько с ним будет удобно жить. Главное — теперь нет стороннего кода и всё под моим контролем, есть простор для кастомизации и экспериментов.
Главный принцип построения архитектуры ПО
Позавчера был мой последний рабочий день в Авито. За год удалось здорово прокачаться во фронтенде, запилить с нуля новый раздел помощи (support.avito.ru) и интегрировать его в мобильные приложения через вебвью, повлиять на развитие общей библиотеки компонентов и нового фронтенд-стека.

Главный вывод, который я сделал — очень многое в работе зависит от команды, это особенно заметно в больших компаниях вроде Авито. Чем сплочённее команда, чем больше в ней единомышленников, тем лучше результат; такой команде не требуется авторитарное управление и навязывание процессов вроде скрама. Если же собрана не очень дружная команда, участники которой не понимают друг друга, результат будет практически нулевым, а попытки навязать команде какие-то процессы скорее всего деморализуют участников и приведут к распаду.
Обратил внимание на UX установщиков программ на винде: установщик весит всего несколько сотен килобайт и скачивается практически моментально, чтобы пользователь сразу открыл его и запустил установку. А скачивание самой программы сделано частью процесса установки, к длительности которого пользователи уже менее требовательны — раз устанавливается, можно подождать.
TL; DR к статье https://www.viget.com/articles/make-your-site-faster-with-preconnect-hints

Прежде чем обратиться к какому-то ресурсу, браузеру нужно установить соединение: определить IP-адрес хоста и провести TCP/TLS-рукопожатия. При плохих условиях на это могут уйти сотни миллисекунд.

На страницах сайта могут использоваться ресурсы с внешних хостов, например, шрифты с Google Fonts или видео с YouTube. Эти ресурсы чаще всего загружаются отложенно: шрифты начинают загружаться после их обнаружения в таблице стилей, превью для видео с ютуба грузится после инициализации плеера. Чтобы сократить время загрузки этих ресурсов, можно указать браузеру, с каких хостов вы собираетесь загружать ресурсы, и он заранее установит соединения с этими хостами. Если вы используете шрифты с Google Fonts, пропишите в <head> такую строчку:

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>


Атрибут crossorigin требуется именно для загрузки шрифтов (https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements).

Если на странице есть плеер ютуба, пропишите в <head> предыдущую подсказку (плеер использует Roboto с Google Fonts) и ещё четыре подсказки:

<link rel="preconnect" href="https://www.youtube.com">
<link rel="preconnect" href="https://i.ytimg.com">
<link rel="preconnect" href="https://i9.ytimg.com">
<link rel="preconnect" href="https://s.ytimg.com">


С тем же успехом можно добавлять подсказки и для других хостов.
Наглядная демонстрация профита от преконнекта к хосту гуглошрифтов
Почему в CSS не будет селекторов, зависящих от текущего состояния раскладки?

Удобно было бы иметь псевдоклассы вроде :stuck для элементов с position: sticky или :overflowing для элементов, переполненных содержимым. К сожалению, таких псевдоклассов не будет, потому что они могут привести к цикличности — для них можно прописать правила, которые отменят действие этих псевдоклассов:

aside { position: sticky; top: 0; }
aside:stuck { position: static; }


Подробнее — https://wiki.csswg.org/faq#selectors-that-depend-on-layout
Постоянно выходят какие-то реакт-подобные библиотеки, которые супербыстрые, работают в IE8 и весят совсем мало. Ничего кардинально нового они не несут, так что вместо них расскажу о действительно интересной библиотеке.

Glimmer — бывший UI-движок Ember, выросший в отдельный проект. Он отличается от реакта и подобных библиотек тем, что его шаблоны компилируются не в JavaScript, а в JSON. Этот JSON на стороне клиента компилируется в байткод, исполняемый в виртуальной машине Glimmer (в терминах Glimmer это называется last mile compilation). Выглядит этот JSON примерно так:

[
['startProgram', [0, []]],
['text', [0, 3]],
['mustache', [1, 3]],
['openElement', [2, 3, 0, []]],
['closeElement', [2, 3]],
['endProgram', [0]]
]


Чем компиляция шаблонов в JSON лучше компиляции в JavaScript? Временем их парсинга, которое критично на мобильных устройствах. Грамматика JSON сильно проще JS, поэтому и парсится JSON гораздо быстрее.

Несмотря на скорость парсинга JSON, с ростом количества шаблонов растут и затраты на их парсинг. Ребята из LinkedIn знатно упоролись и решили свести эти затраты к нулю: вместо компиляции в JSON они сразу компилируют шаблоны в байткод и доставляют их в браузер в бинарном формате, так что на стороне клиента last mile compilation не требуется и виртуальная машина Glimmer может сразу исполнять полученный байткод.

Байткод в бинарном формате сокращает не только время парсинга, но и размер шаблонов. А в ближайшем будущем можно будет добиться ещё большей скорости, портировав части виртуальной машины Glimmer на WebAssembly.
2025/07/08 03:26:33
Back to Top
HTML Embed Code: