Xiper

Тень для блока

Автор: Андрей Косяк и Евгений Рыжков Дата публикации:

Задача

Организовать тень для блока, не используя изображения.

тень для блока без картинок

Немного риторики

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

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

После выхода Opera 10.50 на реализацию тени можно посмотреть теперь и со стороны CSS3. А именно, используя box-shadow. Итак...

Решение

Свойство box-shadow в деталях расписывать не буду, скажу лишь, что общий вид правила такой: box-shadow: 0px 0px 10px #000;, где первые два значения — сдвиг тени, третье — радиус размытия и последнее — цвет. В деталях о свойстве читай в нашем справочнике.

Пойдем по порядку и начнем, пожалуй, не с ИЕ :) (кстати, ничего особо плохого, как ни странно, я не имел ввиду). Наш блок:

<div class="mainContainer">
</div>
.mainContainer {
	width:30%;
	height: 30%;
	position: absolute;
	top: 35%;
	left: 35%;
	border: 1px solid #000;
	background: #fff;
}

"Адекваты"

chrome и safariGoogle Chrome и Safari работают на движке WebKit, box-shadow в "чистом" виде пока не работает, но экспериментальное свойство -webkit-box-shadow вполне рабочее.

firefoxУ Firefox похожая ситуация, с версии 3.5 поддерживает это свойство, правда тоже экспериментально с приставкой -moz-.

operaC Opera ситуация чуть хуже, поскольку только с версии 10.5 она понимает полноценный box-shadow. Думаю, что через некоторое время о версиях оперы ниже 10.5 можно будет не вспоминать, поскольку пользователи довольно активно обновляются (все же не ИЕ). Хотя, по большому счету, это относится ко всем перечисленным выше браузерам.

В итоге добавляем в css:

.mainContainer {
    width:30%;
    height: 30%;
    position: absolute;
    top: 35%;
    left: 35%;
    border: 1px solid #000;
    background: #fff;
    -webkit-box-shadow: 0 0 30px #969696;
    -moz-box-shadow: 0 0 30px #969696;
    box-shadow: 0 0 30px #969696;
}

Вуаля! Очень даже симпотненькая тенька. Результат.

Племя "Вуду"

Поговорили о прелестях CSS3, вдохнули свежего воздуха и ладушки. Возвращаемся на фронт, нюхать порох и вкушать прелести "Священной войны"...

племя IEИменно! Я о клане туземцев "IE". У них своя культура, и они не признают всякие новшества и диковинки привезенные с "большой земли". Зато они обладают тайными магическими знаниями, а это могучие знания, которые не раз спасали племя от вымирания...

Конечно же речь идет о фильтрах. У ИЕ имеются фильтры shadow и dropShadow... забудем о них, это топор, а не тень. А вот фильтр Blur — в самый раз, на нём и остановимся. Выглядит он вот так:

filter:progid:DXImageTransform.Microsoft.Blur(PixelRadius="23", MakeShadow="true", ShadowOpacity=".5");

где PixelRadius — радиус размытия, MakeShadow — ставим в true, ShadowOpacity — прозрачность.

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

<div class="mainContainer">
<!--[if IE]>
    <div class="shadow"></div>
<![endif]-->
    <div class="content">[тут какой-то контент]</div>
</div>

Фишка в том, что Blur "размоет" блок, на который мы его наложим(а накладывать мы его будем на блок shadow) и он, собственно, превратится в сплошную тень. Затем мы просто блок-тень подложим под блок-контент. Блок с классом shadow заключаем в условный комментарий, поскольку он нам нужен только для ИЕ в качестве тени. Меняем немного стили:

.mainContainer {
	position: relative;
	margin: 100px 0 0 100px;
	-webkit-box-shadow: 0 0 30px #969696;
	-moz-box-shadow: 0 0 30px #969696;
	box-shadow: 0 0 30px #969696;
	float: left;
	zoom: 1;
}
* html .mainContainer { /* устраняем для IE6 баг с высотой тени */
	height: 1px;
}
.content {
	width: 500px;
	border: 1px solid #000;
	background: #fff;
	padding: 20px;
	zoom: 1;
	position: relative;
	z-index: 2;
}
.shadow {
	width:100%;
	height: 100%;
	position: absolute;
	z-index: 1;
	top: -15px;
	left: -15px;
	background: #fff;	
	filter:progid:DXImageTransform.Microsoft.Blur(PixelRadius='15', MakeShadow='true', ShadowOpacity='.4');	
}

Результат. В итоге имеем общий контейнер mainContainer, который мы сможем со спокойной совестью позиционировать, и внутри блок content, который, если нужно, будет задавать размеры своему родителю. Ну, и в случае ИЕ — в коде окажется еще один блок — тень.

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

Проверено в:

Преимущества

  • ни одного изображения для тени — быстрей будет грузится страница
  • возможно кроссбраузерно сделать тень как минимум с большой схожестью на дизайн
  • небольшое количество "лишних" элементов в коде
  • на верстку тени уходит в разы меньше времени, нежели верстка картинками
  • не забываем, что CSS тень не влияет на размеры блока, что еще упрощает работу кодера с этим блоком
  • меньше станет багов с анимациями в IE, которые ой как не любят картинок в плавно появляющихся/скрывающихся блоках (ососбенно это касается картинок png-24)

Недостатки

  • не смотря на тот факт, что пользователи активно обновляют "адекватные" браузеры, нельзя 100% гарантировать, что этот способ сработает у всех. По крайней мере еще некоторое время (жаль пользователей Opera 9, но они тени не увидят)
  • хотелось бы обойтись без дополнительных элементов в коде, но, увы, ИЕ нам не даёт покоя
  • наличие фильтра для IE несколько снижает производительность браузера
  • CSS код не пройдет валидацию из-за наличия в коде фильтров и вендорных CSS свойств, но при большом желании и использовании условных комментариев (для фильтров и zoom) и javascript (для динамической установки вендорных свойств) этот недостаток можно устранить

Заметки

На практике могут быть сюрпризы от ИЕ, как ни странно, но мне в недавнем проекте доставил неприятности ИЕ8. А именно отказался накладывать фильтр. Я решил этот момент включением режима совместимости:

<meta http-equiv="X-UA-Compatible" content="IE=7" /> 

Это нужно вставлять в теге <head> самым первым. Но, повотрюсь, это исключение, хотя подозреваю, что сюрпризы могут быть разные. В примерах этой статьи все отработало безупречно, без лишних телодвижений

  • в реальных проектах можно "подчистить" код, путём динамического добавления блоков shadow и content, тем самым избавиться от условного комментария и оставить в коде всего один целевой блок
  • в примере был рассмотрен блок, в котором тень равномерная, а часто встречаются дизайны, где тень смещена в каком-то направлении. Свойство box-shadow позволяет управлять смещением первыми двумя параметрами, а в случае ИЕ нужно будет двигать блок shadow

Update by Ksayri: для IE появилось более элегантное решение — javascript плагин PIE, который способен отрисовать тень средствами VML:

.mainContainer {
	position: relative;
	margin: 100px 0 0 100px;
	-webkit-box-shadow: 0 0 30px #969696;
	-moz-box-shadow: 0 0 30px #969696;
	box-shadow: 0 0 30px #969696;
	float: left;
}

А для IE6-8 (IE9 будет поддерживать box-shadow) добавляем правило:

.mainContainer {
	behavior: url(path-to/PIE.htc);
}

Преимущества:

  • чистый HTML код;
  • отсутствие фильтров, замедляющих работу браузера;
  • простота реализации.