Еще один способ вертикального выравнивания в CSS

26 Apr, 2007

Много копий сломано на ниве вертикального выравнивания без таблиц. Однако недавно я узнал о еще одном более простом способе. Этот пост, перевод статьи уважаемого мною Gunlaug о вертикальном выравнивании без дополнительного HTML и с помощью правда другого зла.
Оригинальная статья: fully centered across browser-land…

Задача

Отцентрировать что-нибудь вертикально внутри какого-либо элемента(экрана например).

Возьмем такой вот HTML:

  1. <div id="out">
  2. <p id="centered" >...</p>
  3. </div>
Будем выравнивать этот абзац текста(с переменной высотой конечно, она зависит от текста). Высота #out не имеет особого значения - но пускай будет к примеру 500px(заведомо больше высоты параграфа).

Для всех современных броузеров(не IE) это достигается двумя простыми строками:

  1. #out{
  2. height:500px;
  3. display:table-cell;
  4. vertical-align:middle;
  5. }
Только и всего. Теперь нужно это повторить для ИЕ...

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 убран для наглядности)

Как это работает

  1. document.documentElement.offsetHeight/2
    определяет высоту body и делит ее на 2. Это дает нам отступ ровно в половину высоты экрана
  2. -(parseInt(offsetHeight)/2))
    Определяет высоту самого центрируемого блока. Отнятое от высоты родителя дает нам конечный margin-top
  3. <0 ? "0" :
    Если полученная разница отрицательная, то отступу присваивается значение 0.
  4. <0 ? "0" :
    Если же полученный результат больше либо равен 0, то повторяем вычисления и берем margin-top равный полученному значению для вертикального центрирования

Словами

Что бы понять откуда взялись все эти вычисления. Представьте что наш блок отцентрирован по вертикали внутри другого блока. Вот так: вертикально отцентрированный элемент

И теперь нам нужно посчитать расстояние от верха родительского блока - до отцентрированного элемента(x-y). Очевидно для этого нам придется отнять от половины высоты родителя(x), половину высоты отцентрированного(y). Вычисление этого расстояния и происходит в скрипте, после чего оно присваивается в качестве margin-top, что по сути визуально центрирует блок по вертикали.

Конечно это своеобразная дилемма - "3 обертывающих DIV" или "expression", зависит от случая, но как по мне, выбор тут однозначен ;).

Если Вам нужна валидность, да и просто ради красоты, эту строку для IE стоит перенести в отдельный CSS файл(СС), либо каким то образом оградить от других броузеров.

Ссылки

Метод в принципе не сложный, может кто то уже даже и использовал... буду рад услышать Ваше мнение или совет по поводу техники!

68 комментариев к “Еще один способ вертикального выравнивания в CSS”

