Еще один способ вертикального выравнивания в CSS
Много копий сломано на ниве вертикального выравнивания без таблиц. Однако недавно я узнал о еще одном более простом способе. Этот пост, перевод статьи уважаемого мною Gunlaug о вертикальном выравнивании без дополнительного HTML и с помощью правда другого зла.
Оригинальная статья: fully centered across browser-land…
Задача
Отцентрировать что-нибудь вертикально внутри какого-либо элемента(экрана например).
Возьмем такой вот HTML:
- <div id="out">
- <p id="centered" >…</p>
- </div>
Будем выравнивать этот абзац текста(с переменной высотой конечно, она зависит от текста). Высота #out не имеет особого значения - но пускай будет к примеру 500px(заведомо больше высоты параграфа).
Для всех современных броузеров(не IE) это достигается двумя простыми строками:
- #out{
- height:500px;
- display:table-cell;
- vertical-align:middle;
- }
Только и всего. Теперь нужно это повторить для ИЕ…
IE+expression=нормальный броузер
Для эмуляции будем использовать expression (маленькие кусочки джаваскрипта который можно внедрять в CSS и работают лишь в ИЕ).
Вот что сэмулирует нам вертикальное выравнивание в ИЕ для элемента #centered внутри другого элемента:
#centered {
margin-top: expression(((outer.offsetHeight/2)
-parseInt(offsetHeight)/2) <0 ? "0" :
(outer.offsetHeight/2)
-(parseInt(offsetHeight)/2) +'px') ;
}
(видно как внутри ЦСС правил для #centered мы получаем его высоту по айдишнику centered.offsetHeight и высоту div#outer)
Или если мы выравниваем внутри body:
#centered{
margin-top: expression((
document.documentElement.offsetHeight/2)
-(parseInt(offsetHeight)/2) <0 ? "0" :
(document.documentElement.offsetHeight/2)
-(parseInt(offsetHeight)/2) +'px') ;
Это правило определяет высоту родительского элемента(или body) и высоту центрируемого элемента - после чего добавляет нужный margin-top для вертикального центрирования элемента.
Был предложен также метод для классов:
margin-top: expression((parentNode.offsetHeight - this.offsetHeight)<0 ? "0" : (parentNode.offsetHeight - this.offsetHeight)/2 + "px")
(parseInt убран для наглядности)
Как это работает
- document.documentElement.offsetHeight/2
определяет высоту body и делит ее на 2. Это дает нам отступ ровно в половину высоты экрана - -(parseInt(offsetHeight)/2))
Определяет высоту самого центрируемого блока. Отнятое от высоты родителя дает нам конечный margin-top - <0 ? "0" :
Если полученная разница отрицательная, то отступу присваивается значение 0. - <0 ? "0" :
Если же полученный результат больше либо равен 0, то повторяем вычисления и берем margin-top равный полученному значению для вертикального центрирования
Словами
Что бы понять откуда взялись все эти вычисления. Представьте что наш блок отцентрирован по вертикали внутри другого блока. Вот так:

