Создание тени по типу «луковой шелухи»
Перевод: Влад Мержевич и Евгений Богомольный.
Да, «луковая шелуха». Аниматоры используют этот эффект, чтобы показать то, что обычно невозможно увидеть: кадры движения во времени. И теперь веб-дизайнеры могут использовать подобный эффект, чтобы показать другую кажущуюся невозможность: создание реалистичной тени с использованием CSS.
Особенности
Есть несколько отличий между данной методикой и методиками, предлагаемых ранее. Некоторые пользователи найдут описанную в этой статье технику более простой, другие — более стабильной, но в любом случае, наш вариант имеет больше преимуществ, таких как:
- не требует определения ширины слоя (параметра width);
- позволяет модифицировать глубину тени без манипуляций с изображением;
- одинаково отображается во всех браузерах.
Чистим луковицу
«Луковая шелуха» используется при создании анимации для наложения кадров последовательности движения друг на друга, чтобы можно было заметить небольшие различия между отдельными кадрами. Аниматор просто просматривает набор слоев, чтобы увидеть одно целое движение через композицию его частей. Непрозрачные области на одном слое могут быть замечены на прозрачном слое выше него. Мы можем сделать то же самое и с тегом <DIV>. Используя CSS, допустимо наложить друг на друга несколько элементов <DIV> подобно луковице и таким образом получить желаемую композицию. В частности, создать тень (рис. 1).

Рис. 1. Изометрическая проекция слоев в виде «луковой шелухи»
Три слоя, каждый из которых содержит фрагмент изображения тени, накладываясь друг на друга, позволяют получить единую тень. Просто поместите ваш объект внутри трех контейнеров <DIV> и каждому из них дайте название класса, которое соответствует его роли. В примере 1, в частности, используются имена wrap1, wrap2 и wrap3 (класс wrap1 соответствует внешнему слою, а wrap3 — внутреннему).
Пример 1. Структура слоев для создания тени
<div class="wrap2">
<div class="wrap3">
<img src="object.gif" alt="Рисунок с тенью">
</div>
</div>
</div>
Код CSS сложнее кода HTML, но не намного. В основном, для создания тени требуется пройти три шага, которые выполняются через правила стиля.
- Отображение тени. Следует установить каждое из трех изображений для создания тени (собственно тень и два уголка к ней) на определенный слой.
- Отбрасывание тени. Требуется задать смещение изображений вправо и вниз на определенное расстояние.
- Размер по объекту. Тень должна соответствовать размерам объекта.
Шаг 1. Отображение тени
Основная идея состоит в том, чтобы сопоставить каждый из трех компонентов изображения тени своему контейнеру <DIV> через соответствующий класс. Цель применения трех изображений состоит в том, чтобы использовать два маленьких рисунка для маскирования среза края тени и создания плавного закругления краев. Для этого один рисунок помещается в правый верхний угол тени от объекта, а второй — в левый нижний.
Чтобы один рисунок находился поверх другого и маскировал его, необходимо изменить его положение с помощью стилевого параметра z-index. На самом деле волноваться по этому поводу не стоит, т.к. вложенная структура тегов <DIV> работает на нас и позволяет автоматически получить нужный порядок. Мы просто назначаем класс с тенью самому нижнему тегу <DIV> в наборе слоев. Поскольку нижние теги <DIV> будут располагаться наверху, то им присвоим классы, которые отображают уголки тени (пример 2).
Пример 2. Стили для отображения рисунков с тенью
background-image: url(shadow.gif);
}
.wrap2 {
background-image: url(corner_bl.gif);
}
.wrap3 {
background-image: url(corner_tr.gif);
}
Когда мы назначаем требуемый рисунок к нужному классу, следует установить для него позиционирование с помощью свойства background-position. Если мы оставим его значение по умолчанию, то все, что мы увидим — это повторяющийся рисунок corner_tr.gif, поскольку слой с ним находится наверху набора слоев. Помните, техника «луковой шелухи» требует прозрачности верхних слоев, чтобы мы могли бы увидеть то, что находится ниже них. Для этого следует отменить повторение фонового рисунка с помощью значения no-repeat и позиционировать рисунок в нужном месте композиции.
Здравый смысл говорит нам, что изображение с именем corner_tr.gif должно находиться в правом верхнем углу, в то время как corner_bl.gif — в левом нижнем. Но что касается основного рисунка с тенью (shadow.gif), надо ли позиционировать и его? Факт — надо. Если мы хотим, чтобы тень отбрасывалась правее и ниже любого объекта, то следует определить ее положение в классе wrap1. В противном случае рисунок заполнит элемент <DIV> относительно его верхнего левого угла, т.е. совсем не там, где он требуется.
Основной слой — DIV.wrap1
Внешний <DIV> содержит самый большой из трех компонентов тени (файл shadow.gif), который позиционирован по правому и нижнему краю (пример 3).
Пример 3. Стиль для основного слоя
background: url(shadow.gif) right bottom no-repeat;
}
На рис. 2 показано содержимое слоя и требуемый графический файл.

