Latest posts

Катерина | Про Frontend
22 Feb, 18:04
Когда height: 100% чуть-чуть поломало вёрстку 🙈Я делала простую сетку: контейнер display: grid, строки — grid-template-rows: repeat(n, auto), в одной ячейке был элемент, которому я прописала height: 100%, чтобы он «растянулся красиво». В Chrome всё было отлично, а вот в Safari макет разъехался. ☹️Сначала показалось: «ну вот, опять баг браузера». Но если копнуть глубже, окажется, что никакой мистики: всё упирается в одно правило CSS.Что же случилось?height: 100% — это 100% от высоты родителя. И здесь есть ключевой момент: процентная высота работает только если у родителя есть определённая высота — то есть та, которую можно вычислить без учёта содержимого.А что у нас? Auto-строка в grid как раз получает свою высоту по содержимому во время layout, поэтому её высота заранее неизвестна. В итоге получаем цикл:
Катерина | Про Frontend
20 Feb, 16:15
Разбираемся с Proxy в JavaScript 👨🏫Proxy — посредник между кодом и объектом. Он перехватывает операции (чтение, запись, вызов, перечисление) и даёт тебе шанс изменить реакцию на эти действия — через набор обработчиков (так называемых ловушек)const p = new Proxy(target, handler);Как же это работает?1️⃣ Создаёте реальный объект target; 2️⃣ Пишете handler — объект с функциями-перехватчиками (get, set, apply и т.д.); 3️⃣ new Proxy(target, handler) возвращает прокси: при любой операции сначала вызывается соответствующая ловушка, и она решает — выполнить стандартное действие (через Reflect) или изменить его;Ключевые моменты:⏺️ get — перехватывает чтение свойства; ⏺️ set — перехватывае
Катерина | Про Frontend
17 Feb, 16:32
Compression Streams API — нативный gzip/deflate прямо в браузере 🤔Недавно снова вспомнила про Compression Streams API — и это тот случай, когда платформа уже умеет то, ради чего раньше тянули библиотеку. 🤭Это встроенное потоковое API для сжатия и распаковки данных в форматах gzip и deflate. Работает поверх Streams, то есть данные обрабатываются по частям, без загрузки всего в память.Если коротко: теперь можно сжимать и распаковывать данные прямо в клиенте — без сторонних зависимостей.🧩 Что важно запомнить?✔️ Форматы: gzip, deflate; ✔️ Классы: CompressionStream и DecompressionStream; ✔️ Работает поверх Streams — данные идут по частям, без загрузки всего в память;
Катерина | Про Frontend
9 Feb, 14:23edited
Почему бизнес-логику не стоит писать в UI-компонентах 🧐Часто вижу один и тот же паттерн: небольшой компонент, пара условий — и через несколько фич он превращается в монстра, который и отображает, и решает, и общается с API, и ещё немного «магии» делает. 🤯 В итоге вместо чистого UI у нас — куча скрытой логики, которую потом тяжело поддерживать.🧩 Как же так получается?Сначала всё выглядит логично: дедлайн, фича маленькая — проще вставить обработку прямо в компонент. Потом «потом вынесем» не наступает, и компонент растёт:➖ вызывает API и трансформирует ответы; ➖решает, какие шаги процесса выполнять; ➖содержит ветвления бизнес-правил; ➖становится
Катерина | Про Frontend
6 Feb, 17:23
Как неочевидные импорты превращают проект в клубок зависимостей 😨На бумаге — простое правило: модуль импортирует только то, что ему положено. На практике — его иногда нарушают. И последствия оказываются внезапными и дорогими.Пару раз в жизни я меняла локальный метод в сервисе, будучи уверена, что трогаю только свой модуль. Но в проде падала функциональность в совершенно другой части продукта. 😅 Причина оказалась одна: неочевидный прямой импорт, который связал, казалось бы, независимые куски архитектуры.Вывод: правило «не импортировать всё подряд» — не архитектурная прихоть. Это практический способ держать систему предсказуемой, управляемой и масштабируемой.Эта пара реальных инцидентов объясняет, почему правило «не импортировать всё подряд» — не абстрактная архитектурная прихоть, а практический способ удерживать
Катерина | Про Frontend
2 Feb, 17:45
«Хочу стиль для p в header, но не хочу повышать специфичность» 😎Иногда самая тривиальная задача — задать стиль для p внутри header — перерастает в бесконечную гонку селекторов. Вы пишете header p { … }, кто-то добавляет .text { … }, вы усложняете селекторы, и проект медленно погружается в «адские» веса CSS. 😞 К счастью, есть аккуратный и очень полезный приём — использовать :where()🧩 Что делает :where()::where() — это CSS-псевдокласс, который принимает список селекторов и всегда имеет нулевую специфичность, независимо от того, что внутри.💡 Это значит: даже если вы положите внутрь #id .class element, итоговый «вес» всё равно ноль — для всей конструкции :where().🔍 Небольшое напоминание про специфичность:Специфич
Катерина | Про Frontend
29 Jan, 16:46edited
Связность и сцепленность: как написать код, который не боишься менять 🧩Представьте проект как дом. Комнаты — это модули и компоненты. В хорошем доме каждая комната имеет своё назначение: кухня для готовки, спальня для сна, ванная для гигиены. Если в одной комнате стоит плита, кровать и стиральная машина, жить неудобно — это низкая связность: элементы внутри модуля занимаются разными вещами. 😏Двери и коридоры — это интерфейсы и API между модулями. Хорошие двери простые и предсказуемые: можно менять содержимое одной комнаты, не затрагивая остальные. Плохие — это отсутствие нормальных дверей, когда приходится ходить «через стену»: любое изменение тянет за собой цепочку правок. Это и есть высокая сцепленность.Идеальный дом — чёткие комнаты и аккуратные двери. В коде это означает: модуль делает одну задачу и как можно


