Frontend Interview - собеседования по Javascript / Html / Css
10.2K subscribers
2.09K photos
117 videos
320 files
494 links
Канал для подготовки к собеседованиям по фронтенду

Админ, сотрудничество, реклама: @seniorFrontPromo, @maria_seniorfront

Купить рекламу: https://telega.in/c/frontendinterview

Канал в реестре РКН:
https://rknn.link/su
Download Telegram
System Design - этап собеседования, на котором часто сыпятся даже сильные разработчики. Не потому, что они плохо пишут код, а потому что никогда не проектировали системы целиком и не знают, как уложить это в 40 минут собеса.

В одном из гайдов собрана база, без которой сложно пройти System Design интервью: что именно проверяют на таких собеседованиях, почему плохой архитектурный дизайн может уронить продукт, какие требования собирают перед проектированием и как инженеры подходят к построению систем уровня Amazon.

В первой части рассказывается:
- что такое системный дизайн и кому он нужен
- как в целом проектируются системы: монолиты, микросервисы, нагрузка, масштабирование, проектирование API
- какие темы нужно понимать для продвинутого уровня: распределённые транзакции, 2PC, 3PC, TCC и другие.

Во второй части планируют разобрать System Design во фронтенде, но для подготовки к собеседованию, по сути, достаточно уже первой.

Ссылка на видео: https://youtu.be/PgC7LzIG29k
🧭 Разбираем React вместе с Podlodka React Crew

Современные React-приложения становятся всё сложнее. Разработчики регулярно сталкиваются с проблемами производительности, утечками памяти и архитектурными вызовами.

Базового понимания фреймворка становится недостаточно для результативной работы.

💡Эксперты Podlodka React Crew решили разобраться с этой проблемой на онлайн-конференции под названием «Продвинутый React».

С 23 по 27 марта ее участники:

⚙️ узнают, как устроен рендер и внутренние механизмы в современном React

🧠 познакомятся с архитектурой приложений, где применяются React Server Components

📊 научатся профилировать React-приложения и выявлять медленные рендеры, memory leak

🛠️познакомятся с дополнительными инструментами, которые помогут упростить отладку и выявить сложные проблемы

Формат — удобный и ламповый: пять дней, живые Zoom-сессии утром и вечером, закрытое профессиональное сообщество в Telegram и общение со спикерами.

Если хотите углубить свои знания про React в компании крутых экспертов, присоединяйтесь к Podlodka React Crew👇

🎟Забрать early-bird билет: https://podlodka.io/reactcrew
👍2❤1
CSS-анимация на примере аналоговых часов

Классический разбор того, как знание спецификации заменяет скрипты. Автор воссоздал реалистичные часы, используя только возможности CSS3.

Адаптивность через em: Один font-size родителя масштабирует все часы пропорционально (включая тени и засечки).

Реалистичный хром: Многослойные box-shadow (внешние и inset) создают объем и металлический блеск без картинок.

Вложенные transform: rotate(): Умная расстановка минутных делений по кругу с помощью всего нескольких тегов <i>.

Тиканье стрелки: Анимация с animation-timing-function: steps(60) вместо плавного вращения.

Понимание вложенных трансформаций и оптимизации рендеринга помогает делать производительные UI-анимации, не нагружая Main Thread.

📖 Детали реализации на Хабре: https://habr.com/ru/articles/171015/

👉 @frontendInterview
❤1👍1👎1
Кастомизация списков: от ::marker до @counter-style

Современный CSS позволяет гибко управлять списками, не перегружая HTML лишними элементами.
Разбираем три основных подхода.

✅ Псевдоэлемент ::marker
Самый быстрый способ изменить стандартную точку или цифру.

Что можно: менять color, font-size и font-family.

Ограничение: нельзя задать фон или произвольное позиционирование.

Нюанс: маркер выравнивается по базовой линии текста. При большом font-size он сместится вверх относительно строки.

✅ Директива @counter-style
Инструмент для создания собственных систем нумерации (Baseline 2023).

system: cyclic — позволяет зациклить любые символы или эмодзи (например, фазы луны 🌑🌓🌕).