Рис. 2. Содержимое слоя wrap1
Средний слой — DIV.wrap2
Второй <DIV>, вложенный внутри первого, маскирует срез левого нижнего края тени и устанавливает плавное закругление (пример 4).
Пример 4. Стиль для среднего слоя
background: url(corner_bl.gif) left bottom no-repeat;
}
На рис. 3 показано содержимое слоя и требуемый графический файл.

Рис. 3. Содержимое слоя wrap2
Внутренний слой — DIV.wrap3
Третий <DIV>, вложенный внутри второго, занимается срезом верхнего правого края тени.
Пример 5. Стиль для внутреннего слоя
background: url(corner_tr.gif) right top no-repeat;
}
На рис. 4 показано содержимое слоя и требуемый графический файл.

Рис. 4. Содержимое слоя wrap3
Шаг 2. Отбрасывание тени
Следующий шаг для CSS — смещение тени, которое создает эффект ее отбрасывания. Проще не бывает. Все что требуется — это добавить параметр padding, который устанавливает поля слева и снизу для самого нижнего слоя. Когда padding применяется к тегу <DIV>, то он изменяет размеры объекта, и остальные два слоя изменяются вместе с ним. Как результат, все три компонента тени, расположенные по правой и нижней стороне этих слоев, смещаются одновременно. Теперь их можно увидеть через пустой промежуток, созданный с помощью атрибута padding (пример 6).
Пример 6. Использование полей для отбрасывания тени
padding: 0px 4px 4px 0px;
background: url(corner_tr.gif) right top no-repeat;
}
Результат данного примера продемонстрирован на рис. 5.

Рис. 5. Использование смещения содержимого
Модификация смещения
Изменение величины смещения тени делается почти также просто, как и замена значений параметра padding для слоя wrap3. Мы говорим «почти», поскольку настройка значения padding просто перемещает тень, в то время как уголки продолжают прижиматься к краям контейнеров. Чтобы точно смоделировать смещение тени, для обоих уголков следует использовать атрибут background-position.
Некоторые разработчики сказали бы, что достаточно настроить значение padding и остановиться на этом. Нет смысла усложнять себе жизнь вниманием к мелким деталям, когда большинство пользователей их просто не заметит. Другие бы привели аргумент, что срезанные уголки снижают эффект производимый тенью. Если метод технически и эстетически позволяет добиться желаемой точности, то разработчику грех не воспользоваться заложенным потенциалом. Тем не менее, каждый выбирает свой собственный путь.
Судите сами. Рис. 6 используется ниже для демонстрации двух видов тени.

Рис. 6. Исходное изображение для создания тени
Все образцы в обоих наборах используют одинаковое значение свойства background-image. Иными словами, одни и те же графические изображения применяются к каждому образцу. Различается только степень смещения тени.
В наборе 1 сдвиг тени регулируется только значением параметра padding для слоя wrap3, при этом перемещается только сама тень без уголков. В наборе 2 значения padding и background-position изменяются таким образом, чтобы одновременно смещалась тень и ее уголки.
![]() |
![]() |
![]() |
| 8 пикселов | 12 пикселов | 18 пикселов |
![]() |
![]() |
![]() |
| 8 пикселов | 12 пикселов | 18 пикселов |
Если вы замечаете различия между приведенными наборами и предпочитаете второй вариант, то к стилю уголков следует прибавить параметр background-position и настроить его значение таким образом, чтобы компенсировать влияние атрибута padding. Далее к изображению уголков с внешней стороны следует добавить пустое белое пространство. Это позволяет рисунку перемещаться на достаточно большое расстояние от границы слоя, без того, чтобы не терять способность маскировать край тени. Каждый вид тени немного отличается от другого, и как только вы начнете экспериментировать со смещением, то сразу станет понятно, на какую величину следует увеличить белое пространство у картинки с уголками.
Шаг 3. Размер по объекту
Потребуется небольшая ловкость рук, чтобы убедить браузер устанавливать тень по ширине объекта. Без этого потребовалось бы вычислять ширину, чтобы корректно добавить тень.
В большинстве браузеров <DIV> принимает размер объекта, когда для него добавляется параметр float. Данный способ подойдет, но только не в том случае, если вы используете Internet Explorer 5 под Macintosh. Простой факт, что есть люди, которые пользуются этим браузером, заставил поискать альтернативное решение. К сожалению, ни одно не было найдено, по крайней мере, такое, которое было бы универсальным.
Некоторое экспериментирование показало, что использование значения inline-table атрибута display может спасти ситуацию. Так, применение комментариев совместно со слэшем (/* */display: block/**/) позволяет скрыть этот код от браузера Internet Explorer 5 под Macintosh, «подсовывая» ему строку display: inline-table, в то время как остальные браузеры «видят» параметр float: left. Таким образом, получается, что «размер по объекту» работает во всех браузерах (рис. 6).

