войти зарегистрироваться

Способ вертикального выравнивания блока с помощью настоящего vertical-align

Сегодня, верстая один макет, я, кажется, изобрел очередной небезынтересный способ вертикального выравнивания блока относительно родительского. Он не основан на превращении блоков в ячейки таблицы и не использует css-свойство position.

Требования

— Должна быть известна начальная высота родительского блока;
— Дочерний блок может иметь произвольный размер как по высоте, так и по ширине.

Возможности

— Работает в IE6+, O9+, FF2+, webkit;
— Тру vertical-align выравнивание со всеми допустимыми значениями;
— Одинаковое поведение во всех браузерах (незначительные отклонение при некоторых условиях в ие6 будут оговорены ниже);
— При вырастании дочернего блока выше «папочки», родительский блок расширяется;
— Ни грамма Javascript.

Итак, для начала рассмотрим заготовку, которую я хочу использовать для рассказа.
Мы имеем блок .container фиксированной высоты 200px и находящийся внутри него блок с текстом, пусть для определенности нам нужно выровнять его по середине родительского контейнера. Также я добавил снизу обычный текст, который при малой ширине окна перекрывается текстом из контейнера. От этого неприятного эффекта мы тоже избавимся.

Трансформация номер раз


Know how моего метода заключается в том, что вместо того, чтобы указывать настоящую высоту блока .container, мы указываем line-height в те же 200px, а дочерний блок делаем встроенным блоком (display: inline-block;). Самая большая неприятность, которая поджидает во всем методе, заключается в том, что значение line-height наследуется на дочерний блок и для него его придется задать еще раз:
.container {
  line-height: 200px;
}
.block {
  display: inline-block;
  line-height: 1.2;
  vertical-align: middle;
}

И мы получаем вот такую страничку, уже работающую в IE8, O9+, FF3+, webkit. Как я и обещал, при уменьшении окна до такого размера, когда дочерний элемент становиться выше родительского, родительский растягивается. Я нарочно заостряю на этом внимание, так как данное поведение может очень и очень пригодиться в реальных макетах, когда маленький заголовок лучше смотрится посреди строки, а большой должен раздвигать следующий далее контент.

Трансформация номер два


Достигнув такого результат я конечно обрадовался, но естественно, я не верил в успех, пока не проверил в ие6 и 7 и, как оказалось, не зря. На самом деле не все так страшно, как кажется. Ответ на первый вопрос, который у меня возник, я знал заранее: старые ИЕ не могут применять значение display: inline-block к изначально блочным элементам. Сказано-сделано, <div class="block"> без сожаления был заменен на <span class="block">
Но в данном случае это было бестолку и я все равно имел то, что изображено на картинке слева:
image
Почесав репу я за каким-то решил проверить, что будет, если после inline-block элемента поставить настоящий инлайновый элемент, скажем текст. Как ни странно это возымело нужное действие и я получил то, что на картинке справа. Ну что-ж, запишем в копилку глюков ИЕ еще один: одиночный инлайн-блочный элемент принудительно становиться блочным. Осталось только упаковать новый инлайновый элемент так, чтобы он не мешал другим браузерам и не занимал места. Получилось как-то так:
<style type="text/css">
  .iefix {
    display: none;
  }
</style>
<!--[if lte IE 7]>
<style type="text/css">
  .iefix {
    display: inline-block;
    width: 0;
    overflow: hidden;
  }
</style>
<![endif]-->
<div class="container">
  <span class="block">
    Lorem Ipsum is simply dummy text of the printing and typesetting industry.
    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
  </span>
  <span class="iefix">&nbsp;</span>
</div>

* This source code was highlighted with Source Code Highlighter.

Оставить .iefix чисто инлайновым элементом тоже не получилось, ибо width и overflow применимо только к блочным элементам. Этот же вариант заработал в ие6 без изменений.
Теперь уже пример работал во всех браузерах, которые меня интересуют при верстке кроме FF2. Стоит отметить только один глюк в ИЕ6. Когда размер элемента с текстом уменьшается до размера самого большого слова (или другого элемента, которого невозможно разбить на несколько строк), ИЕ6 все-таки переносить элемент нулевой ширины .iefix на другую строчку, отчего высота всего блока увеличивается на 200 пикселей (величина line-height):
image

Трансформация номер три


