Microsoft — мировой лидер в области ПО и ИТ-услуг
492,56
рейтинг
2 мая 2012 в 11:11

Разработка → Введение в CSS3 Multicolumn. Работаем с колонками tutorial

apples

Как расположить текст на странице в несколько колонок? И можно ли это делать автоматически? Наверняка, многие из тех из вас, кто занимается или занимался раньше веб-разработкой, сталкивались с такой задачей — и часто упирались в сложные решения, требующие хитрых стилей, либо применения дополнительных библиотек на JavaScript (см. например Columnizer-плагин для jQuery).

Многоколоночная верстка контента (не путать с задачей общей многоколоночной верстки страницы, которая скорее ближе к проблеме расположения блоков по сетке) долго пробивала себе дорогу в мире веб-стандартов и, наконец-то, не просто достигла статуса Candidate Recommendation в виде соответствующего модуля CSS3 Multi-column Layout, но и получила достаточно широкую поддержку в браузерах: где-то с префиксами (-moz- или -webkit-) и где-то в актуальных (Opera 11.1+) и планируемых версиях (IE10+), причем сразу без префиксов.

Замечание
В случае Internet Explorer 10 это автоматически означает возможность использования CSS3 Multi-column при разработке приложений в стиле Metro для Windows 8 с использованием HTML/CSS/JS.

В рамках статьи я не буду использовать браузерные префиксы, чтобы на запутывать код, но при реальном использовании не забудьте добавить поддержку префиксов для Firefox, Safari и Chrome.

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

progressive enhacement

Во-вторых, многоколоночное отображение хорошо сочетается с возможностями Media Queries (и идеями отзывчивого дизайна, Responsive Design), например, при разных размерах экрана можно форматировать текст в разное количество колонок:

responsive design

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

multicolumn layout vs vertical scroll

В этом смысле горизонтальная природа колонок лучше сочетается с горизонтальным скроллом (как это, используется во многих приложениях для Win8 — например, это хорошо видно по приложению USA Today):

multicolumn layout plus horizontal scroll

В общем, колонки — это прекрасно, но не забывайте об удобстве пользователей. А теперь в бой!

Колонки


Итак, у нас есть текст (контент), который мы хотим разместить в несколько колонок. С чего начать?

plain text

Чтобы превратить такой элемент в многоколоночный нужно через стили в CSS выставить одно из свойств: column-width или column-count в значение, отличное от auto. Например,
чтобы разбить текст на две колонки, достаточно сделать так:

article {
    column-count: 2;
}


Все остальное сделает браузер:
2 columns

Альтернативное свойство — column-width — позволяет задать оптимальную ширину колонок:

article {
    column-width: 150px;
}


3 columns

При этом браузер сам разбивает контент на нужное количество колонок, чтобы заполнить внешний контейнер, подстраиваясь под указанную ширину колонок. Важный момент заключается в том, что реальная ширина может отличаться от заданной в большую или меньшую сторону: на картинке выше серая полоска имеет как раз ширину в 150px — и, как видно, она меньше, чем реальная ширина колонки.

Такое поведение определено спецификацией и позволяет (автоматически) добиться большей гибкости при разработке адаптивной разметки:

adaptive column width

Например, если у вас контейнер шириной 100px и вы задали колонки шириной 45px, то браузер посчитает, что влезет только две колонки, а чтобы заполнить все место, увеличит размер каждой до 50px. (Здесь также учитывается отступ между колонками, о чем будет рассказано в следующем разделе.)

В определенном смысле, это можно рассматривать как альтернативу указанию с помощью Media Queries разного количества колонок в зависимости от размера окна и с автоматическим рассчетом ширины колонок:

@media (min-width:400px) {
    article {
        column-count: 2;
    }
}
@media (min-width:600px) {
    article {
        column-count: 3;
    }
}
...


Я второй раз говорю про альтернативу — и вот почему.

count vs. width