Катерина | Про Frontend
27 Jan, 17:35
Разбираемся с Feature-based архитектурой 🤩Feature-based архитектура организует код по бизнес-фичам, а не по техническим слоям, благодаря чему изменения локализуются, команды работают автономнее, а кодовая база остаётся понятной по мере роста продукта.Feature-based архитектура строится вокруг идеи локализации контекста: каждая фича оформляется как самостоятельный модуль, внутри которого находится всё необходимое для её работы — UI, состояние, бизнес-логика, взаимодействие с API и тесты. За счёт этого разработчику не нужно переходить между десятками папок, чтобы внести изменение, потому что весь связанный код лежит в одном месте и читается как единое целое. 👍Такой подход особенно хорошо масштабируется вместе с командой. Когда фичи изолированы, несколько разработчиков или команд могут параллельно работать над разными
Катерина | Про Frontend
21 Jan, 15:25
Разбираемся с CSR (Client-Side Rendering) 👨🏫Client-Side Rendering (CSR) — это подход к рендерингу, при котором сервер отдаёт минимальный HTML-каркас, а весь интерфейс и основная логика формируются уже в браузере пользователя с помощью JavaScript. Браузер загружает скрипты, выполняет код и строит DOM на клиенте.Главное преимущество CSR — интерактивность после инициализации. Интерфейс начинает работать плавно и отзывчиво: легко реализуются сложные виджеты, динамическая персонализация и переходы без перезагрузки страницы. Однако за эту гибкость приходится платить — основная нагрузка по построению интерфейса ложится на устройство пользователя 😐Пока браузер скачивает, парсит и выполняет JavaScript, страница может либо отображаться частично, либо оставаться «белой». Даже если UI уже виден, он часто остаётся слабо
Катерина | Про Frontend
19 Jan, 15:21edited
INP: как измеряется отзывчивость страницы 🤨Иногда сайт загружается быстро, контент появляется почти сразу, но пользоваться им всё равно не очень приятно. Клик срабатывает с задержкой, поле ввода реагирует не сразу, интерфейс как будто «думает». Формально всё загрузилось, но ощущение отзывчивости — так себе. 😥Именно такие ситуации описывает INP (Interaction to Next Paint).INP — это метрика, которая показывает, насколько быстро интерфейс реагирует на действия пользователя. Она измеряет задержку между пользовательским действием (клик, тап, ввод) и моментом, когда браузер завершает рендеринг следующего кадра, который отражает результат этого действия. Проще говоря, сколько времени проходит от действия до визуального отклика.Важно понимать, что INP не оценивает одно конкретное взаимодействие, а берёт 75-й перцентиль
Катерина | Про Frontend
14 Jan, 14:36
Как сделать «скрытый, но находимый» контент? 🔍Представьте: у вас длинная страница с FAQ, аккордеонами и сворачиваемыми разделами. Пользователь нажимает Ctrl/Cmd+F, вводит слово — и... браузер ничего не показывает, потому что нужный текст спрятан в свернутом аккордеоне. Раздражает? 😔Для таких случаев есть hidden="until-found" — атрибут, который позволяет визуально скрывать контент, но оставлять его доступным для поиска на странице. Если браузер находит совпадение, он автоматически раскрывает нужный блок и даёт возможность синхронизировать интерфейс через событие beforematch.По сути, это прогрессивное улучшение:✔️ браузер поддерживает фичу → поиск работает «магически»; ✔️ не поддерживает → интерфейс остаётся полностью рабочим.Главный плюс подхода
Катерина | Про Frontend
30 Dec 2025, 15:00
Сейчас все подводят итоги, и я долго думала — писать ли тоже. Чем честнее смотришь на год, тем легче принять: он был непростым для канала. Активность немного просела, многие планы отложились, а фокус всё чаще уходил в личные дела. Иногда просто не хватало времени и сил проявляться так, как хотелось — и это тоже часть истории, хотя принять это было непросто. 😒Вместе с тем год подарил много хорошего: были разобраны интересные темы, снято несколько видео, а также получен важный опыт. 👏Были публикации, которые действительно зацепили вас — и это согревает душу. Даже ошибки и паузы оказались ценными: они напомнили, что главное — сохранять интерес и возвращаться к делу снова и снова. ☺️Огромное спасибо каждому, кто был рядом — читал, комментировал, делился мыслями или просто наблюдал.
Катерина | Про Frontend
27 Dec 2025, 10:30
Распределение условных типов и infer в TypeScript 🤩В TypeScript условные типы по умолчанию распространяются по объединениям (A | B). Это часто полезно, но иногда приводит к неожиданным результатам. Простое и надёжное решение — спрятать параметр в кортеж: [T] extends [X] ? ...🧩 Проблема:Условный тип вида T extends X ? A : B при подстановке T = A | B автоматически разбивается и проверяется для каждого члена объединения отдельно. Такой механизм называется distributive conditional types.type IsString<T> = T extends string ? "yes" : "no"; type R = IsString<string | number>; // "yes" | "no"Ожидание «всё или ничего» (весь тип — строка?) нарушается: вместо одного ответа получаем объединение ответов для частей. 😥🧩 Решение:Чтобы проверить весь тип
Катерина | Про Frontend
25 Dec 2025, 17:04
Обработка комбинаций клавиш 🧑💻Комбинация клавиш используют для обычных вещей: сохранить данные, перейти между экранами, ускорить работу. В JavaScript это реализуется довольно просто, если понимать, как работают события клавиатуры.Немного теории✔️ Комбинация клавиш — это одно событие keydown, внутри которого мы проверяем: ⏺️ какую клавишу нажали; ⏺️ зажаты ли модификаторы (Ctrl, Shift, Alt, Meta); ✔️ В браузере нет отдельного события “Ctrl+S” — всё делается через условия.Ключевые свойства события✔️ event.key — символ или имя клавиши ("a", "Enter"); ✔️ event.code — физическая клавиша ("KeyA", "Enter"); ✔️ event.ctrlKe
Катерина | Про Frontend
23 Dec 2025, 17:12
firstValueFrom vs lastValueFrom 🤨В RxJS мы часто работаем с Observables — потоками данных. Иногда нужно получить одно значение из Observable как Promise, чтобы использовать async/await. Для этого есть firstValueFrom и lastValueFrom.😉Немного теории:✔️ firstValueFrom(obs$) — возвращает Promise, который резолвится при первом эмите и автоматически отписывается;✔️ lastValueFrom(obs$) — возвращает Promise, который резолвится только после завершения Observable и содержит последний эмит до завершения.👀 Что важно учитывать?1️⃣ Если поток завершился без эмитов, оба метода reject’ят промис. Чтобы этого избежать, можно передать defaultValue:await firstValueFrom(obs$, { defaultValue:
Катерина | Про Frontend
20 Dec 2025, 10:55
Когда нужен приоритет загрузки 🤔Ленивая загрузка (loading="lazy") удобна: экономит трафик и ускоряет загрузку страницы за счёт отложенной загрузки картинок, которые пока не видны пользователю.Однако если вы не укажете приоритет для критичных картинок, браузер сам примет решение о порядке загрузки — а его алгоритмы могут не совпасть с вашими целями. ☹️ В результате изображение или шапка могут загрузиться позже, чем нужно: это ухудшит LCP и создаст ощущение «медленной» страницы; при отсутствии заданных размеров это ещё и может привести к CLS.🧩 Что делать?✔️ Для некритичных изображений — смело ставьте loading="lazy". Это экономит трафик и не вредит UX;✔️ Для критичных изображений на первом экране — НЕ полагайтесь
Катерина | Про Frontend
17 Dec 2025, 14:30
Cumulative Layout Shift: почему страница «прыгает» и как это остановить 🤓Cumulative Layout Shift (CLS) — это метрика, которая показывает, насколько часто и насколько сильно элементы страницы неожиданно смещаются после первого рендера. Браузер для каждого такого сдвига оценивает, какая часть экрана была затронута и как далеко элементы уехали, а затем суммирует эти значения. В итоге CLS отражает не скорость загрузки, а стабильность интерфейса во времени.📚 Откуда берётся CLSПочти всегда причина одна и та же — неопределённость размеров. Если в момент первого расчёта layout браузер не знает, сколько места займёт элемент, он не резервирует пространство. Когда элемент появляется или меняет свои размеры, браузеру приходится перестраивать макет, и пользователь видит «прыжок».На практике чаще всего виноваты изображения,




Катерина | Про Frontend
14 Dec 2025, 16:45
Как проверить поведение, если конкретный запрос падает? 🥲Когда мы тестируем — часто включаем в браузере режим «нет сети». Это полезно, но не всегда реалистично: в жизни обычно падает не всё подключение, а отдельный запрос к API. Поэтому, иногда нужно проверить, как приложение с этим справится. 😁Здесь на помощь приходят DevTools. В Chrome можно не просто отключить сеть, а заблокировать конкретный запрос: ✔️ Открываем DevTools → вкладка Network; ✔️ Находим нужный запрос, щёлкаем правой кнопкой → Block request URL / Заблокировать URL запроса; ✔️ Перезагружаем страницу / повторяем действие и наблюдаем, как приложение реагирует на падение именно этого запроса.Это позволяет протестировать:
Катерина | Про Frontend
11 Dec 2025, 18:26
На днях увидела на одном сайте интересный эффект — интерактивную «лупу», через которую видно нижний фон сквозь верхний слой. Давайте реализовывать! 👩💻Первое решение, которое приходит в голову — использовать mask-image. Но тут есть нюанс. 🤔Дело в том, что маска (mask-image) управляет прозрачностью всего элемента, а не отдельных слоёв фоновых изображений. То есть, если вы применяете маску к элементу с несколькими background’ами, прозрачная зона не покажет нижний фон того же блока, а только то, что находится за элементом — например, фон страницы. 😥Правильное решение вытекает из этой логики: если вы хотите, чтобы прозрачная область показывала нижний фон, слои нужно разделять по DOM. То есть создаём два уровня: ⏺️ родительский блок с нижним фоном;
Катерина | Про Frontend
8 Dec 2025, 16:50
Компоненты-монолиты — как их распознать и что с этим делать 🧐Формальное разделение системы на компоненты ещё не гарантирует модульности.Компонент-монолит — это «папка», внутри которой смешаны UI, бизнес-логика и доступ к данным, и любое небольшое изменение требует погружения в большой объём кода. Такая структура создаёт иллюзию независимости: команды думают, что работают автономно, но правки в одной части часто ломают другие, потому что границы слишком проницаемы.Как быстро понять, что перед вами компонент-монолит? ✔️ Невозможно объяснить ответственность компонента одной фразой; ✔️ Для добавления фичи нужно читать тысячи строк и разбираться в десятке вспомогательных модулей; ✔️ Локальное изменение функции вызывает регрессии в соседних модулях.

Related Channels
Other channels in the same section of the catalogue.