Ну и на закуску остался FF2, который как известно, не понимает инлайн-блоков, но может это эмулировать через значение display: -moz-inline-stack;. Свойство -moz-inline-stack требует чтобы его содержимое было обернуто в еще один блок, поэтому HTML код здесь немного разрастается:
<div class="container">
  <span class="block">
    <span>
      Lorem Ipsum is simply dummy text of the printing and typesetting industry.
      Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
    </span>
  </span>
  <span class="iefix">&nbsp;</span>
</div>

* This source code was highlighted with Source Code Highlighter.

Стоит отметить, что FF2 не захотел переносить текст, поэтому пришлось явно задать блоку с текстом width: 100%; в принципе это не так страшно, скорее всего реальная страница будет подразумевать конкретные значения для ширины текста.

В результате получился отличный способ вертикального выравнивания во всех популярных браузерах.

комментарии (53)

  • Отлично!
  • Правильно ли я понял, что весь бенифис метода — использование line-height и inline-block?
    • В правильных браузерах да.
  • старые ИЕ не могут применять значение display: inline-block к изначально блочным элементам.
    Давно известен обходной маневр против этого: display:inline + включенный hasLayout (напр., через zoom:1).
    • Такой вариант тоже работает без проблем, просто я больше привык к описанному выше, меньше кода в css. Кто с вопросом знаком, сам выберет себе по душе.
  • А где html-nazi, которые должны прибежать и кричать, что код для ФФ2 несемантичен?
    • Заменил тег.
      • И стало семантичным?
        Я не претендую на истинность утверждения, но имо, семантично == не имеет элементов-оберток и пустых тэгов. Разве не так? Если так, то код все равно таким остается.
        • Вы можете пользоваться любым другим семантичным кросбраузерным способом вертикального выравнивания. На сколько мне известно, их ровно ноль.
          • Так я и не являюсь вышеназванным наци. Я так, любопытствую.
        • Извините, но у Вас не совсем правильное понимание слова Семантика — система правил определения поведения отдельных языковых конструкций. Семантика определяет смысловое значение предложений алгоритмического языка.
          В верстке использование оберточных блоков следует избегать по возможности, но это не обязательное правило: если Вы дадите оберточному блоку класс из которого будет понятно что этот блок делает, что именно он оборачивает — семантика практически не пострадает.
          • Кстати, да. В последних редакциях HTML5 эти «смысловые обертки», наоборот, начали не по-детски плодиться по принципу матрешки.
    • Имхо, ради официально призннаного умершим FF2 с его жалким одним процентом в самых оптимистичных статистиках можно уже вообще не заморачиваться. Это даже не IE6 с его пока заметной долей в корп. секторе.
      • и не говори, его «пока заметная доля» каких-то жалких 25%. Сдается мне, счастье быстро не наступит.
        • Так а я о чем все время говорю… я вообще оптимист по жизни, но нужно же быть хоть сколько-то реалистами: IE6 жив пока жива на Земле глупость, а это очень и очень долго и если честно я вижу в этом и положительные стороны: именно этот дибильный IE6 многих из нас заставляет совершенствовать свои знания быстрее чем мы это можем делать :)
  • cssing.org.ua/2005/07/14/vertical-align-middle/
    cssing.org.ua/examples/valign/index1.html
    • Способ хоть и похожий, но на другом принципе.
  • А что если высота контейнера неизвестна (определяется другим контентом)? Есть ли способ?
    • Есть. Через display:table-cell; для нормальных браузеров и небольной expression для IE. Всё это есть в комментарии выше. (Ладно, не удержусь и дам ссылку: cssing.org.ua/2007/04/26/another-css-valign-method/)
  • Стало грустно после «Должна быть известна начальная высота родительского блока;»
    А так неплохо. О line-height мало кто помнит. Кстати, для IE inline-block элементы проще верстать span'ами, и к черту семантику.
    • ну здесь помоему фигня больше не в семантике, а в непредсказуемости поведения вложенных блоков, нужно будет потестить на приближенных к реальности примерах: вот у меня есть версия что проблемы начнуться, когда мы внутрь .block поместим дивы с float: left; и float: right;
      Если пройдет испытание временем — то такой метод мне кажется неплохим и span'ы его сильно не испортят
    • тогда уж лучше ins — в него можно оборачивать блочные элементы, и сам он строчный при этом. и с бааальшой натяжкой можно будет сказать, что семантика соблюдена) — элемент по названию предназначен для вставки чего-либо (INSert), ну так мы и добавляем
      • А давайте навалим дивов, только чтобы была семантика.
        Был у меня один заказчик, просил таблицы на 6 столбцов верстать дивами, потому что таблицы — это не семантично вообще. Убедил-таки.
      • в него можно оборачивать блочные элементы, и сам он строчный при этом

        Это заблуждение. То, что валидатор на это не ругается — лишь свидетельство его тупости, вызванной недостаточностью выразительных средств DTD :)

        Спецификация однозначно говорит, что
        The INS and DEL elements must not contain block-level content when these elements behave as inline elements.
  • Супер, спасибо!
    Буквально на днях столкнулся с такой проблемой, а вот уже и решение =)
  • раскрыть комментарий
    • Кстати говоря, «Баян» уже давно сам стал баяном.
      • объяснит кто-нибудь, за что минус?
        слово «Баян» уже реально надоело, все кому не лень им отписываются, похоже ради того, дабы отписаться, лучше тогда молчать и мысленно не соглашаться с мнениями.
        • Да. ты прав. лучше молчать. Но то что написали, очень древняя вещь для тех, кто умеет верстать
          • Подскажите что-то поновее?!
            • Более нового ничего нет. Это решение весьма оптимальное, и по крайней мере работает везде. У меня просто нет времени, чтобы заниматься рукоприкладством и искать новые неизведанные способы. Ничего нет проще того, что уже работает
  • раскрыть комментарий
    • не все, я не знал… почему-то каждый наталкиваясь на знакомый метод считает нужным прокомментировать это… при том что давно всем известно, что действительно новые изобретения случаются крайне редко, тем более в нашей стране, все равно все так или иначе заимствованно из-за бугра, а вот то что многие статьи почти полностью копипастятся внутри самого хабра по 5 раз мало кто замечает…
  • Я совсем недавно изучал вопрос и вот одна из возможных ссылок: haslayout.net/css-tuts/Vertical-Centering
    Изобретения не вышло.
  • white-space: nowrap
    • Это помогает выровнять по вертикали? Или просто в качестве «суперклея» для строки инлайн-блоков?
  • еще один источник www.cssplay.co.uk/ie/valign.html
    • Источник чего? Ни в одном браузере не заработало.
  • Красивое решение. Жаль только, что с DOCTYPE Transitional не работает.
    • ???
      • Попробуйте вместо HTML 4.01 Strict, который используется в примерах, задействовать HTML 4.01 Transitional или XHTML 1.0 Transitional.

        P.S. Зато в HTML5 работает.
        • Ух ты. И действительно, в Опере 10 line-height не растягивает высоту блока, а в IE8 растягивает, но не центрирует… Такой тонкости Almost Standards mode я не знал (я думал, оно только про картинки...), спасибо! Интересно, чем это объясняется?

          Забавно, что в IE6-7 разницы нет, т.к. там нет Almost Standards. Эх, мозилла-мозилла, как же ты в 2001-м намудрилла… :)
          • Точно, я забыл уточнить, что смотрел в Opera 10.
  • ссылки на Стью Никольса и прочих, можно хоть целый день кидать, а тут вот, Наш человек решил задачу по-новому, ну, разве это не здорово? =)
  • Все бы хорошо, если бы не практически полная бесполезность примера: ну где вы найдете блоки с фиксированной высотой, да еще и в пикселях?? (хотя line-height можно и в em задать конечно)
    • ну где вы найдете блоки с фиксированной высотой, да еще и в пикселях??
      В данном случае, как раз способ был найден для конкретного применения, а не наоборот:
      image
    • На практике это встречается. Не надо говорить о бесполезности.
  • Думаю как клёво что придумали.
    Смотрю в код, а там марин-топ 100пх, лайн-хейгт 200пх и в transitional не работет ;)
    • Не понял, что не так с марин-топ 100пх?
      • Затупил, сорри.
        Но что делать с Transitional не ясно ;)
  • это, конечно, валидно и лаконично, но старая занудная таблица потребует меньше итогового кода…
  • Замечательно! Осталось научиться писать ногой и ходить на руках.
  • Остроумное решение, но как по мне: слишком много «хаков» и усложнений, использовать врятли буду.
Только авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста.