Смягчение теней с помощью слоёв в CSS-свойстве box-shadow

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

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

box-shadow
0 6px 6px rgba(0,0,0,0.4);
слоёная box-shadow
постепенное увеличение смещения/размытия

Квадратным и неуклюжим выглядит эффект от box-shadow по умолчанию (первый блок) по сравнению с многослойной тенью (второй блок). Такого эффекта, как у второго блока, можно добиться, если для него сделать несколько описаний (разделяя каждое запятой) и увеличивать смещение и размытие для каждой следующей тени (синтаксис box-shadowX-смещение Y-смещение размытие цвет):

/* box-shadow по умолчанию */
.box-shadow-default {
  box-shadow: 0 6px 6px rgba(0,0,0,0.4);
}

/* Гладкая box-shadow с несколькими слоями теней
 * с увеличением смещения и размытие для каждой следующей */
.box-shadow-smooth {
  box-shadow: 0 1px 1px rgba(0,0,0,0.12), 
              0 2px 2px rgba(0,0,0,0.12), 
              0 4px 4px rgba(0,0,0,0.12), 
              0 8px 8px rgba(0,0,0,0.12),
              0 16px 16px rgba(0,0,0,0.12);
}

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

слоёная box-shadow
4 слоя с прозрачностью 15%
слоёная box-shadow
6 слоёв с прозрачностью 11%

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

.shadow-4 {
  box-shadow: 0 1px 1px rgba(0,0,0,0.15), 
              0 2px 2px rgba(0,0,0,0.15), 
              0 4px 4px rgba(0,0,0,0.15), 
              0 8px 8px rgba(0,0,0,0.15);
}

.shadow-6 {
  box-shadow: 0 1px 1px rgba(0,0,0,0.11), 
              0 2px 2px rgba(0,0,0,0.11), 
              0 4px 4px rgba(0,0,0,0.11), 
              0 8px 8px rgba(0,0,0,0.11), 
              0 16px 16px rgba(0,0,0,0.11), 
              0 32px 32px rgba(0,0,0,0.11);
}

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

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

резкая box-shadow
с уменьшением прозрачности
рассеянная box-shadow
с увеличением прозрачности

Для более резкой тени ниже самая внутренняя тень (с наименьшим смещением и размытием) имеет наивысшее значение прозрачности, и оно уменьшается с каждым слоем. И наоборот для рассеянной тени второго блока, где самый внутренний слой имеет самое низкое значение прозрачности:

.shadow-sharp {
  box-shadow: 0 1px 1px rgba(0,0,0,0.25), 
              0 2px 2px rgba(0,0,0,0.20), 
              0 4px 4px rgba(0,0,0,0.15), 
              0 8px 8px rgba(0,0,0,0.10),
              0 16px 16px rgba(0,0,0,0.05);
}

.shadow-diffuse {
    box-shadow: 0 1px 1px rgba(0,0,0,0.08), 
                0 2px 2px rgba(0,0,0,0.12), 
                0 4px 4px rgba(0,0,0,0.16), 
                0 8px 8px rgba(0,0,0,0.20);
}

Можно смелее увеличивать размытие, чтобы расширить распространение и ещё больше смягчить эффект тени:

Тень ещё мягче
увеличение шага прозрачности

Тень становится ещё мягче с увеличением шага изменения прозрачности:

.shadow-dreamy {
    box-shadow: 0 1px 2px rgba(0,0,0,0.07), 
                0 2px 4px rgba(0,0,0,0.07), 
                0 4px 8px rgba(0,0,0,0.07), 
                0 8px 16px rgba(0,0,0,0.07),
                0 16px 32px rgba(0,0,0,0.07), 
                0 32px 64px rgba(0,0,0,0.07);
}

Наконец, можно управлять длиной тени.

короткая тень
с меньшим расстоянием
длинная тень
с большим расстоянием

Надо разделить радиус размытия и смещение по оси Y и увеличивать смещение с большим или меньшим шагом:

.shadow-shorter {
  box-shadow: 0 1px 1px rgba(0,0,0,0.11), 
              0 2px 2px rgba(0,0,0,0.11), 
              0 4px 4px rgba(0,0,0,0.11), 
              0 6px 8px rgba(0,0,0,0.11),
              0 8px 16px rgba(0,0,0,0.11);
}

.shadow-longer {
  box-shadow: 0 2px 1px rgba(0,0,0,0.09), 
              0 4px 2px rgba(0,0,0,0.09), 
              0 8px 4px rgba(0,0,0,0.09), 
              0 16px 8px rgba(0,0,0,0.09),
              0 32px 16px rgba(0,0,0,0.09);
}

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