Как уже должно быть понятно из описания выше, спецификация дает два способа для задания количества и ширины колонок (кстати, у всех колонок она одинаковая!):
  • column-count позволяет указать число колонок, на которые нужно поделить контент, при этом ширину колонок определяет браузер с учетом доступного пространства.
  • column-width заходит с обратной стороны: указывает, какими примерно должны быть колонки, однако, оставляет рассчет их количества на усмотрение браузера.

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

columns: 12em;      /* column-width: 12em; column-count: auto; */
columns: 2;         /* column-width: auto; column-count: 2; */
columns: auto;      /* column-width: auto; column-count: auto; */
columns: auto 12em; /* column-width: 12em; column-count: auto; */
columns: 2 auto;    /* column-width: auto; column-count: 2; */


Что будет, если указать и количество колонок, и оптимальную ширину? Согласно спецификации, в этом случае column-count определяет максимальное количество колонок:

article {
    columns: 150px 3;  /* column-width: 150px; column-count: 3; */          
}


limited to 3 columns

В спецификации вы также найдете псевдо-код, описывающий алгоритм рассчета количества колонок и их ширины.

Отступы и разделительные линии


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

Чтобы изменить отступ между колонками, определено свойство column-gap. Чтобы визуально обозначить раздел между колонками, введено еще одно свойство — column-rule-*:
column gap and rule

column-gap


column-gap позволяет указать ширину пространства между колонками. Свойство принимает в качестве значения длину, либо определяемое браузером значение normal (спецификация рекомендует использовать 1em), являющееся также значением по умолчанию:

article {
    columns: 3;  
    column-gap: 3em;          
}

3em gap

Важно учитывать, что размер отступа между колонками используется при расчете ширины колонок и их количества. Например, если указано только количество колонок (как в примере выше), то ширина рассчитывается так:

W = ((available-width + column-gap) / N) - column-gap;


column-rule


Если для обозначения колонок свободного пространства недостаточно, можно использовать свойства column-rule-*, добавляющие линию между колонками. По своему поведению и заданию аналогичные свойствам border-*:
  • column-rule-color — цвет линии,
  • column-rule-style — стиль линии,
  • column-rule-width — ширина линии.

Как и в случае с границами блоков, есть краткая форма записи — просто column-rule:

article {
    columns: 3;  
    column-rule: 3px dotted CornflowerBlue;         
}


dotted rule

Важный момент: разделительная линия отрисовывается ровно посередине отступа между колонками, при этом не занимая места. Если вдруг разделительная линия оказывается больше по ширине, она начинает пересекаться с контентом:

article {
    columns: 3;  
    column-rule: 5em groove SkyBlue;      
}


rule overflow

Причем отрисовывается разделитель сразу после фона (background) контейнера.

Разрывы


Распределение контента по колонкам — еще одна интересная задача, требующая иногда тонкого управления. По умолчанию, контент — это сплошная «масса», весьма прямолинейным образом, перетекающая из одной колонки в другую. Но что делать, если, скажем, я хочу быть уверенным, что в конце колонки у меня не повиснет одинокий заголовок? Или если мое визуально-эстетическое чувство требует, чтобы цитата не разрывалась на несколько колонок или даже больше: единолично занимала целиком всю колонку?

Для решения всех этих задач есть специальные свойства. Знакомьтесь:
  • break-before — что должно происходить перед блоком контента,
  • break-after — что должно происходить после блока контента,
  • break-inside — что должно происходить внутри блока контента.

Если вы знакомы с аналогичными свойствами, отвечающими за разбивку контента на страницы (page-break-*), то данные свойства для колонок ведут себя схожим образом: используют те же значения плюс несколько дополнительных (отмечены курсивом):
  • break-before: auto, always, avoid, left, right, page, column, avoid-page, avoid-column
  • break-after: auto, always, avoid, left, right, page, column, avoid-page, avoid-column
  • break-inside: auto, avoid, avoid-page, avoid-column

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

article dialog {
    break-inside:avoid;
    break-before: column;
    break-after: column;
    display:block;
}


column breaks

Важный момент: на сегодня управление разрывами в колонках поддерживается только в Opera 11.10+, — что не удивительно, учитывая, что редактор спецификации Хокон Виум Ли, — и IE10.

