Пользователь
0,0
рейтинг
9 апреля 2011 в 14:45

Разработка → Кроссбраузерный inline-block перевод

CSS*
Разрешите представить вам перевод статьи «Cross-Browser Inline-Block», написанной Райном Доэрти холодным февралем 2009 года. В статье рассказывается о верстке элементов списка с установкой для свойства display значения inline-block. Статья об этом, а также о трудностях, возникающих в процессе достижения результата и о методах их «лечения».



Inline-block, заманчивое значение для свойства display, которое обещает очень много, а выполняет совсем мало. Очень часто я получал PSD-файлы, подобные этому:


и плакал.

Обычно такой способ отображения не вызывает проблем. Фиксированная ширина, фиксированная высота, float: left и готово. Если бы не одно, но! Дизайн должен отображаться корректно при любом количестве содержимого. В нашем случае, если в одном из блоков окажется чуть больше данных, то он «сломает» всю сетку.



Так как первый элемент выше следующих, пятый становится не под ним, как нам того хотелось бы, а «обтекает» по правому краю. В общем, нам необходима эластичность таблицы, но в правильной, семантичной верстке.

Начнем с простого примера, где у пунктов списка для свойства display установлено значение inline-block:

<ul>
    <li>
        <h4>This is awesome</h4>
        <img src="1450821541436477177797"
        alt="lobster" width="75" height="75"/>
    </li>
...
<ul>

<style>
    li {
        width: 200px;
        min-height: 250px;
        border: 1px solid #000;
        display: inline-block;
        margin: 5px;
    }
</style>


Результат выглядит корректно в Firefox 3, Safari 3 и в Opera:



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

А происходит здесь следующее, базовая линия (baseline) каждого элемента <li> выравнивается с базовой линией родительского элемента <ul>. Вы спросите, что такое базовая линия? Лучше один раз увидеть, чем сто раз услышать:



Базовая линия на рисунке выше обозначена линией, идущей через основание символов. Значением по-умолчанию для свойства vertical-align у inline и inline-block элементов является baseline. Это значит, что базовая линия элементов выравнивается с базовой линией родителя. На рисунке ниже представлен пример такого выравнивания:



Как видите, каждая базовая линия блоков на рисунке выше выравнена по базовой линии текста «This is the baseline», который не является элементом <li>. Это просто текстовый узел, находящийся непосредственно в <ul>, помещенный туда в качестве индикатора расположения базовой линии элемента <ul>.

Получить желаемый изначально вариант выравнивания довольно просто, достаточно для свойства vertical-align указать значение top и получить в результате отличную сетку:



Вот только это не работает в Firefox 2, IE 6 и 7:



Для начала займемся Firefox 2.

Firefox 2 не поддерживает значение inline-block, зато отлично понимает специфичное для Мозиллы значение -moz-inline-stack для свойства display. Оно приводит к результатам, подобным действию inline-block. Когда мы добавляем его перед display: inline-block, то Firefox 2 игнорирует вышеуказанное, так как не понимает его, и использует -moz-inline-stack. Другие браузеры используют inline-block, игнорируя непонятное для них -moz-inline-stack.

<style>
    li {
        width: 200px;
        min-height: 250px;
        border: 1px solid #000;
        display: -moz-inline-stack;
        display: inline-block;
        vertical-align: top;
        margin: 5px;
    }
</style>


К сожалению, это вызывает небольшой баг:



Честно, я не знаю, что является его причиной. К счастью, лечится он довольно просто обертыванием всего содержимого элемента <li> дополнительным <div>.

<li>
        <div>
            <h4>This is awesome</h4>
            <img src="1450821541436477177797"
            alt="lobster" width="75" height="75"/>
        </div>
</li>




Теперь перейдем к IE 7. Он тоже не поддерживает inline-block, но мы можем использовать трюк, благодаря которому элементы <li> будут выводиться на экран так, будто используют значение inline-block. Как? Будем использовать hasLayout, волшебное свойство IE, делающее доступными многие манипуляции. Вы не можете явно указать для элемента hasLayout: true или сделать это каким-либо подобным простым образом, однако можете запустить механизм, указав zoom: 1.

Технически элементы с hasLayout, установленным в значение true сами отвечают за рендеринг самих себя и дочерних элементов. Объедините это с min-height и width, и получите результат, очень близкий к display: block. Это как магический порошок, заставляющий исчезать все появляющиеся при отображении проблемы.

Когда мы добавим zoom: 1 и *display: inline (звездочка является хаком для IE 6 и IE 7) для элементов <li>, то научим IE 7 отображать их совсем как inline-block:

<style>
    li {
        width: 200px;
        min-height: 250px;
        border: 1px solid #000;
        display: -moz-inline-stack;
        display: inline-block;
        vertical-align: top;
        margin: 5px;
        zoom: 1;
        *display: inline;
    }
</style>




Почти готово. Остался лишь IE 6:



IE 6 не поддерживает min-height, но взамен мы можем использовать его неверное обращение к свойству height. Установим для _height (обратите внимание на подчеркивание спереди) значение в 250px и получим все элементы <li> с нужной высотой. Если же содержимое превысит указанную величину, то просто растянет свой контейнер. Все остальные браузеры проигнорируют _height.

Финальный CSS и HTML выглядит так:

<style>
    li {
        width: 200px;
        min-height: 250px;
        border: 1px solid #000;
        display: -moz-inline-stack;
        display: inline-block;
        vertical-align: top;
        margin: 5px;
        zoom: 1;
        *display: inline;
        _height: 250px;
    }
</style>

<li>
        <div>
            <h4>This is awesome</h4>
            <img src="1450821541436477177797"
            alt="lobster" width="75" height="75"/>
        </div>
</li>
Перевод: Ryan Doherty
Павел Рыбин @drfisher
карма
43,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (65)

  • +9
    • +9
      Неясно почему минусуют. Ведь была уже статья, кто-то переводил раньше уже. Зачем делать одну работу несколько раз?
    • +5
      chikuyonok.ru/2011/04/inline-vertical-align/ статья от всеми нами любимого автора Сергея Чикуёнка — подход очень похожий
  • +4
    На самом деле, для укрощения старых IE достаточно использовать тэги, которые по умолчанию ведут себя как inline-block: например, ins и del.
    <ins style="display: inline-block;width: 25%; ">
    <div style="float: left; width: 100%;">
    это инлайн-блок
    </div>
    </ins>
    

    Вот пример использование, когда товары в магазине автоматически выстраиваются в подходящее число колонок по ширине в зависимости от ширины окна браузера (надеюсь не рухнет). Сам метод описывал еще лет 5 назад один из сотрудников студии Лебедева (по крайней мере я узнал от них).

    Может это и не самое кошерное решение с точки зрения семантики, зато оно простое и главное работающее без хаков под каждую версию браузера.
    • 0
      Единственное, у вас в конце, где 3 букета, они выравниваются по середине.
      • 0
        Это настройки общего дива, в котором все инсы.
    • +6
      «для укрощения старых IE достаточно использовать» любый inline элементы + hasLayout
    • 0
      Крайне некошерное, данные должны быть отдельно, а оформление отдельно.
      Все рецепты, содержащие дополнительное обёртывание или замену тега, противоестественны.
      • +1
        Да, в идеальном мире для идеального браузера. Я еще не видел настоящей кошерной верстки, рассчитаной на весь сегмент браузеров от хотя бы ie7 и выше — везде так или иначе приходится добовлять хотя бы один лишний элемент.
        • 0
          Значит её нет, раз вы её не видели.
      • НЛО прилетело и опубликовало эту надпись здесь
        • –2
          Только если ему не следовать.
  • 0
    Полезная вещь.
    Я делал по другому: брал все в дивы и после 4го дива писал
    • +1

    • 0
      <br clear="all" />

      получилось ;)
      • –1
        Наверное, все же clear=«both»?)
        • 0
          Нет, именно так, попробуйте.
          • 0
            Да-да, у вас как атрибут, а я имел в виду стиль.
        • +1
          тьфу блин,
          <br style="clear:both">
          • –1
            А зачем делать это стилем если есть атрибут? Да и способ не лучший.
      • +3
        Смысл как раз в том, чтобы число элементов попадало в одну строку автоматически. Даже таблицей так не сверстать…
        • 0
          Это же программированием решается, и уже не важно что там в верстке)
          • 0
            В зависимости от ширны окна уместить либо три либо пять либо семь блоков?
            • 0
              о, нет, конечно (речь о таблицах)
            • 0
              Чем вам поиск по яндекс.картинкам не пример?
  • +4
    zoom: 1;
    display:-moz-inline-box;
    -moz-box-orient:vertical;
    display:inline-block;
    _display:inline;
    *display:inline;
    vertical-align: top;

    По-моему работает без всяких обверток в лишние div, в том числе в FF2.
    • +8
      Я уже забыл, когда видел последнего посетителя с ФФ2
      • +4
        Ну это для понта.
      • 0
        Прочитав Ваш комментарий, решил посмотреть как обстоят дела на моём сайте ит-шной наклонности.
        Знаете, у меня есть заходы не то что с Fx2, но даже с Fx1.5, хотя они все в пределах статистической погрешности:
        img
    • +2
      не тру. Сначала идет _хак для ИЕ6, затем общий зак для 6 и 7 — *.
      В данном случае этот _хак не нужен, звездочка все равно к обоим применится.
      • –1
        Звездочка, насколько я помню из детства, только с IE7 работает. Согласен, что можно заменить на комментарий "//", чтобы оставить одну декларацию.
        И перед zoom еще, чтобы Safari исключить.
        • +3
          Виноват. И вправду на IE6 срабатывает. Детство мое было неправильное.
  • НЛО прилетело и опубликовало эту надпись здесь
    • –2
      ничего не исчезает, не знаете сути проблемы не пишите чушь
      • –1
        Возьмитесь за правый край старого осла (гг) и подергайте сверстанный по статье сайт влево-вправо. Поймете, о чем речь.
  • +9
    Чем дольше поддерживаешь IE6, тем дольше он проживет.
    • +5
      Ну на самом деле тихий консенсус в отрасли состоит в том, чтобы по-умолчанию поддерживать IE6 лишь частично. То есть верстка не должна разваливаться, а сам сайт должен оставаться рабочим, но попиксельной точности уже никто не требует.
  • +3
    Я в таких случаях просто использую таблицу. Несмотря на то, что идеалогически это куда более худшее решение, оно значительно быстрее рендерится в браузерах.
  • 0
    Несколько дней назад столкнулся с подобной проблемой — допилил функционал сортировки таблицы на мониторинге, в итоге заметил неправильное отображение в ИЕ7 (под ИЕ6 — не делали, согласно ТЗ) ссылок из серии Добавить в закладки/избранное/на сайт. display: inline-block в ИЕ7 не работал почему-то.
    Оказалось, если в <div>`е есть несколько <a> и <p>, то inline-block — не работал, а inline — не поддерживает border как надо. Выход — замена <p> на <span> — возможно, технологи скажут, что это семантически неверно, но работает.
    • 0
      Сохранять семантику при ие7 — тяжкое дело. А заказчик упёрто пытается указывать на «таблицы для нетабличных данных».
  • +2
    • +1
      Ссылку на статью для этого перевода я нашел именно там )
  • +2
    CSS-хаки можно использовать более элегантно:

    li {
    min-height: 250px;
    height: auto !important; // IE6 в одном селекторе игнорирует important
    height: 250px;
    display: inline;
    display: inline-block; // IE такого не знает и воспользуется предыдущим свойством
    zoom: 1;
    }
    • +3
      два слеша не являются комментариями в css
      • +3
        Ну это же не css-файл :) Лень было просто.
    • НЛО прилетело и опубликовало эту надпись здесь
  • –2
    Превосходная статья, не встречал раньше подобного метода. Теперь буду использовать! Спасибо за перевод.
  • –5
    Хорошее решение. Но я бы использовал джаваскрипт, просто чтобы выровнять высоту всех блоков по самому высокому +3px
    И тоже самое при попытке изменить размер окна
  • +1
    Легендарная прямо таки статья
  • 0
    FF2 уже вне игры, хаки для IE в эпоху Conditional Comments смотрятся как атавизм.
    Что еще удивительно, нашлось немало тех, кто за два года с выхода статьи, ни разу на неё не наткнулся.
    Или это хабр глючит выдавая архивные посты?
    • –1
      Нее, просто Чикуёнок мимоходом упомянул эту статью, вот все и кинулись читать.
  • +1
    Во-первых firefox 2 уже давно морально устарел и вот это можно выкинуть
    display: -moz-inline-stack;
    Во-вторых на резиновых сайтах возникали проблемы с таким кодом для firefox 2, так что там все чуть сложнее было, если кому надо могу поискать решение
    В-третьих вы не решили проблему отступов у inline элементов, тоесть если убрать маргины то блоки будут не вплотную друг к другу стоять. Там нужно у контейнера несколько параметров обнулить, а у вложенного тега все восстановить.
    Ну и код для ие6 — 7 лучше выносить в CC, но это и так все знают ))
    • 0
      Вот кстати сниппет, для того чтобы убрать отступы между inline-block блоками
      snipplr.com/view/49933/display-inlineblock-/
      может кому пригодится
      • НЛО прилетело и опубликовало эту надпись здесь
    • +1
      Еще -moz-inline-stack; не работал в связке с position:relative;, а в Opera inline-block + relative переодически глючит до сих пор.
  • 0
  • –1
    И тут на помощь приходит дремучий. Как ни странно, это было бы лучшим решением.
  • –2
    Пардон. Дремучий table
    • 0
      Вы не поняли, в чём проблема table. А проблема эта в том, что table не умеет переносить ячейки на новую строку или оставлять на предыдущей в зависимости от ширины окошка.
      • 0
        Резиновая верстка…
        Я inline-block использую, когда нужно сделать горизонтальное ul-меню, чтобы оно размещалось в центре блока, т.е. реагировало на text-align: center;

        Пока другого подобного решения не встречал.
  • +2
    Да, хороший рецепт. 10 июня прошлого года я приводил гиперссылку на сборник, состоящий из этого и нескольких других преполезнейших рецептов (общим числом полсотни), так что очень рад, что у Вас дошли руки перевести один из них. Поглядите на них — быть может, и другие приглянутся для перевода или хотя бы употребления.
    • +1
      Спасибо, обязательно посмотрю.
    • +1
      Вечера доброго!
      А можно еще раз ссылочку, а то этот адрес уже канул в неизвестность?
      • 0
        По-видимому, та блогозапись была уничтожена физически из-за какого-то глюка Хабрахабра или стёрта модераторами хаба CSS. Сейчас я не нахожу в своём блоге ни одной блогозаписи от 10 июня 2010 года.
  • 0
    Привет вам из позапрошлого года.

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