system: extends — модифицирует стандартные стили (например, заменяет точку после цифры на скобку: 1) вместо 1.).

✅ Полный контроль через ::before
Когда возможностей ::marker не хватает для сложного дизайна.

Доступность: при list-style: none обязательно добавляйте role="list" в HTML, иначе Safari перестанет озвучивать список корректно.

Механика: используйте функции counter(list-item) для простых списков или counters(list-item, ".") для вложенной нумерации (1.1, 1.2).

Верстка: через position: absolute маркеру можно задать любые размеры, фон и точное положение относительно текста.

Источник: https://piccalil.li/blog/an-in-depth-guide-to-customising-lists-with-css/

👉 @frontendInterview
Please open Telegram to view this post
VIEW IN TELEGRAM
«Летающий» фокус на View Transitions API

Анимация перемещения фокуса между элементами (focus ring) делает интерфейс «живее» и помогает пользователю не терять активный элемент при навигации с клавиатуры. Раньше для этого высчитывали координаты через getBoundingClientRect, теперь всё делает браузер.

Вместо анимации самой кнопки мы анимируем только рамку фокуса. Для этого каждому интерактивному элементу добавляется вспомогательный <span>.

1️⃣ CSS: Рамка фокуса получает уникальное view-transition-name только в тот момент, когда родительский элемент находится в состоянии :focus-visible.

2️⃣ JS: Переключаем фокус программно внутри startViewTransition. Браузер увидит, что элемент с именем focus-ring переместился и изменил размер, и сам создаст плавный переход.

👉 @frontendInterview
👍2❤1
TanStack Form: новый стандарт для работы с формами в JS

Все знают TanStack Query (бывший React Query), который перевернул работу с запросами. Теперь команда разработчиков выпустила TanStack Form - библиотеку для управления формами, которая решает старые боли фронтендеров.

Главные фишки:

🟢Агностицизм: работает не только с React, но и с Vue, Angular, Solid, Svelte и даже Vanilla JS.

🟢100% Type-Safe: глубокая интеграция с TypeScript. Ошибки в названиях полей или типах данных подсвечиваются прямо при написании кода.

🟢Валидация без привязки: можно использовать любую привычную библиотеку (Zod, Valibot, Yup) или писать кастомные функции.

🟢Производительность: библиотека обновляет состояние точечно, поэтому даже огромные формы с сотнями полей не будут тормозить интерфейс.

Если вам надоело мучиться с настройкой сложных форм, TanStack Form - отличный кандидат на замену старым инструментам.

👉 @frontendInterview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Как убрать «висячие» строки во Flexbox: flex-wrap: balance и flex-line-count

Каждый фронтендер сталкивался с проблемой: настраиваешь flex-wrap: wrap, но при сужении экрана на последнюю строку перескакивает ровно один элемент. Раньше это костылили через медиазапросы. Теперь в Chrome есть нативные свойства flex-wrap: balance и flex-line-count.

Автобалансировка: flex-wrap: balance
Свойство распределяет элементы по строкам равномерно, убирая одиноких «сирот» в конце:

CSS
.channels {
display: flex;
flex-wrap: balance;
justify-content: center;
gap: 1rem;
}
Никаких сложных вычислений или JS — браузер всё делает сам.

Контроль строк через flex-line-count
Оно задает минимальное количество строк. Даже если места хватает для одного ряда, элементы принудительно распределятся по заданному числу:

CSS
.nav-list {
display: flex;
flex-wrap: balance;
flex-line-count: 2; /* Минимум 2 строки */
gap: 0.5rem;
}

Подробнее в статье👇

👉 @frontendInterview
👍2
🎚 «Больше или равно» в CSS без единого if

Новая CSS-функция progress(значение, от, до) показывает, где значение лежит в диапазоне: дробь от 0 до 1. Всё, что за границами, по умолчанию обрезается до 0 или 1.

Отсюда трюк. В диапазоне от 0 до порога ровно 1 выйдет, только когда значение достигло порога. Это готовый флаг.

Например, бейджи за фильмы: пороги 3, 6 и 9 в --badgeLevel, число фильмов в --movieCount:

.badge {
--isLevelUnlocked: progress(var(--movieCount), 0, var(--badgeLevel));
}


При 2 фильмах из 6 получится 0.33, при 6 или 10 будет 1. Container style query (проверка значения переменной у родителя) показывает бейдж при style(--isLevelUnlocked: 1). Перебирать уровни в JS не нужно.

Учтите, что флаг регистрируют через @property с типом <number>, чтобы style query могла проверить его значение.

Приём годится для любого сравнения с порогом, не только для бейджей.

👉 @seniorFront
👎2❤1
📏 Высота блока в строках, а не в пикселях

В CSS есть единица lh: 1lh равен вычисленному line-height, то есть высоте одной строки текста. Она давно существует, но о её применении рассказывают редко.

Пример: список надо обрезать по пяти строкам и плавно растворить низ. С max-height: 120px стоит увеличить шрифт, и всё ломается: строки растут, а пиксели нет. С lh размер считается в строках:

.list {
max-height: 5lh;
mask-image: linear-gradient(
to bottom,
#000,
#000 calc(100% - 1lh),
transparent 100%
);
}


Теперь при любом шрифте видно пять строк, а последняя плавно тает.

Оговорка: lh берётся от line-height самого элемента. Чтобы расчёт на родителе совпал со строками детей, задайте шрифт на родителе, а детям оставьте наследование.

В статье ещё отступы между абзацами, «тетрадные» линейки, картинки с float точно по строкам и иконки по размеру текста.

👉 @seniorFront
👍1
🚀 Два атрибута у картинки, и страница перестаёт прыгать

Пока картинка грузится, тег img занимает на странице нулевой размер. Когда файл приходит, блок раздвигается, и текст под ним резко уезжает вниз. Браузер заново пересчитывает раскладку, а читатель теряет строку.

Лечится это атрибутами width и height у img, например width=800 height=600. Браузер ещё до загрузки файла знает пропорции и сразу оставляет под картинку место. В замере автора это сэкономило около 12% процессорного времени.

Одна тонкость: в CSS картинке нужно задать width: 100% и height: auto. Тогда ширина подстроится под контейнер, а высота посчитается по пропорциям. Без height: auto изображения растянутся.

А ещё в статье объяснено, почему padding-bottom и aspect-ratio автор считает худшими вариантами и как самому замерить разницу в профайлере.

👉 @seniorFront
👍3
🌈 Свечение внутри элемента, но из любого фона

Подсветить элемент изнутри проще всего через box-shadow с inset. Но такое свечение одноцветное. А если хочется радужный conic-gradient() или картинку?

Решение из статьи: накрыть элемент псевдоэлементом ::after с нужным фоном и маской оставить видимыми только края. Середина прозрачна, и сам элемент под ней виден.

Маска для левого и правого краёв (black в маске значит «видно»):
--inset: 30px;
mask-image: linear-gradient(
to right,
black 0%,
transparent var(--inset),
transparent calc(100% - var(--inset)),
black 100%
);

Вторая такая же маска с to bottom берёт верх и низ, а mask-composite: add объединяет обе полосы в рамку.

Накладка стоит на position: absolute и inset: 0, поэтому самому элементу нужен position: relative.

В статье есть демо, где оба вида свечения вспыхивают на случайных элементах.

👉 @seniorFront
❤2
🔍 Убрал повтор в скринридере и сломал кнопку

Джейк Арчибальд делал кнопку-иконку «жирный» с подсказкой «Bold (⌘B)» на popover="hint". На кнопке стояли aria-label="Bold" и aria-describedby со ссылкой на подсказку.

VoiceOver читал «Bold. Bold. Command B». Чтобы убрать повтор, Джейк удалил aria-label. И кнопка осталась без доступного имени, то есть без названия для скринридера. aria-describedby добавляет только описание, имя он не заменяет.

JAWS в итоге собрал текст из соседних элементов и объявил кнопку сразу жирной и курсивной.

Чинится заменой одного атрибута: aria-labelledby вместо aria-describedby. Он тоже ссылается на подсказку по id, но берёт из неё именно имя. Теперь VoiceOver говорит «Bold. Command B. Button».

