Равномерное выравнивание блоков по ширине

    Продолжая свои «css-раскопки» возникла новая идея, разобрать по косточкам ещё одну актуальную тему, которая касается равномерного выравнивания блоков по ширине. В принципе мои доскональные исследования я уже запостил у себя в блоге, но так как прошлая моя работа очень понравились Хабра-сообществу, то я решил сделать здесь небольшой краткий обзорчик этой статьи, чтобы ни одна хабра-душа не пропустили её наверняка. Так что, как говорил Гагарин: «Поехали».

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

    На рисунке видно, что пункты выравниваться по ширине, примыкая к боковым стенкам и делая отступы между собой – равнозначными.

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


    По сути, мы должны получить то, что делает text-align: justify с текстом. Так как поведение наших блоков уж очень напоминает результат выравнивания слов в строке с помощью именно этого свойства. Думаю многие уже примерно представляют, что это за свойство и примерную его работу.

    *В этом обзоре я не стал постить разбор этапов всего алгоритма, об этом можно почитать в самой статье. Главное, чтобы вы понимали суть.

    Наша задача


    Наша задача состоит в том, чтобы построить решение на базе этого алгоритма. Применить, симулировать, заменить, сделать всё что угодно, главное в итоге получить то, что мы хотим. А именно – равномерно выровненные элементы в строке, боковые из которых прижаты к своим границам. Ну и конечно же расстояния (пробелы) между этих элементов должны быть абсолютно одинаковыми при любой ширине контейнера.

    * Сразу хочу сообщить, что вариантов (рабочих и не очень) на самом деле получилось целых 4 штуки, плюс ещё куча интересных и полезных разобранных нюансов, на огромную статью (в моём стиле). Поэтому тут я вкраце опишу некоторые из них :)

    Варианты 1 и 2


    Самое первое, что пришло мне на ум, это взять список из пяти пунктов и построить выравнивание на старых-добрых float-ах, поэтому я смастерил два варианта (один, два), которые к сожалению оказались не совсем универсальными. Точнее первый из них вообще не прокатил, а второй оказался вполне себе рабочим, но только лишь для фиксированной ширины пунктов.
    Кому интересно подробное исследование этих вариантов, милости прошу в саму статью.

    Варианты 3


    А вот третий вариант уже построен на самом алгоритме text-align: justify и инлайн-блоках, которые и принесли свои плоды, но не совсем. Во-первых, мне пришлось разбавить список лишним, дополнительным элементом, а во-вторых, в IE6-7 обнаружились интересные факты, рыться в которых мне доставило большое удовольствие. В этих браузерех данное решение отказывалось работать вообще. И догадайтесь, кто пришёл мне на помощь. Верно, SelenIT2! Но он пришёл ни один, а с великолепной идеей (которую он нагло спёр у нашего общего коллеги по цеху GreatRash), от которой я был просто в шоке. Как оказалось, пара волшебных свойств CSS3 родом из глубокой древности может превратить это решение в кроссбраузерное и заставить работать text-align: justify в наших старичках IE6-7.

    третий вариант

    Весь секрет оказался в последней строчке следующего кода:
    <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li class="helper"></li>
    </ul>
    

    ul {
            font: 14px Verdana, Geneva, sans-serif;
            text-align: justify;
    
            /* Обнуляем для родителя*/
            line-height: 0;
            font-size: 1px; /* 1px для Opera */
    
            /* Лекарство для IE6-7*/
            text-justify: newspaper;
    }
    

    Как видно, с помощью text-justify: newspaper; у ul наш вариант становится кроссбраузерным. Это происходит за счёт того, что свойство text-justify: newspaper предназначено для увеличения или уменьшения интервалов между буквами и между словами. MSDN заявляет, что эта вещь «Самая навороченная форма выравнивания для латинского алфавита», а вот в этой статье ещё есть и дополнение, что для арабских текстов это свойство вытягивает и сами буквы.

    Варианты 4


    Ну, и вариант 4 стал отказом от дополнительной разметки, что повлекло за собой новые проблемы в IE6-7.
    image
    Оказывается всё дело в том, что text-justify: newspaper лишь даёт возможность растягивать наши буквы (inline-block), но не команду. Проще говоря, он рассказывает строке, как бы он хотел, чтобы она была растянута, а text-align: justify является растягивающей силой. Т.е. text-align: justify отвечает за растяжение строки, а text-justify: newspaper лишь уточняет, как именно это растяжение будет происходить.

    В обзоре 3-го варианта я сказал, что SelenIT2 подсказал мне два свойства, одно из которых (text-justify: newspaper) помогло нам в предыдущем варианте, а другое как раз помогло в этом! Причём в этот раз они объединились и уже с двойной силой смогли победить последний вариант.
    ul {
            font: 14px Verdana, Geneva, sans-serif;
            text-align: justify;
    
            /* Обнуляем для родителя*/
            line-height: 0;
            font-size: 1px; /* 1px для Opera */
    
            /* Лекарство для IE6-7*/
            text-justify: newspaper;
            zoom:1;
    
            /* Включаем в работу последнюю строку*/
            text-align-last: justify;
    }
    

    Встречайте! text-align-last — свойство, которое включает алгоритм text-align: justify в самой последней строке текста, если к ней применён этот самый text-align: justify. Проще говоря, когда мы применяем к тексту обычный text-align: justify, то, видя это, text-align-last указывает первому на то, что он поступает плохо и что ему придётся теперь работать и в последней строчке тоже.

    И вот, собственно, результат

    Кстати, эти свойства специфицированы, а не какая-нибудь проприетарщина (кроме значения newspaper, которое теперь называется иначе). Так что ни один котенок не пострадает) И хочу подчеркнуть, что баг IE6-7 поборен с помощью CSS3 — кто еще когда такое видел? :)

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

    Если краткого обзора кому-то показалось мало, то я рекомендую прочитать вот эту (уже большую) статейку с доскональным разбором полётов. Но, предупреждаю! Статья действительно не маленькая, поэтому перед началом чтения лучше запастись вашими любимыми печеньками с чаем :)
    Поделиться публикацией

    Похожие публикации

    Комментарии 87
      +3
      Спасибо огромное! Сам собирался исследовать этот вопрос и написать статью, но никак не мог выкроить времени, а тут все предельно подробно, замечательно.
        +3
        Пожалуйста. Изучайте на здоровье!
          +5
          не говорите это моему дизайнеру, неделю назад я его уверял, что это невозможно…
        0
        Слушайте, у вас в примере 3 ширина блоков задана жестко — где это может вообще пригодиться? По моему, задача обычно бывает другая — равномерно распределить блоки произвольной (определяемой контентом) ширины с равными пробелами между ними.

        Хотя, конечно про свойство text-justify почитать интересно. Майкрософт изобрела часть CSS3 еще лет 10 назад.
          +2
          в примере поставил width: 19% вместо 98px и все гуд работает, а это вообще тру тру тру ))) Спасибо автору )
            +2
            Буквально вчера решал задачу, аналогичную описанной. Нужно было три баннера расположить по ширине родительского контейнера. Так что вы зря, проблема «рабочая».
              +2
              Проблема «рабочая» еще и потому что в Photoshop есть такой способ выравнивания объектов, уже не раз присылали на верстку макеты, где элементы были выровнены подобным образом.
            +4
            Ширина выставлена для наглядности примера. Вы смело можете убрать её, если пожелаете. Так что задача «равномерно распределить блоки произвольной (определяемой контентом) ширины с равными пробелами между ними» — решается :)

              +8
              Я джва года ждал этого решения. Долой старые костыли! Запасаюсь печеньем…
                +2
                Спасибо!!! Когда смог решить эту задачу только с применением jQuery.
                  +5
                  Супер! Раньше использовал отрицательный сдвиг ul, и рассчитывал отступы так, чтобы последний оказывался прижат к правому краю.
                  Теперь всё будет проще :)
                  Спасибо большое, Максим.
                    +2
                    Очень круто. И самое главное, изящно.
                      +2
                      Большое спасибо за статью! До этого пользовалась решением, описанным здесь: habrahabr.ru/blogs/css/81611/
                        +1
                        Ой, ёй, ёй, сколько разметки лишней. Хорошо, что всё таки удалось более затратные и изящные решения!
                          +2
                          Дополнительной разметкой можно не пользоваться, она нужна для правильного абсолютного позиционирования внутри инлайн-блоков. В принципе, целью было сделать абслоютно одинаковую реализацию инлайн-блоков во всех браузерах :) а выравнивание там заодно приплетено.

                          Способ выравнивания, сам по себе, очень старый — можно даже вообще без лишней разметки (.helper) обойтись, т.к. в IE newspaper и так всё решит, а в нормальных браузерах всё решается с помощью псевдоэлементов
                        0
                        А чем не устраивает :last-child + expression для IE?
                        • НЛО прилетело и опубликовало эту надпись здесь
                            –1
                            Для IE6 точно нужен expression, IE7 не помню. А так уверен…
                              +3
                              А зачем expression, если в посте представлены решения без него?
                                –2
                                В 2-3 раза меньше кода для нормальных браузеров, да и решение с :last-child проще для понимания. А вообще использовать готовую сетку и не думать о таких вещах.
                                  +1
                                  Если бы речь шла о «в 2-3» раза меньше кода 500-а строк, то да, разница была бы на лицо, а в последнем варианте, например, кода ерунда и игра с expression не стоит свеч, мне кажется.

                                  Но, не смотря на это, было бы полезно взглянуть на реализацию такого примера. Сможете сделать?
                              • НЛО прилетело и опубликовало эту надпись здесь
                            +4
                            Забавно одну за другой видеть хорошо разобранные темы, о которых сам хотел написать статью…
                            А про выносные таблицы (и вообще любые блоки) из блока с overflow:hidden; собираетесь написать? :-)
                              +4
                              А как же! Следите за новостями :)
                              • НЛО прилетело и опубликовало эту надпись здесь
                                  0
                                  Вообще прикольно, я такой блок с display:table растягивал по-другому, но код тут приводить не буду из эстетических соображений :-)

                                  А вот про выносные блоки — это я чуть-чуть про другое говорил, надо будет пример где-нибудь накидать и так же Максу отправить.
                                +1
                                Офигеть :-)
                                  +2
                                  Офигеть, я тебе сидел это рассказывал, а ты спустя два года «офигеть» тут пишешь :D
                                  0
                                  А что делать в том случае, когда на последней строке остается только 2 из 4(например) элемента и они оба оказываются выровнены по левому краю?
                                    0
                                    Знаете, это решение реализуемо через text-align-last, для которого реализован плагин и соответствующая статья здесь.
                                      0
                                      Вот хоть убейте, не могу представить, каким образом text-align-last, решает эту задачу?
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                      +1
                                      Супер!
                                        +1
                                        Полезная информация с утра! Буду применять теперь. Постоянно проблемой было.
                                          +1
                                          отлично.
                                            +1
                                            Вы не только спасли котёнка, но и мои нервные клетки в придачу. В избранное однозначно!
                                              0
                                              Ну хорошо, «text-align-last: justify;» заставляет IE дать последней строке абзаца (она же и первая) выключку по ширине.

                                              А чем обеспечивается для последнего варианта выравнивание в остальных браузерах? Вот чего я пока ещё не понимаю.
                                                +2
                                                Это происходит за счёт псевдоэлемента (хелпера), который фактически и есть последний строчно-блочный элемент в списке. За счёт его растяжки на 100% по ширине text-align: justify; включается в работу на предпоследней строке, тобишь на первой, где у нас все видимые пункты.

                                                +1
                                                Спасибо, мозг, за отличную статью ;)
                                                  +1
                                                  Пожалуйста, дружище, изучай на здоровье!
                                                  –2
                                                  Тема не нова. Решение с «text-align:justify» давно рассмотрено тут:
                                                  www.getincss.ru/2008/03/29/ravnoudalennye-elementy/
                                                  www.getincss.ru/wp-content/uploads/2008/elements.html
                                                    +1
                                                    Да, но во-перых, у этих способов есть явные минусы, хотя бы в доп. элементе в хтмл, а во-вторых, в нашей статье разобрано всё по полочкам.
                                                    +1
                                                    Вы продолжаете меня радовать, Максим. Спасибо!
                                                      0
                                                      :) изобрел подобную конструкцию в 2009м ivanpakhomov.ya.ru/replies.xml?item_no=2274
                                                        +1
                                                        но статью вашу одобряю, пожалуйста не минусуй меня о, хабр
                                                          +1
                                                          Да, но это всё не то, т.е. я считаю, что есть решения лучше и они представлены в этой статье.

                                                          0
                                                          Теперь остаётся между каждыми двумя пунктами добавить разделитель и сделать так, чтобы каждый пункт занимал всё пространство между двумя соседними разделителями. ;-)
                                                            0
                                                            тег table к вашим слугам
                                                              0
                                                              Не забывайте об условии равного расстояния между текстами пунктов.
                                                                0
                                                                Покажите тестовый пример плз, того, что вы имеете ввиду.
                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                                0
                                                                Как-то это не оч. красиво и не pixel-perfect. ;-)
                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                                    0
                                                                    UL-список, текстовая чистота кода (без явного наличия разделителя как текста), разделитель должен иметь произвольный вид (например, быть графическим), ссылка должна прилегать к соседним разделителям вплотную (без каких-либо отступов), высота ссылки и вертикальные отступы вокруг списка должны быть предсказуемо и точно настраиваемыми без приблизительной подгонки какими-либо отрицательными отступами. ;-)
                                                                      0
                                                                      А нарисовать сможете?
                                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                                        • НЛО прилетело и опубликовало эту надпись здесь
                                                                            +1
                                                                            Спасибо за усилия, Илья, стало заметно лучше. ;-)

                                                                            К сожалению, есть ряд недостатков, затрудняющих применение решения на практике: у ссылок в зависимости от шрифта могут появляться паразитные вертикальные отступы, причём в разных браузерах разные (в одних — только сверху, в других — также и снизу от ссылок — см. jsfiddle.net/cjGgT/ ), в IE8 некликабельна половинная часть пустого пространства до разделителя слева от текста ссылки, в Chrome 17 для щелчка доступна только часть ссылки, соответствующая высоте текста (области над текстом и под текстом некликабельны); не слишком интуитивно понятная магия с вертикальным padding, нежелательная фиксация высоты списка (вместо её автоматического определения браузером на основании высоты содержимого). (В IE7, кстати, не работает, но для меня это роли не играет.)

                                                                            Но как proof-of-concept — вполне. ;-)
                                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                                              +1
                                                                              К вопросу об UL-списке: список ссылок (объединённая последовательность однотипных сущностей) не перестаёт быть списком вне зависимости от его функциональной нагрузки (навигация или не навигация). Не флейма ради, а ясности для. ;-)
                                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                                  0
                                                                                  Последовательность навигационных пунктов является относительно самодостаточной лишь до того момента, пока одна из ссылок не перестаёт быть таковой ввиду совпадения её URL-адреса с адресом текущей страницы.

                                                                                  Если у нас не список, получим конструкцию вида «последовательность ссылок + обычный текст + последовательность ссылок», которая для машины может выглядеть уже как цельное предложение. (Бывает навигация и в виде фразы.) В случае же использования списка последовательность названий разделов останется связанной последовательностью однотипных сущностей вне зависимости от того, является ли каждый из пунктов ссылкой.
                                                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                                    0
                                                                    Opera 11.61 Mac — последний пример разъехался.
                                                                      0
                                                                      image
                                                                        0
                                                                        Да, есть такое дело. Жаль, но у меня нет Mac-a. Очень надеюсь, что кто нибудь сможет повозится и понять, в чём причина.
                                                                          0
                                                                          В опере все ломает вот эта строчка ul li {font-size:1px}, но без нее в webkit появляется пробел после последнего li
                                                                            0
                                                                            опечатка! ul {font-size:1px} — все ломает, а вот ul {font-size:2px} делает все более менее ок, пробел уменьшается до 1px (справа) — и в опере все становиться ок, что для нее обычно.
                                                                              +1
                                                                              Спасибо за проделанную работу. А вы не могли бы выложить скриншот рабочего варианта в Opera и webkit-ов?
                                                                              Да, и желательно css.
                                                                                +1
                                                                                Opera: cl.ly/EPWJ
                                                                                Webkit: cl.ly/EPyA
                                                                                CSS: ul {font-size:2px} :)

                                                                                надо найти четко работающий вариант, без зазора в 1px справа, пока только удаление переноса строки между последним li и ul решают этот вопрос, но это не спортивно!
                                                                                  +1
                                                                                  как вариант быстрого фикса — noindex:-o-prefocus, ul {font-size:2px;}
                                                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                                                      0
                                                                                      пробовал, и ем и дроби
                                                                                      0
                                                                                      Спасибо вам!
                                                                          0
                                                                          4-й вариант (под Win):
                                                                          Firefox 3.6.27 — ок
                                                                          Opera 7.21 — ок
                                                                            0
                                                                            вопрос небольшой, а чем плох float?(я могу быть не опытным, поэтому если знаете, то был бы очень благодарен ссылке с материалом по данной штуке)
                                                                            как я понимаю нам блоки нужны одинаковой ширены расположить равномерно?
                                                                            а если использовать first-child с маленькой css'кой?
                                                                              +1
                                                                              нк так с флоатами равномерности не добиться, нужны кастом отступы для первого и последнего элементов и при этом равномерные отступы между промежуточными элементами.
                                                                                +1
                                                                                В первых двух вариантов в статье я делал варианты как раз на float, и как можно увидеть, это не увенчалось успехом. Прочитайте внимательно всю статью, думаю станет ясно.
                                                                                0
                                                                                Попробовал последний вариант. Обнаружился недостаток.
                                                                                Если страница перед отдачей браузеру оптимизируется (удаляются лишние переносы строк и пробелы между тегами), пример не работает. Видимо это логично, поскольку если элементы списка не отделены друг от друга, браузер понимает их как одно единое слово и не пытается распределить их по ширине. Проблема выявилась когда я решил посмотреть на пример через GoogleTranslate.
                                                                                Оказалось, что GT удаляет в переведенных участках странички избыточные символы (пробелы и переносы строк между тегами) и пример перестает работать.
                                                                                Если не найдется решения, придется обратно перейти на неидеальный вариант display-inline + last-child.
                                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                                                    0
                                                                                    Ответил вам ниже ↓
                                                                                  0
                                                                                  display:inline точно так же зависит от пробелов между тегами

                                                                                  Я неверно выразился, имел ввиду display:inline-block. С тем, что вы написали согласен. Но факт остается фактом, и данный приём мне не подходит, т.к. хочется, чтобы в популярном GoogleTranslate верстка сайта сохранялась + чтобы была возможность сжимать HTML не задумываясь о том, что верстка от этого пострадает.
                                                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                                                    0
                                                                                    Еще более интересным будет увидеть способ не просто выравнивать по ширине, а саму ширину делить между всеми элементами без таблиц (не поровну, а в зависимости от ширины каждого элемента)
                                                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                                                        0
                                                                                        да, похоже на то что надо, осталось проверить/адаптировать под все IE
                                                                                          0
                                                                                          не простая разметка, я смотрю, пробелы, переносы и неразрывные строки, и надо фиксить ie7.

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

                                                                                      Самое читаемое