26 апреля, 2007

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

Много копий сломано на ниве вертикального выравнивания без таблиц. Однако недавно я узнал о еще одном более простом способе. Этот пост, перевод статьи уважаемого мною 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 файл(СС), либо каким то образом оградить от других броузеров.

Ссылки

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

XHTML/CSS

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

1. 26 апреля | pepelsbey

Эта техника довольно часто упоминается, только вот адекватного expression’а не видел ни разу, спасибо ;)

2. 26 апреля | Sam

Занятный способ. Вообще на самом деле как таковое вертикальное центрирование требуется далеко не всегда.

Меня чаще спасает line-height + padding в %.

3. 26 апреля | garA

Надо взять на заметку.. Вообще, хороший блог, столько всего интересного, я “вырос” на этом блоге.. Спасибо :)

4. 26 апреля | Zigzag

за экспрешн спасибо

5. 26 апреля | strix

http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

способ без экспрешена

6. 26 апреля | akella

Зато менее универсальный, и требует нескольких элементов. Все остальные способы я собирал два года назад в этом посте

7. 26 апреля | Smash

Используем, хороший способ. Эспрешшн вообще классная штука.

8. 26 апреля | Yuriy

Интересно. Хотелось бы еще услышать минусы этого способа. Я начну.
1. Замедляет рендер страницы.
2. IE expressions ignore CSS media types
У кого какие соображения?

9. 26 апреля | YoYurec

спасибо, будем юзать!

оффтоп - а никто не знает как (пусть даже с expression) как заставить div’ы, например с float в виде нескольких колонок, выравниваться по высоте самого большого (типа как ведут себя ячейки таблицы)?

10. 26 апреля | akella

обычно достаточно иллюзии их одинаковой высоты.
Однако вот например способ от все того же Gunlaug
И вот тут еще один

Недостатки, со всем согласен, но игра стоит свеч имхо :)
Еще я бы добавил из недостатков - необходимость защиты, и по сути скриптовость(не работает с отключенным джаваскрипт)

11. 27 апреля | power

Метод интересный, но вот только использование expression на мой взгляд - противоречие идеологии CSS. Стили должны работать всегда, даже если javaScript отключен. А в данном случае это не так.

12. 27 апреля | power

сори, не прочел последний пост :)

13. 27 апреля | akella

да, но зная статистику, этим все же можно пренебрегать в меру ;) Вертикально выровненный блок в ИЕ вряд ли жизненно важен )

14. 27 апреля | LeKz

Интересно почитать коментарии. Вообще люди часто не хотят воспринимать и запоминать полезные вещи. Как много раз я сталкивался с ситуациями, что вот говоришь человеку “можно сделать так вот”, а он упирается и кричит, что можно и лучше, но как это лучше? Да.. к чему это я? :))
Есть проблема - есть способ ее решение. Спасибо! Действительно не раз сталкивался.

15. 28 апреля | pepelsbey

С днём варенья, коллега ;)

зы: если ничего не перепутал…

16. 29 апреля | akella

все правильно - спасибо :)

17. 21 мая | Del'ka

А зачем такие сложности если есть абсолютное позицирование?
Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.

18. 21 мая | Del'ka

А зачем такие сложности если есть абсолютное позицирование?
Для содержаего блока - relative, для текста - top: 0 или bottom: 0 соответсвенно.

19. 22 мая | akella

Во первых в посте рассказывается про вертикальное центрирование - боттом 0 этого не даст очевидно.

Во вторых недостатком подхода топ:50% служат два дополнительных обертывающих ДИВ, и некоторые некорректности при уменьшении размера внешнего блока.

20. 7 июня | Del'ka

уй, чёт мя проглючило что речь о выравнивании “внизу блока”(

респект, действительно очень хороший способ!

21. 28 июня | я

ля ну и разметка у сайта просто ппц

22. 2 июля | coder

В примере центрирования в блоке заметил неприятный момент: в Firefox и Opera блок #out не выравнивается по центру экрана из-за объявления display:table-cell; , хотя margin-left и margin-right у этого блока установлены как и положено в значение auto…

23. 9 июля | Николай

Прикольно )