Рис. 6. Конечный результат
В итоге CSS с учетом всех трех шагов показан в примере 7.
Пример 7. Окончательный стиль для создания тени
display: inline-table;
/* */display: block/**/
}
.wrap1 {
float: left;
background: url(shadow.gif) right bottom no-repeat;
}
.wrap2 {
background: url(corner_bl.gif) left bottom no-repeat;
}
padding: 0px 4px 4px 0px;
background: url(corner_tr.gif) right top no-repeat;
}
Еще один стиль для хорошего тона
Как было показано в примерах выше, изображения достаточно часто используются с приведенной техникой. В подобном случае для рисунка, к которому добавляется тень, следует установить свойство display со значением block. Во многих случаях это поможет избежать наложения элементов друг на друга. Просто добавьте следующий стиль (пример 8).
Пример 8. Стиль для изображений
display: block;
}
Комментарии переводчика
В данной статье Брайан Уильямс изложил свою универсальную методику создания тени на основе слоев. Однако многие читатели хотели бы видеть не принцип добавления тени к объекту, а готовый код, который с легкостью можно скопировать и модифицировать «под себя». Для таких людей и написан приведенный далее текст.
Итак, вам понадобится три рисунка: собственно сама тень (рис. 7), правый верхний уголок (рис. 8) и левый нижний уголок (рис. 9).

