Привет, Хабр!

CSS часто преподносит сюрпризы, способные запутать даже опытных разработчиков. Я понимаю их раздражение. Тут всё закономерно.

Как человек, хорошо знающий CSS, могу сказать, что он умеет удивлять. Причём так, что в замешательстве оказываются даже опытные разработчики. Поэтому я понимаю разные мемчики по поводу CSS. Они возникли не на пустом месте.

И всё же, несмотря на все потраченные нервы, CSS мне нравится. Поэтому хочется, чтобы разработчики реже тратили время на борьбу с его особенностями. Изменить стандарты языка не в моих силах, но я смог собрать несколько неочевидных моментов, которые в своё время поставили в тупик меня и моих коллег.

Пришёл поделиться с вами. Давайте посмотрим, что я подготовил.

Свойство min-width

Работа с текстом в веб-интерфейсах — это всегда сложная задача. То его мало, то слишком много. Или вообще нужно отобразить весь текст в одну строку и обрезать ту часть, которая не помещается.

Я думаю, вы встречали этот трюк: когда строка не помещается, появляется многоточие.

<body>
  <div class="awesome-block">
    <span class="clip">Длинный текст, который не переносится</span>
  </div>
</body>
.awesome-block {
  max-width: 200px;
}

.clip {
  display: block;
  border: 2px solid;

  text-wrap: nowrap;
  text-overflow: ellipsis;
  overflow: clip;
}

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

.awesome-block {
  max-width: 200px;
  display: grid;
}

.clip {
  display: block;
  border: 2px solid;

  text-wrap: nowrap;
  text-overflow: ellipsis;
  overflow: clip;
}

Вы знаете причину такого поведения? Во всём виновато свойство min-width. Если вы удивлены, то давайте разберёмся в деталях.

Дело в том, что свойство min-width добавляется по умолчанию ко всем элементам. Если вы проинспектируете код, то в инструментах разработчиках увидите значение 0 для него.

А если посмотрите значение для этого свойства у элемента с классом .clip, то увидите auto.

И это не баг. Дело в том, что раньше значение по умолчанию у свойства min-width было 0px. Потом его поменяли на auto. Так и осталось до сегодняшних дней.

Но для обратной совместимости в стандарте указали, что нужно использовать значение 0px. По этой причине у нас разное поведение, и важно помнить, что делают оба значения.

Когда браузеры встречают значение auto для свойства min-width, то делают всё, чтобы минимальная ширина рассчиталась по всей строке контента. Именно это мы увидим в инструментах разработчика.

Значение 0px же ничего не заставляет делать. Браузеры поймут, что минимальная ширина элемента 0px. Всё. Никаких обязательств по отображению контента нет.

Соответственно, чтобы починить нашу демонстрацию, надо переопределить значения auto на 0 у элемента с классом .clip.

.awesome-block {
  max-width: 200px;
  display: grid;
}

.clip {
  display: block;
  border: 2px solid;
  min-width: 0;

  text-wrap: nowrap;
  text-overflow: ellipsis;
  overflow: clip;
}

Свойство overflow

У многих разработчиков, не любящих верстать, есть проблема неожиданного появления полосы прокрутки. Решают они её с помощью свойства overflow: добавляют его со значением hidden и скрывают полосу прокрутки.

Казалось бы, в чём проблема? Знали вы бы, сколько раз мне приходилось разбираться с этим свойством, потому что оно приводит к неожиданным багам.

Давайте для начала разберёмся, что же делает свойство overflow. Как сказано во многих источниках, свойство управляет отображением элемента, если в него не помещается контент.

Нюанс заключается в его значениях. Если вы откроете спецификацию, то увидите везде упоминание про термин scroll-container. Если говорить по-простому, то это прямоугольник, относительно которого работает прокрутка.

Все значения свойства overflow делятся на две группы. Первая создаёт новую область scroll-container, а вторая так не делает. По этой причине мы получаем неожиданное поведение. Рассмотрим его на нескольких примерах.

Начнём мы со свойства scroll-margin-top. Отличный способ задать отступ между границей вьюпорта и элементом, к которому происходит переход. Для демонстрации я создал несколько разделов, к котором можно перейти по ссылкам.

<body>
  <nav>
	  <ul>
		  <li><a href="#section-one">Раздел №1</a></li>
		  <li><a href="#section-two">Раздел №2</a></li>
		  <li><a href="#section-three">Раздел №3</a></li>
	  </ul>
  </nav>
  <section class="awesome-section">
	  <h2 id="section-one">Раздел №1</h2>
	  <p>Контент раздела</p>
  </section>
  <section class="awesome-section">
	  <h2 id="section-two">Раздел №2</h2>
	  <p>Контент раздела</p>
  </section>
  <section class="awesome-section">
	  <h2 id="section-three">Раздел №3</h2>
	  <p>Контент раздела</p>
  </section>
</body>
.awesome-section {
  min-height: 100dvh;
  border-top: 1px solid;
}

Для начала я не использую свойство scroll-margin-top. Поэтому у меня не будет отступа от вьюпорта.

Теперь добавим его. Например, 10rem.

.awesome-section {
  min-height: 100dvh;
  border-top: 1px solid;
}

h2 {
  scroll-margin-top: 10rem;
}

У нас появился отступ, поэтому мы видим границу раздела. Что ж, давайте всё сломаем. Добавим свойство overflow со значением hidden.

.awesome-section {
  min-height: 100dvh;
  border-top: 1px solid;
  overflow: hidden;
}

h2 {
  scroll-margin-top: 10rem;
}