24. 25 июля | Ринат

{table}{td} Hello world! {/td}{/table}
Остальное от Лукавого.

25. 25 июля | akella

Мне по душе лукавство )

ЗЫ я знаю кто такой Лукавый =)

26. 8 сентября | klierik

tnx автору за метод. очень помог.
я в свою очередь его чуток изменил, да бы не привязываться к именам (id)
className {
margin-top: expression((parentNode.offsetHeight - this.offsetHeight)

27. 8 сентября | klierik

мой пример блог порезал ((

28. 28 декабря | ashDesigner

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

1. Насчет “адекватных expression” - посмотрите созданный нами работающий код: http://svoy-group.ru/about/clients/ Мне кажется, здесь все вполне адекватно (спасибо автору этого топика и klierik, см. пост номер 26!)) )
2. line-height, равный высоте внешнего блока. Этот способ не будет работать, если вам нужно выровнять не текст, а что-то другое (например, картинку), а также если ваш текст будет содержать более двух строк.
3. Табличная верстка - это хорошо и даже грамотно, однако не всегда и не совсем удобно, когда, например, вывод нужно делать из CMS по единому шаблону. Поясню: программисту гораздо удобнее выводить однотипные данные по одному шаблону, чем открывать/закрывать тегами таблицу, а также просчитывать нужное кол-во столбцов.
4. На тему “expression противоречит идеологии CSS”. Ничуть не противоречит, когда речь идет об обходе багов насквозь глючного IE, а других вариантов ноль. Кривой браузер - кривые и способы его обхода, все вполне логично. Я лично тоже приверженец чистого CSS, однако есть случаи, когда хаки неизбежны.

29. 28 декабря | akella

Спасибо! Добавлю, что по-хорошему, этот expression нужно использовать с оптимизацией (только при фиксированных размерах внешнего блока)

30. 14 января | Ertong

Хоть это и не очень красиво, но ИМХО лучше использовать TABLE, чем эмулировать его DIV’ом.

Какое-то странное поведение vertical-align … там работает … там нет. Недоработка ли это стандарта ( http://www.w3.org/TR/REC-CSS2/visudet.html )?

31. 16 января | akella

Просто спецификация не “свойство-ориентирована” а “элементо-ориентирована”, для элемента тейбл придумали чисто табличное выравнивание по центру, а для дива его поведение попросту гораздо сложнее описать. И нужно оно, надо сказать, довольно редко, несмотря на внимание людей к этой проблеме.

32. 22 января | bobrob

пока не вышел IE8 который поддерживает display: table-cell; заморачиватся на верстки без таблиц смысла нет. Все можно сделать по стандартам. И не забывайте что елемент float, придуман не для верстки а для обтекания. Не согласны? Посмотрите google, yandex…. как они сделаны? Вы думаете их делали случайные люди ? Если думаете что вы круче их … ну … задумайтесь какой успех у ваших сайтов и какой у google и yandex-a :)

33. 22 января | akella

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

Покажите мне хоть один из новых сервисов яндекса на таблицах? Вы похоже не совсем в курсе дел веба, потому я не буду строго судить ваше мнение, будем считать это некоторым незнанием. ;)

У больших компаний свои проблемы с кодом, но то, что они знают как правильно, очевидно. Если вы ставите вопрос так, я, можно сказать недолго, но, “работал” в яндексе, и знаю эти проблемы, и людей их решающих. И я очень уважаю этих профессионалов, и знаю что они делают все “верно”.
А какая популярность у Ваших проектов? ;) Это риторический, не нужно меряться, это совершенно не имеет значения. Потому что хорошая верстка уже тут =)

Потому, извините, но лучше не судите не зная людей =) Многие ждали ИЕ7, теперь ждут ИЕ8, а потом будут ждать ИЕ9, только чтобы не тратить время на обучение чему-то новому.
Я не прав? Я бы хотел оказаться не прав. Мне кажется Ваше мнение о верстке необходимо обновить свежей информацией.

34. 22 января | Юрко

bobrob, Юра не может задуматься, у него вместо мозгов мохито!

35. 22 января | 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

36. 22 января | akella