Сам Джейк советует проверять в нескольких скринридерах: один, как и один браузер, полной картины не даёт.

В статье есть и вариант, где имя и сочетание клавиш разведены по разным span.

👉 @seniorFront
🔥1
🎨 Текст, который сам подбирает цвет под фон

Если фон карточки задаётся фирменным цветом и может быть любым, подбирать к нему цвет текста вручную неудобно.

CSS-функция contrast-color() берёт цвет и возвращает black или white, смотря что контрастнее:

.card {
--bg: var(--brand-color);
background: var(--bg);
color: contrast-color(var(--bg));
}


Можно пойти дальше. Сохраняем результат в кастомное свойство, зарегистрированное через @property, и проверяем его запросом @container style(). Вышло white, значит фон тёмный, и текст красим в светлый оттенок цвета карточки. Вышло black, берём глубокий тон того же оттенка.

Если цвета палитры задать вручную, а не выводить из фона, на результат contrast-color() уже не опереться: такие пары автор советует тщательно тестировать.

В статье этот приём вместе с light-dark() собран в целую систему светлой и тёмной темы.

👉 @seniorFront
🧮 Поле ввода, в которое можно вписать формулу

Часто число для формы сначала надо посчитать. С обычным <input> приходится бегать в калькулятор и обратно. А позже в поле виден только итог, и непонятно, откуда он взялся.

Bramus сделал для этого веб-компонент <calc-input>. Пишешь (2 + 3) * 4, уходишь из поля, и там появляется 20. Возвращаешь фокус, и снова видна формула, её можно проверить или поправить.

Считает компонент своим парсером, без eval(). Он понимает обычные операторы, скобки и функции вроде sqrt, round, min, max. Внутри лежат обычные <input>, поэтому отправка формы и валидация работают как есть. С недописанной формулой вроде 2 + форма не отправится.

Учтите, что по умолчанию в поле с вашим name уходит сама формула «2 + 3», а не 5. Чтобы сервер получил число, нужен атрибут submit="result".

Как устроены три поля внутри и почему стили на самом теге сразу применяются к ним, Bramus показывает в статье.

👉 @seniorFront
❤1
✨ CSS может заметить, что элементы вот-вот столкнутся

Сбоку от секции с карточками висит декоративный элемент, и его размер и положение меняются вместе с экраном. Медиазапросом момент наезда не поймать, а спрятать декор нужно, как только зазор станет меньше 20px.

Между декором и секцией через anchor positioning растягивается невидимый элемент .measure. Внутри у него псевдоэлемент шириной 20px и overflow-x: auto. Когда зазор меньше 20px, .measure переполняется.

Само переполнение запускает scroll-driven анимацию, прокручивать ничего не нужно. Анимация лишь ставит --touching: 1, а style container query прячет декор:

.decor {
@container style(--touching: 1) {
opacity: 0;
}
}


Работает только в браузерах, где есть и scroll-driven анимации, и anchor positioning, так что это улучшение поверх обычной вёрстки.

В статье есть интерактивные демо, где можно потянуть границу и поймать момент срабатывания.

👉 @seniorFront
❤1
✨ Скроллбар, который следит за прокруткой без JavaScript

Свой скроллбар обычно рисуют так: нативный прячут, а размер и положение ползунка считают в JS на каждое событие scroll. Это дорого: scroll летит много раз в секунду, а чтение scrollHeight может вызвать reflow.

Разработчик библиотеки Taiga UI отдал эту работу CSS через scroll-driven animations. Их прогресс зависит не от времени, а от прокрутки контейнера.

Хитрее всего с высотой ползунка. Анимации его краёв растягивают на высоту контейнера (100cqb) за конец прокрутки, и в крайней точке они замирают ровно там, где нужно:

.bar {
animation-range: 0% calc(100% + 100cqb), calc(0% - 100cqb) 100%;
animation-fill-mode: both;
}


JS остаётся только для перетаскивания ползунка мышью.

Учтите, что на момент статьи Firefox умел это лишь в Nightly, поэтому в Taiga UI новая схема включается только там, где браузер её поддерживает.

