Как разместить блок неизвестного размера точно в центре страницы
Гуляя по Internet, совершенно случайно натолкнулся на статью "Стили CSS - центрируем объекты по центру веб-страницы".
Первой мыслью было, что автор начнёт рассказывать про вертикальное центрирование и всем известный margin: 0 auto. Но не тут-то было, всё гораздо интереснее
Статья, на которую я наткнулся — это перевод статьи Криса Койера (Chris Coyier) Quick CSS Trick: How To Center an Object Exactly In The Center. При этом высота и ширина центрируемого объекта в статье полагаются известными. Что ж, я ожидал чего-то большего.
Я сначала вкратце опишу идею Криса, потом расскажу, почему так не надо делать и затем покажу, что простого решения, удовлетворяющего всем требованиям, нет
Начнём. Пусть у нас имеется, например, <div> размерами 200×100 пикселей. Поступаем следующим образом:
position: fixed;
top: 50%;
left: 50%;
margin-top: -50px; /* 50% высоты */
margin-left: -100px; /* 50% ширины */
height: 100px;
width: 200px;
}
Начнём с того, что IE6 position: fixed очень плохо понимает. Для него нужно добавить небольшой хак:
position: absolute;
}
Теперь о минусах:
- размеры блока должны быть известны;
- при уменьшении окна так, чтобы оно перекрывало отцентрированный объект, скроллер хотя и появляется, но прокрутить отцентрированный объект не сможет (из-за
position: fixed); - при уменьшении ширины окна можно дойти до такого размера, когда у объекта границы станут отрицательными.
Теперь о реализации центрирования в общем виде (считаем, что высота объекта нам неизвестна; ширина же должна быть известной, так как блочный элемент, не имеющий явно заданной ширины автоматически получает width: 100%). Решение основывается на идеях, представленных в следующих статьях:
- Вертикальное выравнивание без таблиц;
- Нижний колонтитул — в нижней части страницы;
- Подборка CSS-хаков для различных браузеров.
Разметка:
<div id="outer">
<div id="middle">
<div id="inner">
Ego autem quem timeam lectorem, cum ad te ne Graecis quidem cedentem in philosophia audeam scribere?
</div>
</div>
</div>
</body>
Прочитавшим статью "Вертикальное выравнивание без таблиц" должно быть ясно, откуда "растут ноги" у этой разметки.
Стили будут почти аналогичными приведённым в той статье, но с небольшими изменениями для IE.
Начнём со стилей для нормальных браузеров:
overflow: auto;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
#outer {
height: 100%; /* В этом случае нельзя использовать min-height. Для таблиц (элементов с display: table) мир устроен иначе */
display: table;
vertical-align: middle;
width: 600px; /* Если ширина не задана явно, будет 100% */
margin: 0 auto;
}
#middle {
display: table-row;
vertical-align: middle;
}
#inner {
display: table-cell;
vertical-align: middle;
}
Теперь стили для Ишака. Я бы поместил их в условный комментарий, например, так:
<style type="text/css">...</style>
<![endif]-->
Вышеприведённый условный комментарий не должен работать для IE8, и это сделано специально: во-первых, IE8 поддерживает display: table, display: table-row и display: table-cell; во-вторых, будучи бетой, он не поддерживает vertical-align ни в каком виде. В общем, когда Microsoft выпустит полноценный браузер, тогда и будем думать
Стили для Internet Explorer:
text-align: center;
}
#outer {
position: relative;
}
#middle {
top: 50%;
position: relative; /* Не используем абсолютное позиционирование, чтобы избежать проблем с прокруткой */
width: 100%;
}
#inner {
position: relative;
top: -50%;
}
Если посмотреть на то, что получилось, можно заметить, что это один из тех случаев, когда код работает корректно в IE6, но не в IE7 (последний будет показывать совершенно ненужный отступ снизу). Если вспомнить статью "Вертикальное выравнивание без таблиц"), то там мы ставили overflow: hidden элементу #outer, чтобы избежать подобного рода неприятностей в IE6/7. И, хотя в IE6 можно обойтись и без этого (перейдя от абсолютного позиционирования к относительному), с IE7 всё не так просто. В качестве быстрого исправления можно предложить такой вариант:
overflow-x: hidden;
}
Что характерно, будет работать хоть overflow-x, хоть overflow-y.
В результате получаем код, который работает нормально везде, кроме IE7: в IE7 при уменьшении размера окна по вертикали полоса прокрутки появляться не будет. Сделать нормальную прокрутку непосредственно для элемента #outer также представляется проблематичным — нижний отступ будет слишком большим. Поэтому остаётся одно решение — таблица. Причём можно сделать так, что таблицу будет видеть только IE7:
<div id="outer">
<div id="middle">
<div id="inner">
Ego autem quem timeam lectorem, cum ad te ne Graecis quidem cedentem in philosophia audeam scribere? quamquam a te ipso id quidem facio provocatus gratissimo mihi libro, quem ad me de virtute misisti. Sed ex eo credo quibusdam usu venire; ut abhorreant a Latinis, quod inciderint in inculta quaedam et horrida, de malis Graecis Latine scripta deterius. quibus ego assentior, dum modo de isdem rebus ne Graecos quidem legendos putent. res vero bonas verbis electis graviter ornateque dictas quis non legat? nisi qui se plane Graecum dici velit, ut a Scaevola est praetore salutatus Athenis Albucius.
</div>
</div>
</div>
<!--[if IE 7]></td></tr></tbody></table><![endif]-->
По большому счёту, это извращение — ибо проще всего использовать таблицу для всех браузеров. Но проще не значит лучше, ибо очень часто встречаются ситуации, когда заказчики требуют, чтобы вёрстка была семантической (а когда видят "незапланированную таблицу", начинают громко ругаться). Правда, в этом случае для IE7 семантика теряется, но, как заметил Максим Покровский, для него [IE], вообще, много чего теряется…
.
Итак, для комбинированного решения у нас получаются следующие стили для IE:
text-align: center;
}
* html #outer {
position: relative;
}
* html #middle {
top: 50%;
position: relative;
width: 100%;
overflow: auto;
}
* html #inner {
position: relative;
top: -50%;
overflow: auto;
}
*:first-child+html table.outer {
height: 100%;
width: 600px;
margin: 0 auto;
}
*:first-child+html table.outer tbody {
vertical-align: middle;
}
Результат можно посмотреть на этой странице.
Есть еще один вариант решения, но он полагается на использование JavaScript в IE:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Centering</title>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
html {
display: table;
overflow: auto;
}
body {
display: table-cell;
vertical-align: middle;
}
.item {
margin: 0 auto;
width: 600px;
}
</style>
<!--[if lte IE 7]>
<style type="text/css">
* > html body {
text-align: center;
}
.item {
margin-top: expression(this.offsetHeight < this.parentNode.offsetHeight ? parseInt((this.parentNode.offsetHeight - this.offsetHeight) / 2) + 'px' : 0);
}
</style>
<![endif]-->
</head>
<body>
<div class="item">
Ego autem quem timeam lectorem, cum ad te ne Graecis quidem cedentem in philosophia audeam scribere? quamquam a te ipso id quidem facio provocatus gratissimo mihi libro, quem ad me de virtute misisti. Sed ex eo credo quibusdam usu venire; ut abhorreant a Latinis, quod inciderint in inculta quaedam et horrida, de malis Graecis Latine scripta deterius. quibus ego assentior, dum modo de isdem rebus ne Graecos quidem legendos putent. res vero bonas verbis electis graviter ornateque dictas quis non legat? nisi qui se plane Graecum dici velit, ut a Scaevola est praetore salutatus Athenis Albucius.
</div>
</body>
</html>
Результат можно посмотреть здесь.


Жаль, что Вы не посчитали нужным поставить ссылочку на мой оригинальный перевод статьи.. Неужто ссылка на западный источник более “в тему”, чем русскоязычный аналог (( Обидно…
Всеволод, если Вы внимательно посмотрите, ссылка на Вашу статью (и даже без rel=”nofollow”) дана в самом начале, в самом первом предложении. Кстати, trackback на Вашем сайте это подтверждает
Edit: я перефразировал первое предложение, чтобы сделать ссылку на Вас более заметной.
Владимир, искренне извиняюсь… (((( Не заметил…
I didn’t agree with you first, but last paragraph makes sense for me…