Мои эксперименты со свежей версией Оперы и предварительной публичной версией IE10 показывают, что местами имеющиеся реализации отличаются друг от друга. Однако тут я затрудняюсь ответить, какой браузер ведет себя «правильней», так как спецификация хотя и содержит отдельный раздел, посвященный переполнению (overflow), все же оставляет некоторые нюансы на усмотрение браузера (например, позволяет появление дополнительных экстра-колонок при явном указании разрывов).

Растягивание на несколько колонок


Теперь, когда мы научились создавать колонки и немного управлять поведением контента, давайте научимся еще одному трюку — растягиванию контента на несколько колонок. Для этого есть специальное свойство: column-span, принимающее значения none и all.

Нас интересует второе значение. Оно выдергивает блок контента из общего многоколоночного потока и растягивает его на все колонки. При этом контент до этого элемента и контент после автоматически балансируются на все имеющиеся колонки.

article dialog.big {
    column-span:all;
    display:block;
    font-size:1.3em;
    margin:20px 0;
}


column span

В данном случае написанная крупным фраза из диалога растянута на все колонки. Обратите внимание на порядок следования текста: верхняя левая колонка, верхняя правая, фраза диалога, нижняя левая и далее нижняя правая.

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

Растягивание элементов на сегодня все еще не поддерживается в Firefox.

Заполнение


И последняя деталь, которой вы, наверняка, уже должны были озадачиться: а как, собственно говоря, браузер решает, как ему заполнять колонки?

Для ответа на этот вопрос спецификация вводит свойство column-fill. Заполнять можно сбалансированно (balance), — именно так делается по умолчанию, — стараясь выдержать одинаковую высоту колонок; либо автоматически (auto), заполняя колонки последовательно.

Сравните, вот так браузер балансирует по умолчанию:

article  {
    columns: 2;
    /*column-fill:balance;*/
    height: 250px;
}


column fill balance

А вот так в автоматическом последовательном режиме:

article  {
    columns: 2;
    column-fill:auto;
    height: 250px;
}


column fill auto

Управление заполнением на сегодня поддерживают только Internet Explorer и Opera.

Итоги


Прежде всего, продолжение повести А.П. Чехова «За яблочки» можно
найти в Викитеке.


По существу дела, следя за развитием веб-стандартов, в том числе по некоторым моим статьям про CSS3 (см. например, статью про CSS3 Grid Layout), я надеюсь, вы с не меньшим вдохновением смотрите на открывающиеся перед веб-разработчиками возможностями. Адаптивные, гибкие и мощные средства для управления размещением контента все ближе и доступнее. А решение сложных задач — все проще.

Интерактив


Поиграться с работой CSS3 Multi-column можно на ietestdrive.com:

hands on