И теперь нам нужно посчитать расстояние от верха родительского блока - до отцентрированного элемента(x-y). Очевидно для этого нам придется отнять от половины высоты родителя(x), половину высоты отцентрированного(y). Вычисление этого расстояния и происходит в скрипте, после чего оно присваивается в качестве margin-top, что по сути визуально центрирует блок по вертикали.
Конечно это своеобразная дилемма - “3 обертывающих DIV” или “expression”, зависит от случая, но как по мне, выбор тут однозначен ;).
Если Вам нужна валидность, да и просто ради красоты, эту строку для IE стоит перенести в отдельный CSS файл(СС), либо каким то образом оградить от других броузеров.
Ссылки
- Оригинал fully centered across browser-land… статья Gunlaug Sørtun про этот прием и центрирование вообще (там же в правой колонке несколько примеров)
- Пример центрирования в блоке
- Пример центрирования на экране
- Пример Gunlaug, для ИЕ там выводятся промежуточные числа вычислений..
- Информация об определении размеров блока на MSDN
- Информация о методе parseInt
- Вариант для классов, а не айди
Метод в принципе не сложный, может кто то уже даже и использовал… буду рад услышать Ваше мнение или совет по поводу техники!
Эта техника довольно часто упоминается, только вот адекватного expression’а не видел ни разу, спасибо ;)
Занятный способ. Вообще на самом деле как таковое вертикальное центрирование требуется далеко не всегда.
Меня чаще спасает line-height + padding в %.
Надо взять на заметку.. Вообще, хороший блог, столько всего интересного, я “вырос” на этом блоге.. Спасибо :)
за экспрешн спасибо
http://www.jakpsatweb.cz/css/css-vertical-center-solution.html
способ без экспрешена
Зато менее универсальный, и требует нескольких элементов. Все остальные способы я собирал два года назад в этом посте
Используем, хороший способ. Эспрешшн вообще классная штука.
Интересно. Хотелось бы еще услышать минусы этого способа. Я начну.
1. Замедляет рендер страницы.
2. IE expressions ignore CSS media types
У кого какие соображения?
спасибо, будем юзать!
оффтоп - а никто не знает как (пусть даже с expression) как заставить div’ы, например с float в виде нескольких колонок, выравниваться по высоте самого большого (типа как ведут себя ячейки таблицы)?
обычно достаточно иллюзии их одинаковой высоты.
Однако вот например способ от все того же Gunlaug
И вот тут еще один
Недостатки, со всем согласен, но игра стоит свеч имхо :)
Еще я бы добавил из недостатков - необходимость защиты, и по сути скриптовость(не работает с отключенным джаваскрипт)
Метод интересный, но вот только использование expression на мой взгляд - противоречие идеологии CSS. Стили должны работать всегда, даже если javaScript отключен. А в данном случае это не так.
сори, не прочел последний пост :)
да, но зная статистику, этим все же можно пренебрегать в меру ;) Вертикально выровненный блок в ИЕ вряд ли жизненно важен )
Интересно почитать коментарии. Вообще люди часто не хотят воспринимать и запоминать полезные вещи. Как много раз я сталкивался с ситуациями, что вот говоришь человеку “можно сделать так вот”, а он упирается и кричит, что можно и лучше, но как это лучше? Да.. к чему это я? :))
Есть проблема - есть способ ее решение. Спасибо! Действительно не раз сталкивался.
С днём варенья, коллега ;)
зы: если ничего не перепутал…
все правильно - спасибо :)
А зачем такие сложности если есть абсолютное позицирование?
Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.
А зачем такие сложности если есть абсолютное позицирование?
Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.
Во первых в посте рассказывается про вертикальное центрирование - боттом 0 этого не даст очевидно.
Во вторых недостатком подхода топ:50% служат два дополнительных обертывающих ДИВ, и некоторые некорректности при уменьшении размера внешнего блока.
уй, чёт мя проглючило что речь о выравнивании “внизу блока”(
респект, действительно очень хороший способ!
ля ну и разметка у сайта просто ппц
В примере центрирования в блоке заметил неприятный момент: в Firefox и Opera блок #out не выравнивается по центру экрана из-за объявления display:table-cell; , хотя margin-left и margin-right у этого блока установлены как и положено в значение auto…
Прикольно )
{table}{td} Hello world! {/td}{/table}
Остальное от Лукавого.
Мне по душе лукавство )
ЗЫ я знаю кто такой Лукавый =)
tnx автору за метод. очень помог.
я в свою очередь его чуток изменил, да бы не привязываться к именам (id)
className {
margin-top: expression((parentNode.offsetHeight - this.offsetHeight)
мой пример блог порезал ((
Большое спасибо автору за пример, очень пригодилось в реальной работе. Кстати, вот мои (личные, без претензий к кому-либо) соображения насчет некоторых высказываний:
1. Насчет “адекватных expression” - посмотрите созданный нами работающий код: http://svoy-group.ru/about/clients/ Мне кажется, здесь все вполне адекватно (спасибо автору этого топика и klierik, см. пост номер 26!)) )
2. line-height, равный высоте внешнего блока. Этот способ не будет работать, если вам нужно выровнять не текст, а что-то другое (например, картинку), а также если ваш текст будет содержать более двух строк.
3. Табличная верстка - это хорошо и даже грамотно, однако не всегда и не совсем удобно, когда, например, вывод нужно делать из CMS по единому шаблону. Поясню: программисту гораздо удобнее выводить однотипные данные по одному шаблону, чем открывать/закрывать тегами таблицу, а также просчитывать нужное кол-во столбцов.
4. На тему “expression противоречит идеологии CSS”. Ничуть не противоречит, когда речь идет об обходе багов насквозь глючного IE, а других вариантов ноль. Кривой браузер - кривые и способы его обхода, все вполне логично. Я лично тоже приверженец чистого CSS, однако есть случаи, когда хаки неизбежны.
Спасибо! Добавлю, что по-хорошему, этот expression нужно использовать с оптимизацией (только при фиксированных размерах внешнего блока)
Хоть это и не очень красиво, но ИМХО лучше использовать TABLE, чем эмулировать его DIV’ом.
Какое-то странное поведение vertical-align … там работает … там нет. Недоработка ли это стандарта ( http://www.w3.org/TR/REC-CSS2/visudet.html )?
Просто спецификация не “свойство-ориентирована” а “элементо-ориентирована”, для элемента тейбл придумали чисто табличное выравнивание по центру, а для дива его поведение попросту гораздо сложнее описать. И нужно оно, надо сказать, довольно редко, несмотря на внимание людей к этой проблеме.
пока не вышел IE8 который поддерживает display: table-cell; заморачиватся на верстки без таблиц смысла нет. Все можно сделать по стандартам. И не забывайте что елемент float, придуман не для верстки а для обтекания. Не согласны? Посмотрите google, yandex…. как они сделаны? Вы думаете их делали случайные люди ? Если думаете что вы круче их … ну … задумайтесь какой успех у ваших сайтов и какой у google и yandex-a :)
Какой успех? Например укр.нет и украинская правда два сайта без таблиц - лидеры по популярности в украине. Сейчас уже ими занимаются другие команды, но это мало что меняет, об их редизайне можно почитать у меня в блоге.
Покажите мне хоть один из новых сервисов яндекса на таблицах? Вы похоже не совсем в курсе дел веба, потому я не буду строго судить ваше мнение, будем считать это некоторым незнанием. ;)
У больших компаний свои проблемы с кодом, но то, что они знают как правильно, очевидно. Если вы ставите вопрос так, я, можно сказать недолго, но, “работал” в яндексе, и знаю эти проблемы, и людей их решающих. И я очень уважаю этих профессионалов, и знаю что они делают все “верно”.
А какая популярность у Ваших проектов? ;) Это риторический, не нужно меряться, это совершенно не имеет значения. Потому что хорошая верстка уже тут =)
Потому, извините, но лучше не судите не зная людей =) Многие ждали ИЕ7, теперь ждут ИЕ8, а потом будут ждать ИЕ9, только чтобы не тратить время на обучение чему-то новому.
Я не прав? Я бы хотел оказаться не прав. Мне кажется Ваше мнение о верстке необходимо обновить свежей информацией.
bobrob, Юра не может задуматься, у него вместо мозгов мохито!
Хорошо , конкретно про этот ваш пример. Без эмоции. Подумайте логически. Для всех браузеров вы используете display: table-cell; которое не поддерживается в IE. Ваше решение проблемы для IE будет работать в любом браузере IE. IE8 будет поддерживать display: table-cell; http://blogs.msdn.com/ie/archive/2007/12/19/internet-explorer-8-and-acid2-a-milestone.aspx и выйдет он в конце 2008 года. Что значит через год не известно как будет себя вести ваша верстка. Вот почему для IE надо делать отдельный CSS и привязывать его через условные комментарии для IE. И там указать:
Если сделаете так , после выхода IE8 у вас все будет работать нормально во всех браузерах. То же самое делается вместо всяких хаков в CSS файле. По тому что все везде и всегда будет работать.
Про условные комментарии в IE можно почитать здесь: http://msdn2.microsoft.com/en-us/library//ms537512.aspx
Спасибо за ссылку на conditional comments. Я уже на них не раз ссылался и писал отдельный пост, но не понимаю как это может быть связано с тем, что подход с експрешн не подходит, и верстать нужно таблицами.
В посте обсуждается подход к решению задачи, а использовать его можно как с condcomments так и с любыми другими хаками. Я умышленно вообще опустил способ применения.
Ну будет ИЕ8 поддерживать display: table-cell;, значит в нем будет работать нормальный способ как и для Фаерфокса сейчас, и?
Простите, так и не увидел логической связи.
Не понятно как себя поведет браузер (в случае IE8). Он применит display: table-cell; потом еще попытается применить експрешн, как он все это пропасит и что будет в конечном итоге предвидеть невозможно.
А про таблицы это да … другая тема. Подскажите где написать комментарий. На реальном примере могу показать и объяснить почему на данном этапе нет смысла заморачиватся на безтабличной верстке
Давайте закроем вопрос с conditional comments, пост совсем не об этом, и про хаки-фильтры я писал отдельно. Добавлю, что вертикальное выравнивание нужно приблизитально в 2-3% проектов. Выйдет ИЕ8 поправлю пост.
Что же касается того что “рано”, то в самом предложении уже вы ответили на свой вопрос. Вы приведете какую-то эпизодическую ситуацию эксплуатирующую табличное поведение и скажете победоносно “РАНО!”. Забыв о сотне посещаемых сайтов мира успешно работающих с нормальным кодом.
Добавлю от себя небольшой исторический факт, популярный журнал Wired, перешел на нормальный код в 2002 году, это 6 лет назад. =)
Добавлю еще, что вопрос таблицы или нет, НЕ вопрос стиля верстки, а вопрос правильного и неправильного. Потому, просто представьте как вы рассказываете милиционеру о том, что вы ехали по встречной, потому что основная полоса слишком медленная.
Буду рад услышать Ваш пример! Или тут, или в почту, как сочтете удобным.
вы что друг у друга списываете контент :D
в пост о вертикальном выравнивании!
что за привычка, постоянно рассматривать один див. хех,
это что ж получается у тебя страница состоит из одного дива?
а если див зафлотирован или еще что-то?..
вообщем это больше похоже на бестолковые заметки, чем на полезный совет! ЗРЯ ПИСАЛ МНОГА БУКАФ! КГ/АМ!
Мне жаль что вам не удалось понять сути поста, если я попытаюсь предусмотреть “див зафлоатен или еще что-то” мне не хватит книги =) Нужно брать 50 дизайнов и в каждом показывать как работает вертикальное выравнивание? =) Думали головой когда писали? =)
Зачем вертикально выравнивать “флотированный див”? Тут где то ошибка. Или он плавающий, или он нужен вертикально по центру. Совмещение нужно так редко, что само упоминание о нем уже преисполняет меня уважения к вашему большому опыту, в котором было и такое! Но если очень хочется, всегда можно добавить обертку для флоата, и выровнять ее, а не сам флоат.
У кого и кто списывает? Любопытно.
к моему сожалению, не смотря на то что будущее за 2.0, до сих пор остались 17 летние, безрукие дизайнеры, которые берут количеством. С их макетами частенько возникают такого рода проблемы, потому что они не имеют ни малейшего представления о, мля, вебе… суть я понял, но такими методами только в блогах удобно, когда две картинки оформляют всю страницу…
З.Ы.: не принимай мой комент близко к сердцу )). посчитал для себя решение бесполезным и написал недовольство, увидев в яндекс запросе по сабжу одинаковые, бесполезные посты…
удачи… ;-)
Да дело не в том что задели, я просто хочу понять а какой могла быть эта статья чтобы она была тебе полезной? Просто любопытно, ведь моя основная цель писать полезные статьи.
Расскажешь?
Спасибо за решение. Оно отлично подходит для компонет с ID. Но если у нас список айтемов - то очень подходит такое оригинальное решение с использованием абсолютного позиционирования и отрицательніх маргинов http://www.jakpsatweb.cz/css/priklady/vertical-align-final-solution-en.html
Да, это хорошее решение.
Но и это легко адаптируется для классов, в этом нет никакой проблемы. Просто нужно будет использовать parentNode.parentNode. Я не хотел засорять пост лишней информацией.
Но например, при известной высоте хак приобретает вид:
.PictureBlock img{ margin-top: expression((62-parseInt(offsetHeight)/2) <0 ? '0' : 62-(parseInt(offsetHeight)/2) +'px') ; }Где высота айтема была 125 пикселов. 62*2~125.
[…] По материалам cssing.org.ua. […]