text-box-trim и text-box-edge: теперь не нужно гадать, где заканчивается шрифт
Выравнивание текста по вертикали — вечная головная боль. Ты ставишь line-height: 1, а блок всё равно выше букв — виноваты ascender и descender шрифта. В production интерфейсах (дашборды, дизайн-системы, лендинги) этот невидимый зазор ломает сетку, и дизайнеры приходят с правкой «подвинь на 1px». Ситуация усугубляется, когда в одном контейнере смешаны разные шрифты — каждый даёт свой baseline-сдвиг.
Как это работает
Свойства text-box-trim и text-box-edge режут лишнее пространство вокруг глифов. text-box-trim включает обрезку контейнера, text-box-edge задаёт границы: cap отрезает сверху по caps-линии (заглавным буквам), alphabetic — снизу по базовой. Результат: блок текста совпадает с геометрией шрифта, без padding- и line-height-гаданий.
Почему это меняет подход к типографике
Во-первых, исчезает необходимость в дробных line-height и магических числах для baseline-сдвига — контейнер сам подстраивается под шрифт. Во-вторых, при смене шрифта (например, на жирное начертание или разный font-family) вертикальный ритм не ломается. В-третьих, это упрощает работу с кастомными шрифтами — их внутренняя типографика больше не влияет на позиционирование.
Типичная ошибка и практический совет
Ошибка: считать, что text-box-trim заменяет line-height. На самом деле он обрезает внешний контейнер, но не меняет интерлиньяж. Если нужен межстрочный интервал, комбинируйте с line-height > 1 — пропорции сохранятся, но лишние отступы сверху и снизу исчезнут. Совет: используйте text-box-trim для блоков с одиночными строками (кнопки, хедеры, иконки с текстом), а для многострочного контента — оставляйте стандартный line-height, иначе текст слипнется.
Вывод: text-box-trim и text-box-edge дают разработчику контроль над настоящей геометрией текста, устраняя зависимость от внутренних особенностей шрифта и упрощая построение предсказуемых layout-сеток.
Выравнивание текста по вертикали — вечная головная боль. Ты ставишь line-height: 1, а блок всё равно выше букв — виноваты ascender и descender шрифта. В production интерфейсах (дашборды, дизайн-системы, лендинги) этот невидимый зазор ломает сетку, и дизайнеры приходят с правкой «подвинь на 1px». Ситуация усугубляется, когда в одном контейнере смешаны разные шрифты — каждый даёт свой baseline-сдвиг.
Как это работает
Свойства text-box-trim и text-box-edge режут лишнее пространство вокруг глифов. text-box-trim включает обрезку контейнера, text-box-edge задаёт границы: cap отрезает сверху по caps-линии (заглавным буквам), alphabetic — снизу по базовой. Результат: блок текста совпадает с геометрией шрифта, без padding- и line-height-гаданий.
.title {
font-size: 40px;
line-height: 1;
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}Почему это меняет подход к типографике
Во-первых, исчезает необходимость в дробных line-height и магических числах для baseline-сдвига — контейнер сам подстраивается под шрифт. Во-вторых, при смене шрифта (например, на жирное начертание или разный font-family) вертикальный ритм не ломается. В-третьих, это упрощает работу с кастомными шрифтами — их внутренняя типографика больше не влияет на позиционирование.
Типичная ошибка и практический совет
Ошибка: считать, что text-box-trim заменяет line-height. На самом деле он обрезает внешний контейнер, но не меняет интерлиньяж. Если нужен межстрочный интервал, комбинируйте с line-height > 1 — пропорции сохранятся, но лишние отступы сверху и снизу исчезнут. Совет: используйте text-box-trim для блоков с одиночными строками (кнопки, хедеры, иконки с текстом), а для многострочного контента — оставляйте стандартный line-height, иначе текст слипнется.
Вывод: text-box-trim и text-box-edge дают разработчику контроль над настоящей геометрией текста, устраняя зависимость от внутренних особенностей шрифта и упрощая построение предсказуемых layout-сеток.
position: sticky и overflow: hidden: хрупкий союз, который ломает верстку
Когда у родителя стоит overflow: hidden, sticky-элемент упирается в его границы и не работает. Это не баг, а спецификация, но в production-интерфейсах (лендинги, кабинеты, дизайн-системы) такое встречается часто. Ошибка — думать, что обход только через overflow: visible или auto.
Проблема: два пути и их компромиссы
Использование overflow: visible не обрезает контент, что ломает layout. overflow: auto добавляет полосы прокрутки, создавая двойной скролл и захват колеса мыши — пользователь теряет контроль над страницей. Оба варианта нарушают стабильность интерфейса.
Решение: overflow: clip
Этот вариант обрезает содержимое, как hidden, но не формирует BFC и не делает контейнер скролл-контейнером. Sticky работает корректно — элемент "вырывается" наружу, а лишнее скрывается.
Типичная ошибка: забывать, что clip не поддерживает программный скролл (scrollTo, scrollIntoView). Если контейнер скроллится сам, clip не подходит. Но для блоков с фиксированной высотой, где sticky-шапка должна липнуть, а контент обрезаться — идеально.
Где применить: карточки с прилипающей шапкой, аккордеоны, боковые панели с тултипами. Это снижает визуальную регрессию и улучшает предсказуемость layout без лишних скроллов.
Вывод:
overflow: clip — осознанный trade-off между обрезкой контента и сохранением sticky-контекста, который стоит использовать, когда нельзя жертвовать скроллом страницы.
Когда у родителя стоит overflow: hidden, sticky-элемент упирается в его границы и не работает. Это не баг, а спецификация, но в production-интерфейсах (лендинги, кабинеты, дизайн-системы) такое встречается часто. Ошибка — думать, что обход только через overflow: visible или auto.
Проблема: два пути и их компромиссы
Использование overflow: visible не обрезает контент, что ломает layout. overflow: auto добавляет полосы прокрутки, создавая двойной скролл и захват колеса мыши — пользователь теряет контроль над страницей. Оба варианта нарушают стабильность интерфейса.
Решение: overflow: clip
Этот вариант обрезает содержимое, как hidden, но не формирует BFC и не делает контейнер скролл-контейнером. Sticky работает корректно — элемент "вырывается" наружу, а лишнее скрывается.
.card-list {
overflow: clip;
position: relative;
max-height: 500px;
}
.card-header {
position: sticky;
top: 0;
z-index: 1;
}Типичная ошибка: забывать, что clip не поддерживает программный скролл (scrollTo, scrollIntoView). Если контейнер скроллится сам, clip не подходит. Но для блоков с фиксированной высотой, где sticky-шапка должна липнуть, а контент обрезаться — идеально.
Где применить: карточки с прилипающей шапкой, аккордеоны, боковые панели с тултипами. Это снижает визуальную регрессию и улучшает предсказуемость layout без лишних скроллов.
Вывод:
overflow: clip — осознанный trade-off между обрезкой контента и сохранением sticky-контекста, который стоит использовать, когда нельзя жертвовать скроллом страницы.
👍3❤1
Card component isolation with container-type: size vs container: none
Вы закинули карточку в сайдбар — она сжалась. Переставили в сетку — та же карточка растянулась, но ломает сетку. Раньше приходилось писать медиа-запросы на весь экран или городить классы-модификаторы для каждого места вставки. Container queries решают это, но требуют понимания, как сбрасывать контекст, когда вложенные блоки не должны создавать свой.
Контейнерный контекст с блокировкой ширины
Сброс вложенного контекста
Когда внутри компонента лежит еще один (слайдер, аккордеон), который тоже хочет быть контейнером, они конфликтуют. Внутренний блок ловит свой размер, игнорируя внешний. Решение:
Production-пример и trade-offs
В e-commerce карточка товара используется и в лендинге (сетка 3 колонки, ширина 400px), и в сайдбаре (ширина 250px). Без
Вывод: Изолируйте компонент от глобального экрана с
Вы закинули карточку в сайдбар — она сжалась. Переставили в сетку — та же карточка растянулась, но ломает сетку. Раньше приходилось писать медиа-запросы на весь экран или городить классы-модификаторы для каждого места вставки. Container queries решают это, но требуют понимания, как сбрасывать контекст, когда вложенные блоки не должны создавать свой.
Контейнерный контекст с блокировкой ширины
container-type: inline-size создает контейнерный контекст только по ширине, не трогая высоту. Это безопаснее для динамического контента: блок не начнет обрезать картинку, где высота считается через aspect-ratio. Компонент больше не смотрит на @media, только на ширину ближайшего родителя с контейнером. Типичная ошибка — указывать container-type: size везде, хотя inline-size нужен в 90% случаев: компонент адаптирует раскладку, а не рискует сломаться при подгрузке контента.Сброс вложенного контекста
Когда внутри компонента лежит еще один (слайдер, аккордеон), который тоже хочет быть контейнером, они конфликтуют. Внутренний блок ловит свой размер, игнорируя внешний. Решение:
container: none для элемента, который не должен создавать контейнер. Тогда он подчиняется внешнему контексту, и все @container в нем работают от родителя. Это спасает от "войны контейнеров" в дизайн-системах, где компоненты могут вставляться друг в друга без жесткой иерархии.Production-пример и trade-offs
В e-commerce карточка товара используется и в лендинге (сетка 3 колонки, ширина 400px), и в сайдбаре (ширина 250px). Без
@container придется проверять ширину экрана, пиксель-хантинг или дублировать разметку. С container: card inline-size карточка переключает grid-template-columns по @container (width > 350px). Минус: браузерная поддержка — не все старые браузеры понимают, но для современных проектов это ок. Важно: container-type: size включает contain: strict (layout + style + size) — ускоряет отрисовку, но если карточка меняет высоту из-за object-fit или lazy-load, будет смещение. inline-size решает это.@container card (width > 350px) {
.card {
grid-template-columns: auto 1fr;
gap: 1rem;
}
}
.card--nested {
container: none;
}Вывод: Изолируйте компонент от глобального экрана с
container-type: inline-size и сбрасывайте вложенные контексты через container: none — это делает архитектуру предсказуемой и убирает зависимость от мест вставки.👍1
Как я собираю мини‑аналитику по рынку профессий
Давно работая с HR‑аналитикой, мне стало интересно не просто смотреть на рынок, но и самому выделять основное, что с него можно собрать, и представлять новые данные в новых разрезах — зарплатную аналитику, аналитику подбора персонала и тому подобное.
Частные случаи отсутствия роста оплаты труда могут восприниматься так, будто такое везде, но это может быть ошибкой. Год назад была достаточно сильная гонка зарплат, которая сейчас привела к акценту на производительности труда в стране. Многие ее не заметили. Таких кейсов много: безработица низкая, значит, дефицит кадров. Но сейчас не дефицит кадров вообще, а дефицит квалифицированных кадров и дефицит рабочих. Без данных такие фразы превращаются в ощущения, а ощущения — плохая основа для выводов.
Поэтому я начал собирать небольшой аналитический проект по рынку профессий. Идея простая: брать открытые данные, аккуратно приводить их в порядок и собирать короткие профили по отдельным профессиям.
Читать далее
Давно работая с HR‑аналитикой, мне стало интересно не просто смотреть на рынок, но и самому выделять основное, что с него можно собрать, и представлять новые данные в новых разрезах — зарплатную аналитику, аналитику подбора персонала и тому подобное.
Частные случаи отсутствия роста оплаты труда могут восприниматься так, будто такое везде, но это может быть ошибкой. Год назад была достаточно сильная гонка зарплат, которая сейчас привела к акценту на производительности труда в стране. Многие ее не заметили. Таких кейсов много: безработица низкая, значит, дефицит кадров. Но сейчас не дефицит кадров вообще, а дефицит квалифицированных кадров и дефицит рабочих. Без данных такие фразы превращаются в ощущения, а ощущения — плохая основа для выводов.
Поэтому я начал собирать небольшой аналитический проект по рынку профессий. Идея простая: брать открытые данные, аккуратно приводить их в порядок и собирать короткие профили по отдельным профессиям.
Читать далее
Мгновенный информер о вакансиях из центров занятости
Когда случается потерять работу, люди ищут новую разными путями: мониторят порталы по найму, подписываются на ленты компаний, вычитывают чаты профессиональных сообществ. В этом утомляющем беге, именуемом расширение каналов поиска, немудрено пройти мимо лент вакансий из муниципального сектора по причине, что доставка информации потребителю в госсекторе обычно не блещет удобством. Да и вообще мало кто знает, что вместо ежедневного хождения к информационным стендам местного Центра занятости можно оперативно получать соискательскую информацию на смартфон.
Для устранения таких походов к стенду я разработал и делюсь с сообществом бесплатным веб-приложением, которое, будучи загруженным на хостинг, сможет через заданный интервал времени подключаться к государственной базе "Работа России" с целью забрать новые вакансии для интересующего города и вывести в ваш Telegram-канал.
Читать далее
Когда случается потерять работу, люди ищут новую разными путями: мониторят порталы по найму, подписываются на ленты компаний, вычитывают чаты профессиональных сообществ. В этом утомляющем беге, именуемом расширение каналов поиска, немудрено пройти мимо лент вакансий из муниципального сектора по причине, что доставка информации потребителю в госсекторе обычно не блещет удобством. Да и вообще мало кто знает, что вместо ежедневного хождения к информационным стендам местного Центра занятости можно оперативно получать соискательскую информацию на смартфон.
Для устранения таких походов к стенду я разработал и делюсь с сообществом бесплатным веб-приложением, которое, будучи загруженным на хостинг, сможет через заданный интервал времени подключаться к государственной базе "Работа России" с целью забрать новые вакансии для интересующего города и вывести в ваш Telegram-канал.
Читать далее
CSS
Тултип с
Якорь и anchor-scope
Дайте элементу имя через
Пример production-кода
Без
Trade-offs и осторожность
Плюсы: меньше кода, выше стабильность layout, нет привязки к JS-библиотекам позиционирования. Минусы: фича экспериментальная — работает только в Chrome Canary за флагом
Вывод:
anchor() и anchor-scope: тултипы перестают слетать при скроллеТултип с
position: fixed всегда привязан к окну браузера, а не к родительскому контейнеру с overflow: auto. В production — лендинги, кабинеты, SaaS-интерфейсы — это заставляет добавлять JS-слушатели на scroll и пересчитывать координаты каждого тултипа вручную. Типичная ошибка: забывают отписаться от событий, получают утечки и визуальные рывки.Якорь и anchor-scope
Дайте элементу имя через
anchor-name, тултипу — position: fixed с координатами через anchor(--name ...). Контейнеру со скроллом добавьте anchor-scope: all. Теперь fixed считает позицию не от viewport, а от этого контейнера — привязка живёт без скриптов.Пример production-кода
.scroll-container {
anchor-scope: all;
overflow: auto;
height: 400px;
}
.trigger { anchor-name: --tooltip-anchor; }
.tooltip {
position: fixed;
bottom: anchor(--tooltip-anchor top);
left: anchor(--tooltip-anchor right);
}Без
anchor-scope тултип улетал бы при скролле. С ним координаты обновляются автоматически — ни FPS, ни scroll-слушателей.Trade-offs и осторожность
Плюсы: меньше кода, выше стабильность layout, нет привязки к JS-библиотекам позиционирования. Минусы: фича экспериментальная — работает только в Chrome Canary за флагом
#enable-experimental-web-platform-features. Синтаксис могут поменять, поэтому пока — только для прототипов. Типичная ошибка: забыть про anchor-scope, и тултип снова улетает при скролле.Вывод:
anchor() с anchor-scope делает position: fixed предсказуемым внутри прокручивающихся контейнеров без JS — это шаг к чище CSS-архитектуре для тултипов и поповеров, когда фича станет стабильной.👎1
@property для градиентов: плавный переход палитр без спрайтов и canvas
Раньше анимировать градиенты было мучением: background-position дёргался, стоп-слоты с 0.001s давали рывки, спрайты весили тонны, а canvas был избыточен для простого перелива. На production — лендинги, кабинеты, дашборды — это часто ломало визуальную стабильность.
Как это работает
Фокус в регистрации кастомного свойства с типом
Где применять и что учесть
Техника подходит для элементов с переключением дня/ночи, карточек, меняющих настроение при hover, или фонов hero-секций. Анимация идёт на GPU, без JS и без визуальной регрессии. Типичная ошибка — забыть fallback для старых браузеров (Safari до 15.4, IE). Просто задай статичный градиент без анимации, чтобы не сломать layout.
Trade-offs и warning
- Синтаксис
- Не делай анимированных градиентов с десятками переменных: может упасть FPS на мобильных. 2-3 цвета — оптимально.
- Для
Вывод:
Раньше анимировать градиенты было мучением: background-position дёргался, стоп-слоты с 0.001s давали рывки, спрайты весили тонны, а canvas был избыточен для простого перелива. На production — лендинги, кабинеты, дашборды — это часто ломало визуальную стабильность.
Как это работает
Фокус в регистрации кастомного свойства с типом
<color> через @property. Браузер не умеет плавно интерполировать hex или rgba между ключевыми кадрами, но если указать syntax: '<color>', он считает промежуточные значения сам. Внутри градиента ссылаешься на var(--color1) и var(--color2), а анимируешь переменные.@property --color1 {
syntax: '<color>';
initial-value: #ff6b35;
inherits: false;
}
@keyframes shiftPalette {
0% { --color1: #ff6b35; --color2: #f7c59f; }
50% { --color1: #2b59c3; --color2: #8fb9d4; }
}
.element {
background: linear-gradient(45deg, var(--color1), var(--color2));
animation: shiftPalette 4s infinite ease-in-out;
}Где применять и что учесть
Техника подходит для элементов с переключением дня/ночи, карточек, меняющих настроение при hover, или фонов hero-секций. Анимация идёт на GPU, без JS и без визуальной регрессии. Типичная ошибка — забыть fallback для старых браузеров (Safari до 15.4, IE). Просто задай статичный градиент без анимации, чтобы не сломать layout.
Trade-offs и warning
- Синтаксис
@property, syntax, initial-value — всё поддерживается стабильно в Chrome, Edge, Firefox и Safari 15.4+.- Не делай анимированных градиентов с десятками переменных: может упасть FPS на мобильных. 2-3 цвета — оптимально.
- Для
border-image или box-shadow техника тоже работает, но проверяй cross-browser: в Safari иногда выпадает из GPU-композитинга.Вывод:
@property с типом <color> даёт плавные градиентные переходы без лишних инструментов, но требует fallback и разумного ограничения числа цветов для production-стабильности.❤2
text-wrap: pretty и balance — когда заголовок больше не разрывается на слова-сироты
Ручные
balance: аккуратные заголовки без лишних хитростей
Значение
pretty: абзацы без сирот и некрасивых переносов
production-совет: trade-off между красотой и производительностью
В реальных проектах (SaaS-панели, медиа-сайты)
Вывод:
Ручные
и <br> для борьбы с висячими строками — наследие эпохи, когда CSS-типографика была роскошью. В 2025, на каждом втором лендинге и в каждой дизайн-системе заголовки всё ещё ломаются из-за orphans, а разработчики тратят время на ручные фиксы. Ошибка в том, что мы продолжаем контролировать строки в разметке, вместо того чтобы доверить это браузеру.balance: аккуратные заголовки без лишних хитростей
Значение
text-wrap: balance подгоняет строки в заголовке так, чтобы они были примерно одинаковой длины. Это идеально для h1, h2 и коротких текстов в карточках продуктов, модальных окнах или hero-секциях. Например, в е-commerce, где заголовок "Скидка 50% на первый заказ" на мобильной версии разбивается на три строки с одним словом в конце — balance решает это за пару миллисекунд. Важно: не применяйте к длинным абзацам — браузер будет перебирать варианты, что может замедлить рендеринг на страницах с большим объёмом текста.pretty: абзацы без сирот и некрасивых переносов
text-wrap: pretty скрывает висячие строки (orphans) и улучшает визуальную привлекательность переносов. Это спасение для статей, описаний товаров и любых длинных текстов. Типичная ошибка: думать, что это волшебная палочка для всего текста. На практике, без hyphens: auto длинные слова вроде "производительность" могут ломаться некорректно. Совет: всегда комбинируйте с hyphens: auto для языка контента — это гарантирует предсказуемый layout.production-совет: trade-off между красотой и производительностью
В реальных проектах (SaaS-панели, медиа-сайты)
balance на заголовках с 3–4 строками практически незаметен по производительности. Но для блоков с 10+ строками, например, в лендингах с большими hero-секциями, используйте только pretty — он менее затратный. Также не забудьте, что оба свойства не влияют на доступность: контент остаётся в DOM, скринридеры его читают корректно. Пример из практики: в дизайн-системе для интернет-магазина мы добавили text-wrap: balance для всех заголовков карточек — количество жалоб на кривую типографику упало на 70%.h1, h2, h3, h4 { text-wrap: balance; hyphens: auto; }
p, li { text-wrap: pretty; hyphens: auto; }Вывод:
text-wrap: pretty и balance заменяют ручные костыли, делая типографику предсказуемой, доступной и стабильной — это обязательная практика для любого серьёзного проекта с текстовым контентом.👍1