Как я говорил, отступ пропал, и теперь мы не видим границу раздела, как раньше. Но давайте починим демонстрацию. Заменим значение hidden на clip.

.awesome-section {
  min-height: 100dvh;
  border-top: 1px solid;
  overflow: clip;
}

h2 {
  scroll-margin-top: 10rem;
}

Магия! Всё снова заработало. Почему так происходит?

Значение hidden относится к группе значений свойства overflow, которое создаёт новую область scroll container. И это плохо.

Дело в том, что браузеры всегда используют область scroll container для вычисления отступа, созданного свойством scroll-margin-top. До добавления свойства overflow ей был прямоугольник всей страницы, а эта область ограничивается каждым элементом с классом awesome-section.

В итоге мы получаем отсутствие отступа. В варианте со значением clip этого нет, потому что оно не создаёт новую область scroll container. Браузеры просто обрезают контент элемента, поэтому отступ есть.

Ещё одной ситуацией, в который свойство overflow может поломать отображение, является использование свойства position со значением sticky. Для демонстрации я создал разметку, в которой залипать будет квадрат.

<body>
  <div class="awesome-container">
    <div class="awesome-sticky"></div>
    <div class="awesome-block">
      <!-- здесь много текста -->
    </div>
  </div>
</body>
.awesome-sticky {
  width: 20rem;
  height: 20rem;
  background-color: tomato;
  position: sticky;
  top: 0;
}

Пока всё работает отлично. При прокрутке страницы квадрат прилипает к верхней границе вьюпорта. Добавим свойство overflow со значением hidden к элементу с классом .awesome-container.

.awesome-sticky {
  width: 20rem;
  height: 20rem;
  background-color: tomato;
  position: sticky;
  top: 0;
}

.awesome-container {
  overflow: hidden;
}

Сломалось. Причина такого поведения та же. Мы изменили область scroll container, и теперь браузеры не могут прилепить квадрат. Исправить ошибку можно значением clip.

.awesome-sticky {
  width: 20rem;
  height: 20rem;
  background-color: tomato;
  position: sticky;
  top: 0;
}

.awesome-container {
  overflow: clip;
}

Вот таким образом привычка разработчиков расставлять свойство overflow может легко привести к багам. Если уж хотите использовать его, то делайте это со значением clip.

Краткая форма свойства и пользовательские свойства

Мой CSS-код — это архитектура, построенная на пользовательских свойствах. Вся работа строится через них. Именно такую пользу я видел от пользовательских свойств, когда они появились.

Только в этом подходе есть свои подводные камни. Иногда можно очень легко допустить ошибку, которая приведёт к некорректному отображению. Для примера давайте рассмотрим код, в котором используется краткая форма записи свойства border вместе со значениями, переданными пользовательским свойствами.

:root {    
  --border-width: 2px;
  --border-style: solid;
}

.awesome-block {
  height: 50px;
  border: var(--border-width) var(--border-style) var(--border-color);
}

Мы не увидим рамку вокруг элемента. И это не ошибка. Об этом кейсе явно написано в спецификации. Как я понял, если отсутствует хотя бы одна составляющая свойства, браузеры не могут правильно сопоставить их. В этой ситуации они просто не применяют значение.

Когда я первый раз встретил этот кейс, то в инструментах разработчика не было никаких подсказок. Я без преувеличения потратил несколько часов, чтобы понять, в чём проблема.

Сейчас же уже есть подсказка. В инструментах разработчика не переданное значение не подсвечивается. Также, если навести на него, то увидите сообщение, что свойство не определено.

Так что обращайте внимание на такие моменты при работе с пользовательскими свойствами.

Свойство hypens

У меня есть формат статей, в которых я рассказываю про редкоиспользуемые фичи CSS. В одной серии хотел рассказать про свойство hypens. Обычно сначала я делаю демку.

<body>
  <div class="awesome-block">
    <!-- здесь текст --->
  </div>
</body>
.awesome-block {
  hyphens: auto;
  max-width: 15rem;
}

Увидев блок с текстом, я озадачился. Значение auto для свойств hypens должно было добавить перенос слов с помощью дефиса. Но, как вы видите, этого не произошло. Браузеры переносят слова целиком, забив на моё желание увидеть дефисы.

Я проверил написание свойства. Проверил разметку. Всё было правильно. Я всё больше не понимал, почему демонстрация не работала. А потом я просто от отчаяния добавил атрибут lang со значением ru. И всё заработало!

<body>
  <div class="awesome-block" lang="ru">
    <!-- здесь текст --->
  </div>
</body>

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

Именно в этом заключалась проблема в моей демонстрации. Поскольку я использую онлайн-песочницу, там для элемента html установлен атрибут lang со значением en. А мой текст написан на русском языке. И эта несостыковка мешала браузерам отобразить дефисы.

Заключение

Подведём итог. В этой статье мы рассмотрели:

  • какие есть значения свойства overflow, приводящие к разным результатам;

  • почему краткие формы записи могут сломаться при использовании пользовательских CSS-свойств;

  • как свойство min-width может поломать обрезку текста;

  • в каких ситуациях свойство hypens не будет работать.

Коллеги, мне ещё интересно узнать о ваших конфликтах с CSS. В каких ситуациях CSS вас бесил? Расскажите, пожалуйста, о них в комментариях. Я постараюсь помочь вам решить эти конфликты в новой статье.

На этом всё. Спасибо за чтение!

P. S. Помогаю больше узнать про CSS и дружелюбные интерфейсы в своих закрытых ТГ-каналах CSS isn't magic и UX + Dev = a11y. Присоединяйтесь. Как вступить, написано в профиле.

© 2026 ООО «МТ ФИНАНС»