Продвинутый CSS для технического собеседования

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

1. Продвинутые селекторы и специфичность

Продвинутые селекторы и специфичность

Почему два правила CSS, написанных для одного элемента, ведут себя так, будто одно из них не существует? Ответ — в специфичности (specificity), и именно её непонимание становится причиной половины багов в стилях на реальных проектах. На собеседовании этот вопрос задают, чтобы проверить: вы пишете CSS осознанно или методом «добавлю !important и заработает».

Как работает специфичность

Каждый селектор в CSS получает «вес», записанный как кортеж из четырёх чисел: (inline, id, class, element). Браузер сравнивает эти кортежи слева направо — лексикографически, как словарь.

| Селектор | Вес | Пример | |---|---|---| | Инлайн-стиль | (1, 0, 0, 0) | style="color: red" | | ID-селектор | (0, 1, 0, 0) | #header | | Класс / псевдокласс / атрибут | (0, 0, 1, 0) | .nav, :hover, [type="text"] | | Элемент / псевдоэлемент | (0, 0, 0, 1) | div, ::before |

Универсальный селектор *, комбинаторы (>, +, ~, пробел) и псевдокласс :where()не добавляют веса. А вот :is() и :not() принимают вес самого тяжёлого аргумента внутри себя.

> Правило с бо́льшим весом побеждает. При равенстве весов побеждает то, что объявлено позже в коде — это называется каскадом.

Комбинаторы: точный язык связей