1.akella | 29 Dec, 2009
Спасибо за ссылку! Этот способ уже был описан в предыдущей моей статье
2.Артём | 29 Dec, 2009
Да) Но, видимо, не совсем, так как соль моего метода в распорке
3.Артём | 29 Dec, 2009
Вот тут: http://piumosso.ru/a/css/display/inline-block/vertical-align описан ещё один способ вертикального выравнивания безо всяких экспрешнов. Надеюсь, кому-нибудь пригодится))
4.Алекс | 22 Sep, 2009
dfsffdfsv fdsfdf dfsdf dfsdf sfdsfs dsf fdsfdf dfsdf dfsdf sfdsfs dsf fdsfdf dfsdf dfsdf sfdsfs dsf fdsfdf dfsdf dfsdf sfdsfs dsf Внешний контейнер по высоте может быть задан как сейчас - жестко, или в %. Следующий контейнер теперь нормально понимает задание высоты в %. Извратный способ с ие-хаками, зато без скриптов в том или ином виде. Вообще, таблиц нужно опасаться в 2-х случаях: когда в них лежат какие-то важные для индексирования поисковыми машинами данные; и когда таблицы большие - этот случай как раз самое зло. Ие пока всю таблицу не загрузит - не покажет.
5.Codriter | 26 Jun, 2009
По поводу метода для "нормальных" браузеров, а именно display:table-cell; vertical-align:middle; есть одно замечание. Сегодня в очередной раз столкнулся с проблемой и решил поделиться - наболело. Дело в том, что данный способ работает только в том случае, когда высота содержащего блока указана явно, причем не в процентах, а в пикселах. Сейчас пытаюсь сделать вертикальное выравнивание у DIV-а резинового по высоте - пока что ничего не получается :(
6.Alexandr | 21 Jun, 2009
Большое спасибо за пост, очень помог. За небольшой срок работы верстальщиком (менее года), два раза приходилось выравнивать страницу по центру окна браузера, если она по высоте менее онного :). Притормаживания ие из-за експрешна незаметил абсолютно. способ просто супер. Насчет таблиц: таблицами оформлять надо только табличные данные. Учитесь делать семантически правильный код.
7.pepelsbey | 26 Apr, 2007
Эта техника довольно часто упоминается, только вот адекватного expression'а не видел ни разу, спасибо ;)
8.Sam | 26 Apr, 2007
Занятный способ. Вообще на самом деле как таковое вертикальное центрирование требуется далеко не всегда. Меня чаще спасает line-height + padding в %.
9.garA | 26 Apr, 2007
Надо взять на заметку.. Вообще, хороший блог, столько всего интересного, я "вырос" на этом блоге.. Спасибо :)
10.Zigzag | 26 Apr, 2007
за экспрешн спасибо
11.strix | 26 Apr, 2007
http://www.jakpsatweb.cz/css/css-vertical-center-solution.html способ без экспрешена
12.akella | 26 Apr, 2007
Зато менее универсальный, и требует нескольких элементов. Все остальные способы я собирал два года назад в этом посте
13.Smash | 26 Apr, 2007
Используем, хороший способ. Эспрешшн вообще классная штука.
14.Yuriy | 26 Apr, 2007
Интересно. Хотелось бы еще услышать минусы этого способа. Я начну. 1. Замедляет рендер страницы. 2. IE expressions ignore CSS media types У кого какие соображения?
15.YoYurec | 26 Apr, 2007
спасибо, будем юзать! оффтоп - а никто не знает как (пусть даже с expression) как заставить div'ы, например с float в виде нескольких колонок, выравниваться по высоте самого большого (типа как ведут себя ячейки таблицы)?
16.akella | 26 Apr, 2007
обычно достаточно иллюзии их одинаковой высоты. Однако вот например способ от все того же Gunlaug И вот тут еще один Недостатки, со всем согласен, но игра стоит свеч имхо :) Еще я бы добавил из недостатков - необходимость защиты, и по сути скриптовость(не работает с отключенным джаваскрипт)
17.power | 27 Apr, 2007
Метод интересный, но вот только использование expression на мой взгляд - противоречие идеологии CSS. Стили должны работать всегда, даже если javaScript отключен. А в данном случае это не так.
18.power | 27 Apr, 2007
сори, не прочел последний пост :)
19.akella | 27 Apr, 2007
да, но зная статистику, этим все же можно пренебрегать в меру ;) Вертикально выровненный блок в ИЕ вряд ли жизненно важен )
20.LeKz | 27 Apr, 2007
Интересно почитать коментарии. Вообще люди часто не хотят воспринимать и запоминать полезные вещи. Как много раз я сталкивался с ситуациями, что вот говоришь человеку "можно сделать так вот", а он упирается и кричит, что можно и лучше, но как это лучше? Да.. к чему это я? :)) Есть проблема - есть способ ее решение. Спасибо! Действительно не раз сталкивался.
21.pepelsbey | 28 Apr, 2007
С днём варенья, коллега ;) зы: если ничего не перепутал...
22.akella | 29 Apr, 2007
все правильно - спасибо :)
23.Del'ka | 21 May, 2007
А зачем такие сложности если есть абсолютное позицирование? Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.
24.Del'ka | 21 May, 2007
А зачем такие сложности если есть абсолютное позицирование? Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.
25.akella | 22 May, 2007
Во первых в посте рассказывается про вертикальное центрирование - боттом 0 этого не даст очевидно. Во вторых недостатком подхода топ:50% служат два дополнительных обертывающих ДИВ, и некоторые некорректности при уменьшении размера внешнего блока.
26.Del'ka | 07 Jun, 2007
уй, чёт мя проглючило что речь о выравнивании "внизу блока"( респект, действительно очень хороший способ!
27.я | 28 Jun, 2007
ля ну и разметка у сайта просто ппц
28.coder | 02 Jul, 2007
В примере центрирования в блоке заметил неприятный момент: в Firefox и Opera блок #out не выравнивается по центру экрана из-за объявления display:table-cell; , хотя margin-left и margin-right у этого блока установлены как и положено в значение auto...
29.Николай | 09 Jul, 2007
Прикольно )
30.akella | 25 Jul, 2007
Мне по душе лукавство ) ЗЫ я знаю кто такой Лукавый =)
31.Ринат | 25 Jul, 2007
{table}{td} Hello world! {/td}{/table} Остальное от Лукавого.
32.klierik | 08 Sep, 2007
tnx автору за метод. очень помог. я в свою очередь его чуток изменил, да бы не привязываться к именам (id) className { margin-top: expression((parentNode.offsetHeight - this.offsetHeight)
33.klierik | 08 Sep, 2007
мой пример блог порезал ((
34.ashDesigner | 28 Dec, 2007
Большое спасибо автору за пример, очень пригодилось в реальной работе. Кстати, вот мои (личные, без претензий к кому-либо) соображения насчет некоторых высказываний: 1. Насчет "адекватных expression" - посмотрите созданный нами работающий код: http://svoy-group.ru/about/clients/ Мне кажется, здесь все вполне адекватно (спасибо автору этого топика и klierik, см. пост номер 26!)) ) 2. line-height, равный высоте внешнего блока. Этот способ не будет работать, если вам нужно выровнять не текст, а что-то другое (например, картинку), а также если ваш текст будет содержать более двух строк. 3. Табличная верстка - это хорошо и даже грамотно, однако не всегда и не совсем удобно, когда, например, вывод нужно делать из CMS по единому шаблону. Поясню: программисту гораздо удобнее выводить однотипные данные по одному шаблону, чем открывать/закрывать тегами таблицу, а также просчитывать нужное кол-во столбцов. 4. На тему "expression противоречит идеологии CSS". Ничуть не противоречит, когда речь идет об обходе багов насквозь глючного IE, а других вариантов ноль. Кривой браузер - кривые и способы его обхода, все вполне логично. Я лично тоже приверженец чистого CSS, однако есть случаи, когда хаки неизбежны.
35.akella | 28 Dec, 2007
Спасибо! Добавлю, что по-хорошему, этот expression нужно использовать с оптимизацией (только при фиксированных размерах внешнего блока)
36.Ertong | 14 Jan, 2008
Хоть это и не очень красиво, но ИМХО лучше использовать TABLE, чем эмулировать его DIV'ом. Какое-то странное поведение vertical-align ... там работает ... там нет. Недоработка ли это стандарта ( http://www.w3.org/TR/REC-CSS2/visudet.html )?
37.akella | 16 Jan, 2008
Просто спецификация не "свойство-ориентирована" а "элементо-ориентирована", для элемента тейбл придумали чисто табличное выравнивание по центру, а для дива его поведение попросту гораздо сложнее описать. И нужно оно, надо сказать, довольно редко, несмотря на внимание людей к этой проблеме.
38.akella | 22 Jan, 2008
Какой успех? Например укр.нет и украинская правда два сайта без таблиц - лидеры по популярности в украине. Сейчас уже ими занимаются другие команды, но это мало что меняет, об их редизайне можно почитать у меня в блоге. Покажите мне хоть один из новых сервисов яндекса на таблицах? Вы похоже не совсем в курсе дел веба, потому я не буду строго судить ваше мнение, будем считать это некоторым незнанием. ;) У больших компаний свои проблемы с кодом, но то, что они знают как правильно, очевидно. Если вы ставите вопрос так, я, можно сказать недолго, но, "работал" в яндексе, и знаю эти проблемы, и людей их решающих. И я очень уважаю этих профессионалов, и знаю что они делают все "верно". А какая популярность у Ваших проектов? ;) Это риторический, не нужно меряться, это совершенно не имеет значения. Потому что хорошая верстка уже тут =) Потому, извините, но лучше не судите не зная людей =) Многие ждали ИЕ7, теперь ждут ИЕ8, а потом будут ждать ИЕ9, только чтобы не тратить время на обучение чему-то новому. Я не прав? Я бы хотел оказаться не прав. Мне кажется Ваше мнение о верстке необходимо обновить свежей информацией.
39.bobrob | 22 Jan, 2008
пока не вышел IE8 который поддерживает display: table-cell; заморачиватся на верстки без таблиц смысла нет. Все можно сделать по стандартам. И не забывайте что елемент float, придуман не для верстки а для обтекания. Не согласны? Посмотрите google, yandex.... как они сделаны? Вы думаете их делали случайные люди ? Если думаете что вы круче их ... ну ... задумайтесь какой успех у ваших сайтов и какой у google и yandex-a :)
40.Юрко | 22 Jan, 2008
bobrob, Юра не может задуматься, у него вместо мозгов мохито!
41.bobrob | 22 Jan, 2008
Хорошо , конкретно про этот ваш пример. Без эмоции. Подумайте логически. Для всех браузеров вы используете 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
42.akella | 22 Jan, 2008
Спасибо за ссылку на conditional comments. Я уже на них не раз ссылался и писал отдельный пост, но не понимаю как это может быть связано с тем, что подход с експрешн не подходит, и верстать нужно таблицами. В посте обсуждается подход к решению задачи, а использовать его можно как с condcomments так и с любыми другими хаками. Я умышленно вообще опустил способ применения. Ну будет ИЕ8 поддерживать display: table-cell;, значит в нем будет работать нормальный способ как и для Фаерфокса сейчас, и? Простите, так и не увидел логической связи.
43.bobrob | 22 Jan, 2008
Не понятно как себя поведет браузер (в случае IE8). Он применит display: table-cell; потом еще попытается применить експрешн, как он все это пропасит и что будет в конечном итоге предвидеть невозможно.
44.bobrob | 22 Jan, 2008
А про таблицы это да … другая тема. Подскажите где написать комментарий. На реальном примере могу показать и объяснить почему на данном этапе нет смысла заморачиватся на безтабличной верстке
45.akella | 22 Jan, 2008
Давайте закроем вопрос с conditional comments, пост совсем не об этом, и про хаки-фильтры я писал отдельно. Добавлю, что вертикальное выравнивание нужно приблизитально в 2-3% проектов. Выйдет ИЕ8 поправлю пост. Что же касается того что "рано", то в самом предложении уже вы ответили на свой вопрос. Вы приведете какую-то эпизодическую ситуацию эксплуатирующую табличное поведение и скажете победоносно "РАНО!". Забыв о сотне посещаемых сайтов мира успешно работающих с нормальным кодом. Добавлю от себя небольшой исторический факт, популярный журнал Wired, перешел на нормальный код в 2002 году, это 6 лет назад. =) Добавлю еще, что вопрос таблицы или нет, НЕ вопрос стиля верстки, а вопрос правильного и неправильного. Потому, просто представьте как вы рассказываете милиционеру о том, что вы ехали по встречной, потому что основная полоса слишком медленная. Буду рад услышать Ваш пример! Или тут, или в почту, как сочтете удобным.
46.master | 06 Feb, 2008
вы что друг у друга списываете контент :D в пост о вертикальном выравнивании! что за привычка, постоянно рассматривать один див. хех, это что ж получается у тебя страница состоит из одного дива? а если див зафлотирован или еще что-то?.. вообщем это больше похоже на бестолковые заметки, чем на полезный совет! ЗРЯ ПИСАЛ МНОГА БУКАФ! КГ/АМ!
47.akella | 06 Feb, 2008
Мне жаль что вам не удалось понять сути поста, если я попытаюсь предусмотреть "див зафлоатен или еще что-то" мне не хватит книги =) Нужно брать 50 дизайнов и в каждом показывать как работает вертикальное выравнивание? =) Думали головой когда писали? =) Зачем вертикально выравнивать "флотированный див"? Тут где то ошибка. Или он плавающий, или он нужен вертикально по центру. Совмещение нужно так редко, что само упоминание о нем уже преисполняет меня уважения к вашему большому опыту, в котором было и такое! Но если очень хочется, всегда можно добавить обертку для флоата, и выровнять ее, а не сам флоат. У кого и кто списывает? Любопытно.
48.master | 07 Feb, 2008
к моему сожалению, не смотря на то что будущее за 2.0, до сих пор остались 17 летние, безрукие дизайнеры, которые берут количеством. С их макетами частенько возникают такого рода проблемы, потому что они не имеют ни малейшего представления о, мля, вебе... суть я понял, но такими методами только в блогах удобно, когда две картинки оформляют всю страницу... З.Ы.: не принимай мой комент близко к сердцу )). посчитал для себя решение бесполезным и написал недовольство, увидев в яндекс запросе по сабжу одинаковые, бесполезные посты... удачи... ;-)
49.akella | 09 Feb, 2008
Да дело не в том что задели, я просто хочу понять а какой могла быть эта статья чтобы она была тебе полезной? Просто любопытно, ведь моя основная цель писать полезные статьи. Расскажешь?
50.Galina | 04 Mar, 2008
Спасибо за решение. Оно отлично подходит для компонет с ID. Но если у нас список айтемов - то очень подходит такое оригинальное решение с использованием абсолютного позиционирования и отрицательніх маргинов http://www.jakpsatweb.cz/css/priklady/vertical-align-final-solution-en.html
51.akella | 04 Mar, 2008
Да, это хорошее решение. Но и это легко адаптируется для классов, в этом нет никакой проблемы. Просто нужно будет использовать parentNode.parentNode. Я не хотел засорять пост лишней информацией. Но например, при известной высоте хак приобретает вид:
.PictureBlock img{
margin-top: expression((62-parseInt(offsetHeight)/2) 
 <0 ? '0' : 62-(parseInt(offsetHeight)/2) +'px') ;
	}
Где высота айтема была 125 пикселов. 62*2~125.
52.Вертикальное выравнивание в div&#8217;ах | 19 Apr, 2008
[...] По материалам cssing.org.ua. [...]
53.нигер | 14 Jun, 2009
каэсэс бойан. Йа креведк0!
54.Евгений | 09 Jul, 2008
Классный блог!!! Очень полезен! Супер! Коммерты тоже в тему, почерпал полезного немного! Спасибо!
55.Евгений | 09 Jul, 2008
ну в смысле не мало))
56.S-a | 11 Jul, 2008
Всё бы хорошо, но IE 6 тормозит. Ощутимо так тормозит.
57.Dimon | 28 Mar, 2009
А может проще вставить в Див Таблицу 1х1 и забить на кучу вложенных Дивов, выражения, различия в браузерах и т.д.? Ведь это не нарушает самой идеи блочной верстки?
58.Пупкин | 29 Jul, 2008
да нах IE6 вообще. Будет тормозить - быстрее от этого дерьма мир избавится...
59.Den | 31 Aug, 2008
Присоединяюсь к посту #22, который почему-то был проигнорирован автором. В FF И Opere DIV не воспринемает margin. Если какое-то решение этой проблемы?
60.akella | 31 Aug, 2008
Это не так часто нужно, советую выравнивать абсолютным позиционированием, либо добавлять еще один блок внутрь блока с table-cell - для которого уже указывать margin:0 auto;
61.13th | 09 Jan, 2009
Возможно пример и хороший, НО как быть если высота не задана? Или если в Диве-родители есть два дива, один из которых флоат(и именно в нем надо разместить элементы по середине длине содержимого), а второй с отступом на ширину флоата? С дивами очень мног ов этом плане бреда. Всё таки в большинства случаев надо использовать дивы , в отдельных случаях таблицы, а проблема наверно не в браузерах , а в самом КСС - нет там еще достаточно возможностей чтоб заменить полностью дивами таблицы и получить ту же "резину"
62.Levik | 27 Aug, 2010
Если у контейнера float:left, то vertical-align:middle в сочетании с display:table-cell не работают. Приходится вводить дополнительный контейнер...
63.Вертикальное выравнивание текста | Искусство создания и продвижения сайтов | 12 Aug, 2010
[...] Еще один способ вертикального выравнивания в CSS [...]
64.Выравнивание горизонтальное и вертикальное &#8211; Простые решения сложных проблем | 25 Oct, 2011
[...] здесь пришлось помучаться, поискать. Поискал в интернете разные способы, но в итоге пришлось спрашивать у ostgals, [...]
65.Demo | 24 Nov, 2011
alert("If you need, you can delete it!");
66.Gmax | 07 Feb, 2012
Gmax - поисковый сервер, контекстная реклама, партнерская программа
67.LeCiel | 27 Dec, 2011
натяжные потолки тут
68.fortnite account generator | 30 Jan, 2021
Does your site have a contact page? I'm having problems locating it but, I'd like to send you an email. I've got some suggestions for your blog you might be interested in hearing. Either way, great website and I look forward to seeing it develop over time.|