Тень для блока
Задача
Организовать тень для блока, не используя изображения.
Немного риторики
В общем-то, тень для блока, практически любой сложности, реализуема картинками. Погуглив можно найти массу решений. Но у данного метода есть ряд существенных недостатков:
- немерянное количество дополнительных элементов и блоков. Одно дело, когда блок, которому нужно нарисовать тень статичный и совсем другое, когда блок должен быть полностью резиновым. К тому же все больше привыкаешь к "чистому" коду и порой просто пальцы не поднимаются насыпать в него несколько лишних блоков.
- несколько дополнительных картинок -> дополнительные запросы к серверу -> уменьшение скорости загрузки страницы + дополнительный трафик + дополнительная нагрузка на сервер
После выхода 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; }
"Адекваты"
Google Chrome и Safari работают на движке WebKit, box-shadow в "чистом" виде пока не работает, но экспериментальное свойство -webkit-box-shadow вполне рабочее.
У Firefox похожая ситуация, с версии 3.5 поддерживает это свойство, правда тоже экспериментально с приставкой -moz-.
C 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". У них своя культура, и они не признают всякие новшества и диковинки привезенные с "большой земли". Зато они обладают тайными магическими знаниями, а это могучие знания, которые не раз спасали племя от вымирания...
Конечно же речь идет о фильтрах. У ИЕ имеются фильтры 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 код;
- отсутствие фильтров, замедляющих работу браузера;
- простота реализации.