Рис. 7. Изображение тени (файл shadow.gif)
![]()
Рис. 8. Изображение правого верхнего уголка (файл corner_tr.gif)
![]()
Рис. 9. Изображение левого нижнего уголка (файл corner_bl.gif)
Рамка вокруг рисунков приведена для наглядности и естественно к картинкам не добавляется. Ширина изображения тени зависит от цели ее использования, например, если планируется устанавливать тень для рисунков шириной не более 600 пикселов, то имеет смысл сделать такой же размер и у тени.
Код для формирования тени с помощью приведенных картинок и методики «луковой шелухи» показан в примере 9.
Пример 9. Создание тени

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Создание тени</title>
<style type="text/css">
.wrap1 {
display: block;
background:
url(images/shadow.gif) /* Рисунок с тенью */
no-repeat /* Отменяем повторение фона */
right bottom; /* Размещаем тень в правом нижнем углу */
float: left; /* Создание обтекания для правильного положения тени */
}
.wrap2 {
display: block;
background: url(images/corner_bl.gif)
no-repeat /* Отменяем повторение рисунка */
left bottom; /* Располагаем в левом нижнем углу */
background-position: /* Положение уголка тени */
-15px /* Смещаем уголок, чем меньше значение, тем левее располагается уголок */
100%;
}
.wrap3 {
display: block;
padding:
0
12px /* Ширина тени справа */
12px /* Высота тени снизу */
0;
background:
url(images/corner_tr.gif) /* Правый верхний уголок тени */
no-repeat /* Отменяем повторение рисунка */
right top; /* Располагаем в правом верхнем углу */
background-position: /* Положение уголка тени */
100%
-15px; /* Смещаем уголок, чем меньше значение, тем выше уголок */
}
.wrap3 IMG {
display: block;
}
</style>
</head>
<body>
<div class="wrap1">
<div class="wrap2">
<div class="wrap3"><img src="images/pic.jpg" width="72" height="72" alt="Картинка"></div>
</div>
</div>
</body>
</html>
Параметры, которые управляют положением тени относительно объекта, подбираются экспериментально, исходя из собственных предпочтений и дизайна сайта.
| Статья опубликована: 25.04.2006 | Последнее обновление: 02.05.2008 |
Прежде, чем писать комментарий к статье, примите во внимание следующие моменты.
- Не задавайте вопросы в комментариях, для этой цели предназначен форум, где вы получите нужную помощь.
- Удаляются любые комментарии, которые:
- включают множество ошибок;
- написаны безграмотно;
- не имеют отношения к данной статье;
- не содержат никакой полезной информации для посетителей.
- Для выделения отдельных слов используйте следующие команды: [b]жирный[/b], [i]курсив[/i], [color=цвет]цветной текст[/color], [tag]тег[/tag], [var]параметр[/var], [code]пример[/code].
- Потренироваться в написании комментариев вы можете в песочнице.
Комментарии к статье
Владислав
05.05.2006
Не могли ли бы Вы выложить этот пример в качестве сверстанного html документа чтобы все было более наглядно?
Заранее благодарю.
Влад Мержевич
05.05.2006
Влад Мержевич
11.05.2006
Денис Левченко
20.07.2006
Везде искал, а здесь вс? и про вс?.
Очень помогает
Александр
18.08.2006
Влад Мержевич
21.08.2006
Virtual Spirit
30.08.2006
elanc
26.09.2006
Весь пакет подключать не советую использовать -- появляются проблемы с FF, да и страницы станут слишком "тяжелыми"..
Witty
03.11.2006
#Image1 {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=`crop`, src=`img/image1.png`);
}
3bepek
12.02.2007
в стили добавляем строку:
* {filter:expression(fixPNG(this));}
и такой скриптик еще юзаем:
function fixPNG(element)
{
if (/MSIE (5.5|6).+Win/.test(navigator.userAgent))
{
var src;
if (element.tagName==`IMG`)
{
if (/.png$/.test(element.src))
{
src = element.src;
element.src = "decoration/blank.gif";
}
}
else
{
src = element.currentStyle.backgroundImage.match(/url("(.+.png)")/i)
if (src)
{
src = src[1];
element.runtimeStyle.backgroundImage="none";
}
}
if (src) element.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=`" + src + "`,sizingMethod=`scale`)";
}
}
3bepek
12.02.2007
это путь к файлу blank.gif - однопиксельный прозрачный гиф
3bepek
12.02.2007
Wink
22.02.2007
Влад Мержевич
02.03.2007
eugenijus
23.06.2007
X
03.07.2007
Андрей
13.07.2007
Что не работает твоя метода. Не пояснишь что к чему?
Anton
06.05.2008
.wrap3 {
padding: 0px 4px 0px 0px;
нормально, но в 9-й опере тень съезжает вверх на 4 пиксела, короче внизу тени не видно
ставишь
.wrap3 {
display: block;
padding: 0px 4px 4px 0px;
background: url(corner_tr.gif) right top no-repeat;
}
в 9-й опере нормально, в IE7 тень съезжает вниз на 4 пиксела, короче внизу уже видно 8 пикселов
IE6 не поддерживает альфа PNG24, короче получается не тень, а белая фигня, с GIF как у вас такая же фигня, т.к. фон страницы может быть разным, и белые тени не везде смотрятся
Вывод: какие же придурки браузеры придумывали вобще?
и вобще HTML это ошибка, на мо?м мониторе 1680x1050 22" шрифт на некоторых сайтах уже не видно, т.к. он мелкий, но можно игнорировать шрифт в настройках браузера, тогда съезжает дизайн
про шапки сайтов в 100пикселов, их вобще не видно
при ещ? большем мониторе с большим количеством точек, но меньшем размере точек вобще нич? не видно будет
дак нафига это надо? не проще типа Word или PDF сайты делать? там хоть размер А4 фиксированный можно было всем договориться сделать и вс?, а по длине неважно хоть сколько
naruto
15.05.2008
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Создание тени</title>
<style type="text/css">
.wrap1 {
display: block;
background:
url(r.gif)
repeat-y
right top;
float:left
}
.wrap2 {
display: block;
background: url(b.gif) repeat-x
left bottom;
}
.wrap3 {
display: block;
background:
url(vr.gif) no-repeat
right top;
}
.wrap4 {
display: block;
background:
url(nl.gif) no-repeat
left bottom;
}
.wrap5 {
display: block;
background:
url(ugol.gif) no-repeat
right bottom;
padding:0px;
padding-right:12px;
padding-bottom:12px;
}
.wrap3 IMG {
display: block;
}
</style>
</head>
<body>
<div class="wrap1">
<div class="wrap2">
<div class="wrap3">
<div class="wrap4">
<div class="wrap5"><img src="1.jpg" width="200" height="200" alt="Картинка"></div>
</div>
</div>
</div>
</div>
</body>
</html>
, где:
r.gif - картинка размером 12х30 px - правая сторона тени
b.gif - картинка размером 30х12 px - нижняя сторона тени
nl.gif - картинка размером 12х12 px - нижний левый угол
vr.gif - картинка размером 12х12 px - верхний правый угол
ugol.gif - картинка размером 12х12 px - нижний правый угол
