Как
расположить текст на странице в несколько колонок? И можно ли это
делать автоматически? Наверняка, многие из тех из вас, кто занимается
или занимался раньше веб-разработкой, сталкивались с такой задачей — и
часто упирались в сложные решения, требующие хитрых стилей, либо применения дополнительных библиотек на 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, в рамках которого пользователи более современных сайтов будут получать больше плюшек:
Во-вторых, многоколоночное отображение хорошо сочетается с возможностями Media Queries (и идеями отзывчивого дизайна, Responsive Design), например, при разных размерах экрана можно форматировать текст в разное количество колонок:
И последнее, что я хотел бы отметить во введении, чтобы на этом не
останавливаться далее и со спокойной совестью перейти к техническим
деталям: при использовании многоколоночной верстки текста надо помнить,
что подобное расположение предполагает и определенный порядок чтения
(для европейских языков слева направо). Поэтому важно, чтобы для
перевода взгляда от одной колонки к другой было необходимо совершать как
можно меньше дополнительных действий, особенно это касается
вертикальных скроллов:
В этом смысле горизонтальная природа колонок лучше сочетается с
горизонтальным скроллом (как это, используется во многих приложениях для
Win8 — например, это хорошо видно по приложению USA Today):
В общем, колонки — это прекрасно, но не забывайте об удобстве пользователей. А теперь в бой!
Колонки
Итак, у нас есть текст (контент), который мы хотим разместить в несколько колонок. С чего начать?
Чтобы превратить такой элемент в многоколоночный нужно через стили в CSS выставить одно из свойств: column-width или column-count в значение, отличное от auto. Например,
чтобы разбить текст на две колонки, достаточно сделать так:
article {
column-count: 2;
}
Все остальное сделает браузер:
Альтернативное свойство — column-width — позволяет задать оптимальную ширину колонок:
article {
column-width: 150px;
}
При этом браузер сам разбивает контент на нужное количество колонок,
чтобы заполнить внешний контейнер, подстраиваясь под указанную ширину
колонок. Важный момент заключается в том, что реальная ширина может отличаться от заданной
в большую или меньшую сторону: на картинке выше серая полоска имеет как
раз ширину в 150px — и, как видно, она меньше, чем реальная ширина
колонки.
Такое поведение определено спецификацией и позволяет (автоматически)
добиться большей гибкости при разработке адаптивной разметки:
Например, если у вас контейнер шириной 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;
columns: 2;
columns: auto;
columns: auto 12em;
columns: 2 auto;
Что будет, если указать и количество колонок, и оптимальную ширину? Согласно спецификации, в этом случае column-count определяет максимальное количество колонок:
article {
columns: 150px 3;
}
В спецификации вы также найдете псевдо-код, описывающий алгоритм рассчета количества колонок и их ширины.
Отступы и разделительные линии
Теперь, когда мы научились создавать колонки, самое время научиться
управлять тем, что происходит между ними: отступами и разделительными
линиями.
Чтобы изменить отступ между колонками, определено свойство column-gap. Чтобы визуально обозначить раздел между колонками, введено еще одно свойство — column-rule-*:
column-gap
column-gap позволяет указать ширину пространства между
колонками. Свойство принимает в качестве значения длину, либо
определяемое браузером значение normal (спецификация рекомендует использовать 1em), являющееся также значением по умолчанию:
article {
columns: 3;
columns-gap: 3em;
}
Важно учитывать, что размер отступа между колонками используется при
расчете ширины колонок и их количества. Например, если указано только
количество колонок (как в примере выше), то ширина рассчитывается так:
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;
}
Важный момент: разделительная линия отрисовывается ровно посередине
отступа между колонками, при этом не занимая места. Если вдруг
разделительная линия оказывается больше по ширине, она начинает
пересекаться с контентом:
article {
columns: 3;
column-rule: 5em groove SkyBlue;
}
Причем отрисовывается разделитель сразу после фона (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;
}
Важный момент: на сегодня управление разрывами в колонках
поддерживается только в 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;
}
В данном случае написанная крупным фраза из диалога растянута на все
колонки. Обратите внимание на порядок следования текста: верхняя левая
колонка, верхняя правая, фраза диалога, нижняя левая и далее нижняя
правая.
Кстати, важный нюанс: если высота колонок ограничена, и дополнительного
места под растягивание элементов нет, браузер может вполне легально
игнорировать требование растягивания.
Растягивание элементов на сегодня все еще не поддерживается в Firefox.
Заполнение
И последняя деталь, которой вы, наверняка, уже должны были озадачиться:
а как, собственно говоря, браузер решает, как ему заполнять колонки?
Для ответа на этот вопрос спецификация вводит свойство column-fill. Заполнять можно сбалансированно (balance), — именно так делается по умолчанию, — стараясь выдержать одинаковую высоту колонок; либо автоматически (auto), заполняя колонки последовательно.
Сравните, вот так браузер балансирует по умолчанию:
article {
columns: 2;
height: 250px;
}
А вот так в автоматическом последовательном режиме:
article {
columns: 2;
column-fill:auto;
height: 250px;
}
Управление заполнением на сегодня поддерживают только Internet Explorer и Opera.
Итоги
Прежде всего, продолжение повести А.П. Чехова «За яблочки» можно
найти в Викитеке.
По существу дела, следя за развитием веб-стандартов, в том числе по некоторым моим статьям про CSS3 (см. например, статью про CSS3 Grid Layout),
я надеюсь, вы с не меньшим вдохновением смотрите на открывающиеся перед
веб-разработчиками возможностями. Адаптивные, гибкие и мощные средства
для управления размещением контента все ближе и доступнее. А решение
сложных задач — все проще.
Интерактив
Поиграться с работой CSS3 Multi-column можно на ietestdrive.com:
Пробуйте, эксперементируйте. Сообщайте разработчикам браузеров о багах. И
не забывайте продумать, что увидят пользователи старых (и вроде бы
современных, но все еще не полностью поддерживающих стандарт) браузеров —
например, можно использовать плагин для jQuery Columnizer. Помните об адаптивности и зрителях маленьких и больших экранов.
|