Отдельно красиво решено, как прибить ползунки к краю контейнера: через anchor positioning.

👉 @seniorFront
🧩 Как сделать, чтобы фоновый узор не обрезался снизу

У секции повторяющийся фоновый узор, плитка 52×44px. Высота блока зависит от текста, поэтому нижний ряд плиток часто обрезается на середине.

Можно поставить background-repeat: round. Но тогда браузер сжимает или растягивает саму плитку, чтобы она уместилась целиком.

Решение аккуратнее: взять автоматическую высоту через calc-size() и округлить её функцией round() до кратного высоте плитки. Высота плитки лежит в переменной --tile-height.

.section {
height: calc-size(auto, round(up, size, var(--tile-height)));
}


Выглядит как фиксированная высота, но работает скорее как min-height. Блок по-прежнему подстраивается под контент, просто его высота всегда кратна высоте плитки, и узор не режется.

Оговорка: на момент написания статьи это работает только в Chrome.

В оригинале есть живые демо, разбор округления вверх и вниз и то, как подогнать под узор ещё и padding.

👉 @seniorFront
❤1
✨ Рамка, которая рисует себя сама, на чистом CSS

Свойство border-image позволяет сделать рамкой элемента градиент вместо обычной линии. Но анимировать градиент напрямую не выйдет: браузер не умеет плавно двигать проценты внутри него.

Это обходится так: регистрируем свою переменную через @property и указываем её тип. Такую переменную браузер уже плавно меняет:

@property --p {
syntax: "<percentage>";
initial-value: 0%;
inherits: false;
}


Дальше она встаёт в градиент рамки: linear-gradient(-45deg, red var(--p), transparent 0%). Пока --p равна 0%, рамка прозрачная. При наведении --p становится 100%, красный заполняет рамку, и кажется, что её рисуют на глазах.

Есть подвох: border-image не изгибается по форме элемента, так что скруглённые углы он не повторит.

В статье тот же приём крутят дальше: conic-gradient, анимация border-image-slice и ещё куча вариаций.

👍 - если было полезно

👉 @frontendInterview
❤1👍1
🚀 Предзагрузка, которая грузит не те данные

В TanStack Router у маршрута есть loader: он запускает запрос ещё до рендера, а компонент забирает готовые данные из кеша TanStack Query. Но параметры запроса тогда описаны дважды, и если они разойдутся, ошибки никто не покажет.

Пример из статьи. В дашборд добавили ?asOf=дата, но только в компоненте. По ссылке loader грузит данные «на сегодня», а компонент потом запрашивает снимок заново. Лишний запрос и лишнее ожидание.

Автор предлагает класть queryOptions в контекст маршрута. Их создаёт одна функция context, а loader и компонент через useRouteContext() берут один и тот же объект. Разойтись им просто негде.

Учтите, что функция context на момент статьи была новой и не описанной в документации.

В статье ещё о том, как контекст наследуют дочерние маршруты и почему лишних ререндеров не будет.

👍 - если было полезно

👉 @frontendInterview
🧩 Один инпут в Angular для строки, функции, шаблона или компонента

Когда компонент принимает кастомный контент, приходится заранее решать: хватит строки или нужен TemplateRef? Потом тип проверяют через @if и ветвят шаблон.

Библиотека Polymorpheus от команды Taiga UI убирает этот выбор. Директива *polymorpheusOutlet одинаково отрисует любой из четырёх вариантов в переданном контексте:

<ng-container *polymorpheusOutlet="content as primitive; context: { $implicit: user }">
{{ primitive }}
</ng-container>


Строка или результат функции попадает в primitive.

Пример с тултипом: обычно в нём просто текст. Когда понадобится ссылка или кнопка, пользователь передаст шаблон, и API тултипа переделывать не придётся.

Оговорка: функцию от конструктора компонента не отличить, поэтому компонент оборачивают в PolymorpheusComponent.

А в статье ещё и трюк, как сделать иконку, которую можно задать просто по имени или целым шаблоном.

👍 - если было полезно

👉 @frontendInterview
❤2