Спасибо за ссылку на conditional comments. Я уже на них не раз ссылался и писал отдельный пост, но не понимаю как это может быть связано с тем, что подход с експрешн не подходит, и верстать нужно таблицами.
В посте обсуждается подход к решению задачи, а использовать его можно как с condcomments так и с любыми другими хаками. Я умышленно вообще опустил способ применения.

Ну будет ИЕ8 поддерживать display: table-cell;, значит в нем будет работать нормальный способ как и для Фаерфокса сейчас, и?

Простите, так и не увидел логической связи.

37. 22 января | bobrob

Не понятно как себя поведет браузер (в случае IE8). Он применит display: table-cell; потом еще попытается применить експрешн, как он все это пропасит и что будет в конечном итоге предвидеть невозможно.

38. 22 января | bobrob

А про таблицы это да … другая тема. Подскажите где написать комментарий. На реальном примере могу показать и объяснить почему на данном этапе нет смысла заморачиватся на безтабличной верстке

39. 22 января | akella

Давайте закроем вопрос с conditional comments, пост совсем не об этом, и про хаки-фильтры я писал отдельно. Добавлю, что вертикальное выравнивание нужно приблизитально в 2-3% проектов. Выйдет ИЕ8 поправлю пост.

Что же касается того что “рано”, то в самом предложении уже вы ответили на свой вопрос. Вы приведете какую-то эпизодическую ситуацию эксплуатирующую табличное поведение и скажете победоносно “РАНО!”. Забыв о сотне посещаемых сайтов мира успешно работающих с нормальным кодом.

Добавлю от себя небольшой исторический факт, популярный журнал Wired, перешел на нормальный код в 2002 году, это 6 лет назад. =)

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

Буду рад услышать Ваш пример! Или тут, или в почту, как сочтете удобным.

40. 6 февраля | master

вы что друг у друга списываете контент :D
в пост о вертикальном выравнивании!
что за привычка, постоянно рассматривать один див. хех,
это что ж получается у тебя страница состоит из одного дива?
а если див зафлотирован или еще что-то?..
вообщем это больше похоже на бестолковые заметки, чем на полезный совет! ЗРЯ ПИСАЛ МНОГА БУКАФ! КГ/АМ!

41. 6 февраля | akella

Мне жаль что вам не удалось понять сути поста, если я попытаюсь предусмотреть “див зафлоатен или еще что-то” мне не хватит книги =) Нужно брать 50 дизайнов и в каждом показывать как работает вертикальное выравнивание? =) Думали головой когда писали? =)

Зачем вертикально выравнивать “флотированный див”? Тут где то ошибка. Или он плавающий, или он нужен вертикально по центру. Совмещение нужно так редко, что само упоминание о нем уже преисполняет меня уважения к вашему большому опыту, в котором было и такое! Но если очень хочется, всегда можно добавить обертку для флоата, и выровнять ее, а не сам флоат.

У кого и кто списывает? Любопытно.

42. 7 февраля | master

к моему сожалению, не смотря на то что будущее за 2.0, до сих пор остались 17 летние, безрукие дизайнеры, которые берут количеством. С их макетами частенько возникают такого рода проблемы, потому что они не имеют ни малейшего представления о, мля, вебе… суть я понял, но такими методами только в блогах удобно, когда две картинки оформляют всю страницу…
З.Ы.: не принимай мой комент близко к сердцу )). посчитал для себя решение бесполезным и написал недовольство, увидев в яндекс запросе по сабжу одинаковые, бесполезные посты…
удачи… ;-)

43. 9 февраля | akella

Да дело не в том что задели, я просто хочу понять а какой могла быть эта статья чтобы она была тебе полезной? Просто любопытно, ведь моя основная цель писать полезные статьи.

Расскажешь?

44. 4 марта | Galina

Спасибо за решение. Оно отлично подходит для компонет с ID. Но если у нас список айтемов - то очень подходит такое оригинальное решение с использованием абсолютного позиционирования и отрицательніх маргинов http://www.jakpsatweb.cz/css/priklady/vertical-align-final-solution-en.html

45. 4 марта | akella