Комбинаторы — это операторы между селекторами, которые задают топологические отношения между элементами в DOM-дереве.

  • Пробел — потомок на любом уровне: .card p найдёт <p> внутри .card на любой глубине.
  • > — прямой потомок: .card > p найдёт только <p>, являющийся непосредственным ребёнком .card.
  • + — сосед сразу после: h2 + p — первый <p>, следующий непосредственно за <h2>.
  • ~ — общий последующий сосед: h2 ~ p — все <p>, идущие после <h2> в одном родителе.
  • На собеседовании часто спрашивают: «Чем отличается + от ~?» Короткий ответ: + берёт только первый соседний элемент, ~ — все последующие.

    Псевдоклассы и псевдоэлементы: два разных мира

    Псевдоклассы (:hover, :focus, :nth-child(), :not()) описывают состояние элемента. Они добавляют один блок к весу (0, 0, 1, 0).

    Псевдоэлементы (::before, ::after, ::first-line, ::selection) создают виртуальные элементы в DOM. Они добавляют (0, 0, 0, 1).

    > На практике: если вам нужно стилизовать часть текста внутри элемента или добавить декоративный элемент без HTML — используйте ::before / ::after. Если нужно отреагировать на действие пользователя — псевдокласс.

    Продвинутые селекторы: атрибуты и структурные псевдоклассы

    Атрибутные селекторы — мощный инструмент, особенно при работе с динамическими классами или data-* атрибутами.

    Структурные псевдоклассы позволяют выбирать элементы по их позиции:

  • :first-child / :last-child — первый/последний среди siblings.
  • :nth-child(an+b) — по формуле: 2n — каждый чётный, 2n+1 — нечётный, 3n+2 — каждый третий со смещением.
  • :nth-of-type(an+b) — то же, но считает только элементы одного типа.
  • :not(.disabled) — исключает элементы по селектору.
  • Ловушки специфичности на собеседовании

    Ловушка 1: Накопление классов. Селектор .a.b.c.d имеет вес (0, 0, 4, 0) — четыре класса. Он перебивает #sidebar с весом (0, 1, 0, 0)? Нет: id всегда тяжелее любого количества классов. Но .a.b.c.d перебьёт .nav.active с весом (0, 0, 2, 0).

    Ловушка 2: !important не решает проблему. Когда два правила оба с !important, побеждает то, у которого выше специфичность. А если специфичность одинакова — правило, объявленное позже. Злоупотребление !important создаёт «гонки вооружений», где каждое следующее правило вынуждено тоже использовать !important.

    Ловушка 3: Порядок в CSS-файле. При равной специфичности побеждает последнее правило. Это значит, что порядок подключения стилейheets влияет на результат — и это частый вопрос на интервью.

    Практический совет: держите специфичность низкой и плоской. Используйте классы, избегайте вложенности более двух уровней. Если вы пишете div.container ul.nav li.item a.link — вы делаете что-то не так. Достаточно .nav-link.

    Каскадные слои (@layer)

    Начиная с 2022 года, CSS поддерживает каскадные слои — механизм явного управления приоритетом целых блоков стилей, независимо от специфичности селекторов внутри них.

    Слои, объявленные позже в списке @layer, имеют более высокий приоритет — даже если внутри них селекторы с минимальной специфичностью. Это решает вечную проблему конфликтов между стилями библиотек и пользовательскими стилями: библиотеку помещают в ранний слой, а свои стили — в поздний.

    На собеседовании @layer — это маркер, что кандидат следит за современными стандартами. Но даже без него понимание специфичности на уровне кортежей — базовый навык, без которого невозможно эффективно работать с CSS на серьёзных проектах.

    2. Современные методы верстки: Flexbox и Grid

    Современные методы верстки: Flexbox и Grid

    Зачем знать обе системы раскладки, если одна из них «лучше»? Потому что ни одна не заменяет другую полностью. Flexbox проектировался для одномерных раскладок — строка или колонка. Grid — для двумерных, где нужно контролировать и строки, и столбцы одновременно. На собеседовании вас не спросят «что лучше» — спросят, когда и почему вы выберете каждую из них.

    Flexbox: одномерная раскладка

    Flexbox работает вдоль одной оси — главной (main axis). Вторая ось — поперечная (cross axis). Всё, что делает Flexbox, вращается вокруг управления пространством вдоль этих двух осей.

    Ключевые свойства контейнера:

  • flex-direction — задаёт главную ось: row (по умолчанию), row-reverse, column, column-reverse.
  • justify-content — распределяет дочерние элементы вдоль главной оси: flex-start, flex-end, center, space-between, space-around, space-evenly.
  • align-items — выравнивает элементы по поперечной оси: stretch (по умолчанию), flex-start, flex-end, center, baseline.
  • flex-wrap — по умолчанию элементы сжимаются в одну строку. wrap позволяет переносить их на новую строку.
  • Свойства дочерних элементов:

  • flex-grow — коэффициент роста. Элемент с flex-grow: 2 займёт вдвое больше свободного пространства, чем элемент с flex-grow: 1.
  • flex-shrink — коэффициент сжатия при нехватке места.
  • flex-basis — базовый размер элемента до распределения свободного пространства. По умолчанию auto (берёт из width / content).
  • > Сокращение flex: 1 эквивалентно flex: 1 1 0% — элемент растёт, сжимается и стартует с нулевой базы. Это самый частый паттерн для равномерных колонок.

    Практический паттерн: навигационная панель

    Классический кейс для Flexbox — шапка с логотипом слева, навигацией по центру и кнопкой справа:

    Логотип и кнопка занимают минимальный объём, а навигация — всё оставшееся пространство. Если нужно, чтобы навигация «прижалась» к центру, а не к кнопке, используйте margin-left: auto на кнопке — она улетит вправо, а навигация займёт середину.

    Grid: двумерная раскладка

    Grid позволяет задавать столбцы и строки одновременно. Это принципиально другой уровень контроля — вы описываете сетку, а потом помещаете элементы в конкретные ячейки.

    Функция repeat() упрощает запись повторяющихся треков:

    Ключевое отличие auto-fill от auto-fit: при auto-fill пустые треки сохраняют место, при auto-fit — схлопываются, и оставшиеся элементы растягиваются. На практике auto-fit чаще используется для карточек, которые должны заполнять всю ширину.

    Размещение элементов в Grid

    Элементы можно размещать явно через grid lines:

    Или через именованные области — более читаемый подход:

    > grid-template-areas — это визуальная карта макета прямо в CSS. На собеседовании это демонстрирует, что вы понимаете не только синтаксис, но и архитектурный подход к раскладке.

    Flexbox vs Grid: когда что выбирать

    | Критерий | Flexbox | Grid | |---|---|---| | Ось раскладки | Одномерная (строка ИЛИ колонка) | Двумерная (строки И столбцы) | | Контент определяет размер | Да — элементы «давят» на контейнер | Нет — контейнер задаёт сетку | | Типичный кейс | Навигация, кнопки, выравнивание внутри компонента | Страница целиком, галерея карточек, сложный макет | | Вложенность | Часто требует вложенных контейнеров | Плоская структура, меньше вложенности | | Переупорядочивание | order — только визуальное | grid-area — семантическое размещение |

    На практике лучшие макеты комбинируют оба подхода: Grid для общей структуры страницы, Flexbox для компонентов внутри ячеек.

    Выравнивание: общая система

    Начиная с уровня спецификации Box Alignment, свойства justify- и align- унифицированы между Flexbox и Grid:

  • justify-content / align-content — распределение треков или элементов в контейнере.
  • justify-items / align-items — выравнивание элементов внутри их областей (в Grid работает полноценно, в Flexbox — только align-items).
  • justify-self / align-self — переопределение для отдельного элемента.
  • Свойство place-items — сокращение: place-items: center эквивалентно align-items: center; justify-items: center. Это самый быстрый способ центрировать что угодно:

    Ловушки, которые спрашивают на собеседовании

    Ловушка 1: flex: 1 vs flex: auto. flex: 1 (эквивалент 1 1 0%) заставляет элементы делить пространство поровну, игнорируя их контент. flex: auto (эквивалент 1 1 auto) учитывает размер контента — элементы с длинным текстом займут больше места.

    Ловушка 2: gap в Flexbox. Свойство gap работает в Flexbox начиная с 2021 года. Раньше использовали margin на дочерних элементах, что ломало последний элемент. Сейчас gap — стандарт.

    Ловушка 3: min-width в Flexbox. По умолчанию flex-элементы не сжимаются меньше своего контента. Если текст не переносится — элемент вылезет за контейнер. Решение: min-width: 0 или overflow: hidden на flex-потомке.

    3. CSS переменные и архитектура стилей

    CSS-переменные и архитектура стилей

    Почему на крупных проектах CSS со временем превращается в «кашу», где изменение цвета кнопки ломает футер? Потому что без системы организации стилей каждый разработчик пишет правила локально, дублирует значения и создаёт скрытые зависимости. CSS Custom Properties (переменные) — это инструмент, который превращает хаос в управляемую архитектуру.

    Что такое CSS-переменные

    Custom Properties — это пользовательские свойства, объявляемые через префикс -- и используемые через функцию var(). В отличие от препроцессорных переменных (Sass, Less), CSS-переменные живут в браузере, работают в рантайме и наследуются по DOM-дереву.

    Ключевое отличие от Sass-переменных: CSS-переменные можно переопределить в любом контексте — по медиазапросу, по классу, по состоянию — и браузер пересчитает все зависимые значения мгновенно, без перекомпиляции.

    Наследование и область видимости

    CSS-переменные наследуются от родителя к потомку, как обычные свойства color или font-size. Это значит, что если вы объявили --color-primary на :root, все элементы на странице имеют к нему доступ.

    Переопределение работает по принципу каскада — ближайший контекст побеждает:

    Теперь добавление класса .dark-theme на <body> переключает всю тему — без единого медиазапроса и без JavaScript. Это и есть сила рантайм-переменных.

    Значение по умолчанию: fallback в var()

    Функция var() принимает второй аргумент — значение по умолчанию, которое используется, если переменная не определена:

    Можно вкладывать fallback'и:

    > Это полезно при создании библиотек компонентов: вы определяете переменные с разумными значениями по умолчанию, а проект-потребитель переопределяет только нужные.

    Динамические вычисления с calc()

    Переменные работают внутри calc(), что позволяет строить адаптивные системы без медиазапросов:

    Это модульная типографская шкала — система, где размеры заголовков вычисляются из одного базового значения и коэффициента масштабирования. Изменив --scale с 1.25 на 1.333, вы мгновенно перестроите всю иерархию заголовков.

    Проектирование дизайн-системы на переменных

    На реальных проектах переменные организуют в три уровня:

    Уровень 1 — Примитивы (токены): конкретные значения без семантики.

    Уровень 2 — Семантические токены: привязывают примитивы к смыслу.

    Уровень 3 — Компонентные переменные: scoped к конкретному компоненту.

    Такой подход даёт три точки входа для кастомизации: изменить примитив — перекрасить всё, изменить семантический токен — переназначить роль, изменить компонентную переменную — настроить конкретный элемент.

    Переменные и JavaScript

    CSS-переменные — это мост между CSS и JavaScript. Их можно читать и записывать из JS:

    Это открывает возможности, которые раньше были доступны только через инлайн-стили или переключение классов: динамические темы, пользовательские настройки, анимации на основе данных.

    Частые вопросы на собеседовании

    «Чем CSS-переменные отличаются от Sass-переменных?» Sass-переменные компилируются на этапе сборки — каждое вхождение заменяется статическим значением. CSS-переменные живут в браузере, наследуются, переопределяются в рантайме и реагируют на изменения DOM. Sass-переменные не могут зависеть от класса элемента или медиазапроса в рантайме.

    «Можно ли использовать переменную в медиазапросе?» Нет. @media (max-width: var(--breakpoint)) не работает, потому что медиазапросы вычисляются на уровне viewport, а переменные привязаны к элементам. Решение: либо статические значения в медиазапросах, либо контейнерные запросы (об этом — в следующей статье).

    «Можно ли анимировать CSS-переменные?» Напрямую — нет. transition: --my-var не сработает. Но можно анимировать свойство, которое использует переменную: transition: background 0.3s при изменении --btn-bg сработает, если браузер может интерполировать итоговое значение. Для сложных сценариев используйте @property для регистрации переменной с указанием типа:

    Это одна из самых продвинутых техник, и упоминание @property на собеседовании точно выделит вас среди других кандидатов.

    4. Адаптивность и современные возможности

    Адаптивность и современные возможности CSS

    Почему медиазапросы — это не адаптивность, а лишь её часть? Потому что настоящая адаптивная вёрстка начинается до первого @media — с гибких единиц, fluid-тиграфии и контейнерных запросов. На собеседовании вас проверят не на знание синтаксиса @media, а на умение проектировать интерфейсы, которые работают на экране от 320px до 4K без хрупких брейкпоинтов.

    Гибкие единицы измерения

    Адаптивность начинается с выбора правильных единиц. Пиксели — это абсолютная единица, которая не реагирует на размер viewport. Современная вёрстка использует относительные единицы:

  • rem — относительно размера шрифта корневого элемента (html). 1rem = font-size на :root (по умолчанию 16px). Используйте для отступов, размеров компонентов — всего, что должно масштабироваться при изменении базового шрифта.
  • em — относительно шрифта текущего элемента. Удобен для padding и line-height внутри компонентов, где размеры должны пропорционально меняться с font-size.
  • vw / vh — процент от размера viewport. 1vw = 1% ширины окна. dvw / dvh — динамические варианты, учитывающие мобильные панели браузера (адресная строка Safari).
  • svh / lvh — маленькая и большая высота viewport на мобильных. svh — с развёрнутой адресной строкой, lvh — со свёрнутой. dvh — динамически переключается между ними.
  • Fluid-типография с clamp()

    Функция clamp(min, preferred, max) задаёт значение, которое плавно меняется между минимумом и максимумом через предпочитаемое выражение. Это ключевой инструмент для fluid-типографии — размера шрифта, который плавно адаптируется к ширине экрана без брейкпоинтов.

    Как это работает: 1.2rem + 2.5vw — линейная функция от ширины viewport. На узком экране результат меньше 1.75rem — срабатывает минимум. На широком — больше 3.5rem — срабатывает максимум. Между ними — плавное масштабирование.

    > На собеседовании вас могут спросить: «Почему clamp, а не медиазапросы?» Ответ: медиазапросы дают ступенчатые изменения — между брейкпоинтами размер фиксирован. clamp даёт непрерывное масштабирование, что выглядит естественнее и требует меньше кода.

    Container Queries: адаптивность компонента

    Контейнерные запросы — это революция в CSS. В отличие от медиазапросов, которые реагируют на размер viewport, контейнерные запросы реагируют на размер родительского контейнера. Это значит, что один и тот же компонент может выглядеть по-разному в широкой и узкой колонке — без JavaScript.

    Сначала объявите контейнер:

    Затем используйте @container:

    Карточка в широкой боковой панели покажет горизонтальную раскладку, а та же карточка в узком столбце основного контента — вертикальную. Это истинная адаптивность на уровне компонента.

    Container Query Units

    Контейнерные запросы вводят свои единицы измерения — cqw, cqh, cqb, cqi и другие. 1cqw = 1% ширины контейнера. Это позволяет создавать fluid-размеры внутри компонента, привязанные к контейнеру, а не к viewport:

    Медиазапросы: продвинутые техники

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

    Лучшие практики:

  • Используйте min-width (mobile-first) — пишете базовые стили для мобильных, затем добавляете сложность для больших экранов. Это стандарт индустрии.
  • Избегайте фиксированных брейкпоинтов «для iPhone» — ориентируйтесь на контент. Когда дизайн ломается — это и есть точка брейкпоинта.
  • Группируйте медиазапросы по компонентам (если не используете контейнерные запросы), а не пишете один большой блок в конце файла.
  • Адаптивные изображения

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

  • srcset и sizes — браузер выбирает оптимальный файл на основе плотности пикселей и размера отображения.
  • <picture> — арт-дирекшн: разные изображения для разных viewport.
  • aspect-ratio — задаёт соотношение сторон, предотвращая Cumulative Layout Shift (CLS) при загрузке.
  • Атрибут loading="lazy" откладывает загрузку изображений, которые вне viewport. decoding="async" разрешает браузеру декодировать изображение асинхронно, не блокируя рендер.

    Современные CSS-возможности, которые стоит знать

    aspect-ratio — задаёт соотношение сторон без padding-hack:

    text-wrap: balance — браузер балансирует переносы строк в заголовках, чтобы строки были примерно одинаковой длины:

    color-mix() — смешивает два цвета в заданной пропорции:

    has() — родительский селектор — одна из самых ожидаемых возможностей CSS. Позволяет стилизовать родителя на основе его потомков:

    До :has() это было невозможно без JavaScript. Теперь чистый CSS может решать задачи, которые раньше были за пределами его возможностей.

    Частый вопрос: «Как вы обеспечиваете доступность при адаптивной вёрстке?»

    Адаптивность — это не только ширина экрана. Учитывайте:

  • Масштабирование текста: пользователи могут увеличить шрифт до 200%. Используйте rem вместо px — тогда всё масштабируется пропорционально.
  • Контраст: проверяйте соотношение через color-contrast() (экспериментальная функция) или вручную через инструменты разработчика.
  • Фокус: при адаптации навигации (например, бургер-меню) убедитесь, что порядок фокуса логичен и все интерактивные элементы доступны с клавиатуры.
  • prefers-reduced-motion — медиазапрос, отключающий анимации для пользователей, которые этого требуют в системных настройках.
  • 5. Лайфхаки и частые вопросы на собеседованиях

    Лайфхаки и частые вопросы на собеседованиях

    Почему кандидат с идеальным знанием теории может провалить собеседование? Потому что интервьюеры спрашивают не определения — они ставят ловушки, проверяют понимание граничных случаев и хотят увидеть, как вы думаете о CSS, а не просто цитируете спецификацию. Эта статья — сборник конкретных вопросов, неочевидных ответов и практических приёмов, которые кандидаты узнают слишком поздно.

    Центрирование: проверка на автоматизме

    Первый вопрос на многих интервью: «Тремя способами центрировать элемент по горизонтали и вертикали». Это не вопрос знания — это проверка, насколько CSS у вас в мышечной памяти.

    Способ 1 — Grid:

    Способ 2 — Flexbox:

    Способ 3 — Абсолютное позиционирование:

    Способ 4 (бонус) — Margin auto + Grid:

    > Если интервьюер спрашивает «а ещё?» — упомяните position: absolute + inset: 0 + margin: auto (работает, когда размеры элемента известны). Это показывает глубину знаний.

    BEM и методологии именования

    BEM (Block-Element-Modifier) — не просто соглашение об именовании, а способ мышления о компонентах.

  • Блок — автономный компонент: .header, .card, .button.
  • Элемент — часть блока, не существует вне его: .card__title, .button__icon.
  • Модификатор — вариант состояния или внешнего вида: .button--primary, .card--featured.
  • Почему BEM работает: он делает специфичность плоской — все селекторы имеют один класс (вес 0,0,1,0). Нет вложенности — нет конфликтов. Нет конфликтов — нет !important.

    Частый вопрос: «А если элемент вложен в другой блок?» BEM запрещает зависимость элемента от контекста. Если кнопка внутри карточки — она остаётся .button, а не .card__button (если это переиспользуемый компонент). Контейнерные стили задаются через обёртку или модификатор блока.

    Альтернативы BEM: SMACSS (разделение на base, layout, module, state, theme), OOCSS (разделение структуры и оформления), ITCSS (инвертированная пирамида: settings → tools → generic → elements → objects → components → utilities). На собеседовании достаточно знать BEM и понимать, зачем нужны методологии — они предотвращают деградацию CSS на больших проектах.

    Позиционирование: ловушки, которые убивают

    position: sticky не работает? Три причины:

  • У предка есть overflow: hidden / overflow: auto / overflow: scroll — sticky блок «прилипает» к ближайшему скроллируемому контейнеру, а не к viewport.
  • Не задано смещение: top: 0 обязательно — без него sticky ведёт себя как relative.
  • Родительский контейнер короче sticky-элемента — прилипать некуда.
  • position: fixed внутри transform? Если у предка элемента задан transform, filter или perspective, то fixed ведёт себя как absolute — позиционируется относительно предка, а не viewport. Это частый баг при использовании анимаций на родителе.

    Блочная модель и box-sizing

    По умолчанию width задаёт размер контентной области — padding и border добавляются снаружи. Это значит, что элемент с width: 100px; padding: 10px; border: 2px solid займёт 124px.

    При border-box padding и border включаются в width. Элемент с width: 100px; padding: 10px; border: 2px solid займёт ровно 100px, а контентная область сожмётся до 76px.

    > На собеседовании: «Почему border-box — стандарт де-факто?» Потому что интуитивно: задал ширину — получил эту ширину. Без border-box каждый padding и border требует пересчёта.

    Margin collapse: классическая ловушка

    Вертикальные margin соседних элементов схлопываются — берётся бо́льшее значение, а не сумма. Элемент с margin-bottom: 20px и следующий с margin-top: 30px дадут зазор 30px, а не 50px.

    Схлопывание не происходит в:

  • Flexbox и Grid контейнерах.
  • Элементах с float, overflow не visible, display: inline-block.
  • Абсолютно позиционированных элементах.
  • BFC (Block Formatting Context) — контекст форматирования блока, изолированная область, в которой правила схлопывания margin не действуют за пределы контейнера. Создаётся через overflow (кроме visible), display: flow-root, display: flex, display: grid, position: absolute.

    Stack context и z-index

    z-index работает только на элементах с position (кроме static) и внутри stacking context. Каждый stacking context — изолированная вселенная: z-index внутри него не конкурирует с z-index вне его.

    Stacking context создаётся, когда:

  • Элемент с position и z-index (не auto).
  • Элемент с opacity меньше 1.
  • Элемент с transform, filter, perspective, clip-path.
  • Элемент с will-change.
  • Элемент с contain: layout / paint / strict.
  • > На собеседовании: «Почему z-index: 9999 не работает?» — потому что элемент находится внутри stacking context, созданного предком. Решение: поднять z-index у предка или убрать свойство, создающее контекст.

    Производительность CSS

    Не все CSS-свойства равны по стоимости перерисовки. Свойства делятся на три уровня:

  • Геометрия (layout): width, height, margin, padding, top, left — вызывают reflow (пересчёт макета) + repaint. Самые дорогие.
  • Отрисовка (paint): color, background, box-shadow, border-radius — только repaint. Дешевле.
  • Композиция (composite): transform, opacity — обрабатываются GPU, не вызывают layout и paint. Самые дешёвые.
  • Для анимаций используйте только transform и opacity:

    will-change — подсказка браузеру заранее выделить GPU-слой. Не злоупотребляйте: каждый слой потребляет память. Применяйте только к элементам, которые точно будут анимированы, и убирайте через JS после завершения анимации.

    Чек-лист перед собеседованием

    Вопросы, которые задают чаще всего, и краткие ответы:

    «Чем отличается em от rem em — относительно шрифта текущего элемента, rem — корневого. em каскадируется и может привести к экспоненциальному росту при вложенности.

    «Что такое BFC и зачем он нужен?» Block Formatting Context — изолированная область, в которой float'ы, margin collapse и поток блоков работают по своим правилам. Решает проблемы с обтеканием float'ов и схлопыванием margin.

    «Как работает каскад?» Порядок приоритетов: importance (!important) → origin (user agent < user < author) → specificity → source order.

    «Как скрыть элемент, сохранив его в потоке?» visibility: hidden — элемент невидим, но занимает место. opacity: 0 — то же, но элемент остаётся интерактивным. display: none — убирает из потока полностью.

    «Разница между relative, absolute, fixed, sticky? relative — смещение от обычной позиции, элемент остаётся в потоке. absolute — позиционируется относительно ближайшего positioned-предка, убирается из потока. fixed — относительно viewport. sticky — гибрид: ведёт себя как relative`, пока не достигнет порога, затем «прилипает».

    «Как сделать доступный скринридер-only текст?» Классический паттерн — визуально скрыть, но оставить для ассистивных технологий:

    Этот набор вопросов и ответов покрывает 80% того, что спрашивают на CSS-интервью. Остальные 20% — это комбинации этих концепций в практических задачах: «Сверстайте адаптивную карточку товара», «Сделайте sticky-header с тенью при скролле», «Реализуйте тёмную тему без JavaScript». Ключ к успеху — не запоминание ответов, а понимание механизмов, которые за ними стоят.