Сегодня поговорим о вертикальном выравнивании, как его добиться и чего не забыть учесть.
Тема понятна, приступим.
Для наглядности возьмём пример кода из прошлого поста и немного изменим, убрав обтекание у картинки и обернув её и текст тегами <div>, немного приведём в порядок внешний вид и сделаем заготовку для нашего класса вертикального выравнивания:
Посмотрим на результат:
Тема понятна, приступим.
Для наглядности возьмём пример кода из прошлого поста и немного изменим, убрав обтекание у картинки и обернув её и текст тегами <div>, немного приведём в порядок внешний вид и сделаем заготовку для нашего класса вертикального выравнивания:
<div class="preview"> <div class="v-block img-wrap"> <img src="/google.logo.png" /> </div> <div class="desc"> Это Google. Лидер мирового поиска. Lorem ipsum dolor sit amet, aliquam pellentesque nunc et quam elementum ornare. Quisque tortor sapien, aliquam in luctus a, fringilla ac ante. Suspendisse potenti. Mauris faucibus justo tortor. </div> </div>
.preview { background:#F3F3F3; border: 1px solid #E5E5E5; float: left; font: 13px/16px Tahoma; margin: 40px 0 40px 40px; overflow: hidden; padding: 10px; } .preview .v-block { } .preview .img-wrap { height:150px; text-align: center; width:250px; } .preview .img-wrap img { background: #FFFFFF; border: 1px solid #CDCDCD; margin:0; max-width: 250px; } .preview .desc { text-align:center; margin-top:10px; }
Посмотрим на результат:
И снова у нас всё отлично, классно и замечательно :-)
А теперь представим ситуацию, когда нам нужно, чтобы таких блоков было несколько и все они шли бы друг за другом:
<div class="preview"> <div class="img-wrap v-block"> <img src="/google.logo.png" /> </div> <div class="desc">Это Google. Лидер мирового поиска.</div> </div> <div class="preview"> <div class="img-wrap v-block"> <img src="/ya.logo.png" /> </div> <div class="desc"Это Яндекс. До Google ему далеко.</div> </div> <div class="preview"> <div class="img-wrap v-block"> <img src="/bing.logo.png" /> </div> <div class="desc">Это Bing. Тоже не конкурент.</div> </div>
Результат:
В принципе красиво, терпимо. Но, так как, тема у нас - вертикальное выравнивание в блоках, то давайте попробуем выровнять изображения по середине блока.
Какие у нас есть варианты?
Первое, что приходит на ум - vertical-align:middle. Давайте его и использовать.
Сперва читаем описание.
Применяется: к встроенным элементам или ячейкам таблицы.
middle: Выравнивание средней точки элемента по базовой линии родителя плюс половина высоты родительского элемента.
Что это значит?Применительно к таблицамmiddle: Выравнивает по середине ячейки
Так как вертикальное выравнивание применяется к встроенным, т.е. inline-элементам или ячейкам таблицам, то нам этот вариант не подходит. Потому что у нас элемент по умолчанию блочный и он, естественно, не является ни таблицей, ни её ячейкой.
Но на помощь нам придёт замечательное свойство display, одним из значений которого является table-cell. Т.е. задав нашему блоку .v-block это свойство, мы скажем браузеру, что его необходимо расценивать как ячейку таблицы, соответсвенно нам будут доступны все сопутствующие css-плюшки, в том числе и выравнивание по середине ячейки.
Пробуем. Добавим необходимые свойтва в css:
.preview .v-block { display: table-cell; vertical-align: middle; }
Смотрим результат:
Отлично! Именно так, как и планировалось.
Но вот незадача - наши любимые IE6 и IE7 не понимают значение table-cell для свойства display, а значит в этих браузерах всё будет по старому. Конечно, можно (и нужно!) отказываться от поддержки старых браузеров, но на больших коммерческих проектах, где важен наибольший обхват аудитории, этот номер не пройдёт - в требованиях к таким проектам всегда стоИт как минимум поддержка IE7.
Но решение есть, и если оно есть, то почему бы его не использовать? :-)
На помощь к нам спешит css-expression! Не будем особо мудорствовать, сразу приведу код:
* html .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); } *+html .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); }
Что же у нас здесь такое? Давайте по порядку.
Сперва определимся со странным набором css-селекторов: * html .v-block img и *+html .v-block img.
Это так называемые css-хаки. В первом случае * html - это хак, который воспринимает только IE6, во втором - *+html - хак для IE7.
Лирическое отступление. Немного про css-хаки.
Те хаки, которые я привёл, проходят проверку на валидность кода, но существует ещё множество различных хаков как для всеми любимого ослика, так и для остальных браузеров, которые эту проверку не проходят. Вообще эта тема довольно обширная и расписывать её - тема для отдельной статьи.Единственно, что хотелось бы отметить, так это необходимость создания отдельных персонализированных стилей для IE как 6й, так и 7й версии и подключение их через conditional comments. Такой способ даёт сразу несколько плюсов:
- чистота основного css-кода;
- такой документ будет проходить проверку на валидность;
- пользователям остальных браузеров не надо будет грузить лишний код (когда количество таких персональных стилей перерастёт все мыслимые пределы).
- не надо помнить все хаки наизусть, потому что в css-файлах, подключенных через CC, писать их уже не нужно.
Лично я за валидностью не гонюсь, но и пренебрагать ею не стараюсь. Поэтому, когда на просторах интернета встретил такую конструкцию:
<!doctype html> <!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]--> <!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]--> <!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> <head> <script> (function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement); </script> ... </head>
я сразу в неё влюбился и сразу стал использовать практически во всех своих проектах.
Плюс такого подхода в том, что не надо держать несколько файлов стилей отдельно для IE, отдельно для его версий и отдельно для остальных браузеров.
Применительно к нашей вёрстке, используя такой подход, получилось бы вот так:
.ie6 .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); } .ie7 .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); }
Удобно, не правда ли? К тому же есть возможность назначить стили всем версиям ie вплоть до 8й, используя класс .oldie, и назначать отдельные стили для пользователей с отключенным javascript прямо не отходя от кассы, т.е. в нашем же файле стилей.
Давайте дальше.
Так что же это за expression и что он делает?
margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px");
Здесь всё просто. Используя возможность использования динамических расчётов в IE, мы производим расчёт, исходя из условия:
(parentNode.offsetHeight - this.offsetHeight)<0если разница в высотах родительского элемента (в нашем случае .v-block) и дочернего изображения < 0 (т.е. изображение и родительский блок одинаковы по высоте или изображение выше), то
? "0"устанавливаем верхний отступ равным 0 (само собой, ведь если изображение выше, то отступ ему не нужен).
А если изображение все же меньше высоты родительского блока, то
: (parentNode.offsetHeight - this.offsetHeight)/2 + "px");высчитываем верхний отступ по нехитрой формуле как разница высот, поделённая пополам.
Проверяем в IE и вуаля:
Всё работает!
Теперь, чтобы использовать возможность выравнивать изображения в блочной вёрстке, просто заведите себе класс .v-block и подключайте его там, где необходимо.
.preview .v-block { display: table-cell; vertical-align: middle; } * html .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); } *+html .v-block img { display: block; margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px"); }
До новых рецептов!
Комментариев нет:
Отправить комментарий