Пробуйте, эксперементируйте. Сообщайте разработчикам браузеров о багах. И не забывайте продумать, что увидят пользователи старых (и вроде бы современных, но все еще не полностью поддерживающих стандарт) браузеров — например, можно использовать плагин для jQuery Columnizer. Помните об адаптивности и зрителях маленьких и больших экранов.
Автор: @kichik
Microsoft
рейтинг 492,56
Microsoft — мировой лидер в области ПО и ИТ-услуг

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

  • 0
    Отличная статья! Надеюсь в скором будущем растягивание элементов будет поддерживаться и в Firefox, а также и column-fill в Chrome.
  • 0
    Скажите, такие колонки предназначены только для текста? Или с их помощью можно и layout страницы верстать?
    • 0
      Учитывая, на какие извращения способна CSS-разметка сейчас, уверен, что эти свойства можно будет использовать и для текста, и для layout, и для еще кучи разных крутых штук.
    • +3
      Технически в сочетании с управлением разрывами можно, однако, основное предназначение — это все же многоколоночная верстка контента.
      • 0
        А планируется ли введение каких-то новых свойств, направленных именно на вёрстку страницы? Или считается, что существующие float, position, отступы и т.п. работают достаточно хорошо?
        • +3
          Grid Layout, FlexBox.
        • +1
          habrahabr.ru/post/125802/
          ну, с чистой совестью юзать сейчас это можно разве что в метро-приложениях для win8 =(
  • +10
    Когда же наступят эти благодатные времена, когда всем, описанным в статье можно просто взять и пользоваться, а не пролистывать в качестве развлекательного чтива.
    • 0
      А вы возьмите и пользуйтесь. Чем дольше все ждут, тем медленнее прогресс.
    • 0
      Когда наступит судный день, и все старые браузеры умрут.
  • +1
    Это перевод что ли? Непонятно почему надписи на картинках английские, а Хокон Виум Ли остался как «Håkon Wium Lie».
    • +1
      С ходу английского аналога не находится. Более вероятно компиляция, или (и) статья основана на раздаточных материалах Майкрософта для евангелистов.
      • –1
        Самописная ;) Хокона перевел, над картинками подумаю — я их сразу готовил под английскую версию, которой пока нет :) То есть тут скорее обратный процесс: на русском появляется раньше.
  • +1
    Есть ли js библиотека для поддержки мульти-колоночности для всех броузеров?
    • 0
      можно использовать плагин для jQuery Columnizer (http://welcome.totheinter.net/columnizer-jquery-plugin/).


      Правда, она около года не обновлялась.
      • 0
        А еще она тормозная и глючная. Проще самому написать. Это не так сложно.
  • +7
    на сегодня поддерживают только Internet Explorer и Opera

    Никто не ожидал, а этот день настал.
  • 0
    Не хватаем, имхо, автоматической разбивки по высоте. То есть чтобы величина контейнера была не выше, допустим, 2/3 экрана. Единицы измерения под это дело уже есть, а поддержки в колонках — нет.
  • +1
    Что-то мне кажется, что многоколоночность будет выглядеть весьма убого без выравнивания по ширине (text-align: justify), а оно, в свою очередь, выглядит весьма убого без авто-переносов в словах.

    Многие ли браузеры умеют авто-расстановку переносов?
    /* да, я знаю, что жаваскриптом можно расставить в тексте ­ */
    • +2
      Ага.
      В css3 есть свойстваhyphenate-after
      hyphenate-before
      hyphenate-characters
      hyphenate-lines
      hyphenate-resource
      hyphens


      Не поддержиаются никем.
      • 0
        IE10 поддерживает ;)
        • 0
          ну да, по данным mdn:
          chrome-13, safari-5.1: -webkit-hyphens
          firefox-6: -moz-hyphens
          ie-10: -ms-hyphens

          Латынь, правда не все поддерживают, поэтому лорем ипсум не проходит :))
  • 0
    ...column-gap. Чтобы изуально обозначить раздел...

    Добавьте букву в перед изуально.
  • 0
    Спасибо, интересная статья, было приятно почитать.

    Интересно, почему column-span может принимать только значения none или all, а не число. Например, если текст разбит на пять колонок, а какой-то фрагмент (цитату) хочется выделить и поместить на ширину двух колонок, то так сделать не получится?
    • 0
      В текущей версии так сделать нельзя. Тут есть важный момент: элемент со span-all разбивает поток контекста на две части: до и после, каждая из которых самостоятельно делится на колонки.

      То есть это работает не так:
      A D G
      S S S
      B E H
      C F I

      а так:
      A B C
      S S S
      D F H
      E G I

      Для вашей задачи больше подходит CSS Exclusions (http://www.w3.org/TR/css3-exclusions/)
      • 0
        Спасибо за пояснение!
        Стал абсолютно понятен механизм разделения потока на части. В принципе это можно увидеть и в примере из статьи, но я сначала не обратил внимания.

        CSS Exclusions — очень мощный инструмент. Правда, насколько я понимаю, браузерами он пока не поддерживается.
  • 0
    Интересно, есть ли возможность как-то реализовать Разрывы в браузерах, так как реализованы они только в WebKit(криво и используя column-break-inside) и Opera). Если такое возможно реализовать, то перестану использовать Masonry в проектах, так как он достаточно тяжелый, и на старых компьютерах чуть подлагивает, а если еще прикручивать другие плагины для jQuery, то может вообще зависнуть.

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

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