Да, это хорошее решение.
Но и это легко адаптируется для классов, в этом нет никакой проблемы. Просто нужно будет использовать parentNode.parentNode. Я не хотел засорять пост лишней информацией.
Но например, при известной высоте хак приобретает вид:

.PictureBlock  img{
	margin-top: expression((62-parseInt(offsetHeight)/2)
        <0 ? '0' : 62-(parseInt(offsetHeight)/2) +'px') ;
	}

Где высота айтема была 125 пикселов. 62*2~125.

46. 19 апреля | Вертикальное выравнивание в div’ах

[…] По материалам cssing.org.ua. […]

47. 9 июля | Евгений

Классный блог!!! Очень полезен! Супер! Коммерты тоже в тему, почерпал полезного немного! Спасибо!

48. 9 июля | Евгений

ну в смысле не мало))

49. 11 июля | S-a

Всё бы хорошо, но IE 6 тормозит. Ощутимо так тормозит.

50. 29 июля | Пупкин

да нах IE6 вообще.
Будет тормозить - быстрее от этого дерьма мир избавится…

51. 31 августа | Den

Присоединяюсь к посту #22, который почему-то был проигнорирован автором. В FF И Opere DIV не воспринемает margin. Если какое-то решение этой проблемы?

52. 31 августа | akella

Это не так часто нужно, советую выравнивать абсолютным позиционированием, либо добавлять еще один блок внутрь блока с table-cell - для которого уже указывать margin:0 auto;

53. 9 января | 13th

Возможно пример и хороший, НО как быть если высота не задана?
Или если в Диве-родители есть два дива, один из которых флоат(и именно в нем надо разместить элементы по середине длине содержимого), а второй с отступом на ширину флоата? С дивами очень мног ов этом плане бреда.
Всё таки в большинства случаев надо использовать дивы , в отдельных случаях таблицы, а проблема наверно не в браузерах , а в самом КСС - нет там еще достаточно возможностей чтоб заменить полностью дивами таблицы и получить ту же “резину”

54. 28 марта | Dimon

А может проще вставить в Див Таблицу 1х1 и забить на кучу вложенных Дивов, выражения, различия в браузерах и т.д.? Ведь это не нарушает самой идеи блочной верстки?

55. 14 июня | нигер

каэсэс бойан. Йа креведк0!

56. 21 июня | Alexandr

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

57. 26 июня | Codriter

По поводу метода для “нормальных” браузеров, а именно display:table-cell; vertical-align:middle; есть одно замечание. Сегодня в очередной раз столкнулся с проблемой и решил поделиться - наболело. Дело в том, что данный способ работает только в том случае, когда высота содержащего блока указана явно, причем не в процентах, а в пикселах.
Сейчас пытаюсь сделать вертикальное выравнивание у DIV-а резинового по высоте - пока что ничего не получается :(

58. 22 сентября | Алекс

dfsffdfsv fdsfdf dfsdf dfsdf sfdsfs dsf
fdsfdf dfsdf dfsdf sfdsfs dsf
fdsfdf dfsdf dfsdf sfdsfs dsf
fdsfdf dfsdf dfsdf sfdsfs dsf

Внешний контейнер по высоте может быть задан как сейчас - жестко, или в %.
Следующий контейнер теперь нормально понимает задание высоты в %.

Извратный способ с ие-хаками, зато без скриптов в том или ином виде.

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

59. 29 декабря | Артём

Вот тут: http://piumosso.ru/a/css/display/inline-block/vertical-align описан ещё один способ вертикального выравнивания безо всяких экспрешнов. Надеюсь, кому-нибудь пригодится))

60. 29 декабря | akella

Спасибо за ссылку! Этот способ уже был описан в предыдущей моей статье

61. 29 декабря | Артём

Да)
Но, видимо, не совсем, так как соль моего метода в распорке

62. 12 августа | Вертикальное выравнивание текста | Искусство создания и продвижения сайтов

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

63. 27 августа | Levik

Если у контейнера float:left, то vertical-align:middle в сочетании с display:table-cell не работают. Приходится вводить дополнительный контейнер…

Оставить комментарий

Комментировать

Обязательные поля