belun.app Блог
EN

CSS box-shadow: смещение, размытие, растяжение и слои

Что на самом деле делают четыре значения box-shadow, чем размытие отличается от растяжения и на каком приёме держатся реалистичные тени.

Веб-дизайнер настраивает CSS-тени элементов на экране ноутбука

Каждый, кто пишет CSS, хоть раз набирал box-shadow: 0 4px 8px что-нибудь, щурился на результат и начинал менять числа наугад. Свойство принимает до четырёх длин и цвет, ни одно значение не подписано, а два из них — размытие и растяжение — звучат одинаково, пока не увидишь их рядом. Собственно, поэтому и существует генератор CSS-теней: двигаешь ползунки, смотришь на блок, не гадаешь.

И всё же разобраться в числах один раз стоит. Это пять минут — и щуриться больше не придётся.

Четыре значения по порядку

box-shadow: 2px 8px 24px -4px rgba(0, 0, 0, 0.25);

Слева направо: смещение по горизонтали, смещение по вертикали, радиус размытия, радиус растяжения, цвет. С первыми двумя всё просто: положительный X сдвигает тень вправо, положительный Y — вниз, отрицательные значения — наоборот. Почти все тени в интерфейсах используют небольшой положительный Y и нулевой X: свет в UI по умолчанию «падает сверху».

Растяжение необязательно и по умолчанию равно нулю — поэтому повсюду встречаются тени из трёх значений.

Размытие и растяжение — не одно и то же

Размытие смягчает край. Размер тени не меняется, просто её граница затухает на более широкой полосе. При blur: 0 получается жёсткая копия блока — выглядит странно почти всегда, если только вы не собираете ретро-плакат.

Растяжение меняет размер самой тени, ещё до размытия. Положительное — тень вылезает за блок со всех сторон. Отрицательное — сжимается и прячется под элемент.

Отрицательное растяжение недооценивают. Большое размытие плюс слегка отрицательный spread дают мягкость без расползания в стороны — та самая «парящая карточка».

Одна тень всегда выглядит чуть фальшиво

Посмотрите на любой предмет на столе. У его тени есть тёмное плотное ядро у точки контакта и широкий бледный ореол вокруг. Одна строка box-shadow умеет рисовать только что-то одно.

Дизайн-системы решают это наслоением. shadow-md в Tailwind — на самом деле два слоя:

box-shadow:
  0 4px 6px -1px rgb(0 0 0 / 0.1),
  0 2px 4px -2px rgb(0 0 0 / 0.1);

В Material Design на один уровень «высоты» приходится до трёх теней. Схема всегда одна: маленькая резкая тень отвечает за контакт, большая размытая — за воздух. box-shadow принимает сколько угодно слоёв через запятую, а в генераторе для этого есть кнопка «Добавить слой».

Заодно держите прозрачность низкой. Чёрный на 10–30% через rgba() читается как глубина; сплошная серая тень — как грязное пятно. Если тень выглядит грязно, дело почти всегда в непрозрачности, а не в размере.

inset выворачивает свет

Добавьте ключевое слово inset — и тень нарисуется внутри элемента, будто блок вдавили в страницу. Обычные клиенты этого режима — поля ввода, углубления под переключатели и нажатые кнопки. Все четыре длины работают так же, меняется только направление иллюзии.

Две привычки напоследок

Не анимируйте box-shadow на hover напрямую: браузер перерисовывает размытие каждый кадр, и на крупных элементах это заметно. Положите большую тень на псевдоэлемент и анимируйте его opacity.

А когда тень не даётся — соберите её глазами. Откройте генератор CSS-теней, подберите смещение и размытие по превью, добавьте второй слой, если глубина кажется плоской, и скопируйте готовую строку прямо в таблицу стилей. Всё работает в браузере, ставить ничего не нужно.

Попробуйте инструмент

Генератор CSS-теней →