, давшую название такой раскладке.

//AN_Xml:

И вот в Рабочей группе по CSS появилось предложение, а спустя считанные месяцы — и его экспериментальная реализация, которую уже можно пощупать в Firefox Nightly/Beta за флагом. Кроме понятной радости, новинка успела вызвать немало путаницы и споров. Попробуем разобраться.

//AN_Xml:

Постановка задачи

//AN_Xml:

Причем тут «масоны»? :)

//AN_Xml:

Сходство названия библиотеки и легендарного тайного общества не случайно: оба — от слова «каменщик». Общая логика masonry-верстки похожа на логику каменной кладки: берем «кирпичик» и укладываем его вплотную к предыдущим.

//AN_Xml:

Но где хоть вскользь упомянуты масоны, там не обходится без путаницы:). Как оказалось, при слове «masonry-раскладка» разные люди представляют себе очень разные вещи — и часто по умолчанию каждый считает свой вариант единственно возможным!

//AN_Xml:

Макеты и библиотеки

//AN_Xml:

Одни представляют себе «каменную кладку» как набор совершенно произвольных блоков, которые надо как можно плотнее прижать друг к другу — типа как на этом фото:

//AN_Xml:

Плотная кладка из каменных блоков разной формы

//AN_Xml:

В вебе форма блоков (пока) ограничена прямоугольниками, но их размеры теоретически могут быть любыми. Справедливости ради, это задача скорее для другой библиотеки ДеСандро — Packery. Ниже скриншот с ее сайта («шапка» там работает как наглядное демо, все эти темные прямоугольники — отдельные анимируемые блоки):

//AN_Xml:

Скриншот сайта библиотеки Packery

//AN_Xml:

У ДеСандро есть и третья библиотека для раскладки блоков — Isotope. Автор разъясняет, что задача Packery — именно упаковка произвольных блоков, Masonry создает masonry-макеты (логично!:), а у Isotope основной упор на интерактивность (перетягивание и т.п.), и она может оперировать разными схемами раскладки (в т.ч. «masonry»). Но все три библиотеки во многом схожи и в какой-то мере даже взаимозаменяемы. Пять лет назад Masonry помогла нам решить задачу плотной упаковки, а первый же пример для Packery называется… «masonry-галерея».

//AN_Xml:

Но чаще всего под «masonry-раскладкой» понимается макет, где по горизонтали блоки вписываются в некую регулярную сетку (занимают целое число колонок, опционально с разделительными интервалами), а по вертикали — как получится. Первым на ум приходит, конечно же, Pinterest, где все блоки одинаковой ширины (в одну колонку). Многие уже считают слово «Pinterest» синонимом для «masonry» и даже не вспоминают про другие варианты. Но возможности библиотеки куда шире, и в ее онлайн-документации Дейв приводит множество симпатичных примеров вроде вот такого:

//AN_Xml:

Пример masonry-раскладки из документации к библиотеке Masonry

//AN_Xml:

Два разных порядка блоков

//AN_Xml:

Именно в нем ключевое отличие «masonry-раскладки» от обычной многоколоночной: колонки заполняются блоками не последовательно, по вертикали, а «параллельно», по горизонтали. Но в библиотеке Masonry есть два режима, переключаемые параметром horisontalOrder:Два варианта порядка блоков в Masonry: по умолчанию они попадают в наименее заполненную колонку, а с параметром horizontalOrder заполняют колонки по порядку

//AN_Xml:

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

//AN_Xml:

А с включенным параметром блоки, наоборот, соблюдают порядок по горизонтали (первый блок — в первую колонку, второй — во вторую… n-й — в n-ю, n+1-й — снова в первую, n+2-й — снова во вторую, и т.д.). Поскольку высота блоков разная и заранее неизвестная, получающиеся «строки» быстро начинают «скакать» вверх-вниз, а высота колонок может стать неравномерной. Но раз автор добавил такой режим, наверное, для чего-то он бывает нужен…

//AN_Xml:

Промежуточный итог: варианты

//AN_Xml:

Получается, что masonry-раскладка — не одна конкретная схема, а множество разных, хоть и родственных, задач. Как минимум:

//AN_Xml:
    //AN_Xml:
  1. Плотная, насколько можно, упаковка блоков произвольного размера, без привязки к какой-либо сетке (как у Packery);
  2. //AN_Xml:
  3. Вписывание блоков в сетку по одной оси (с кратным шагом) и плотная упаковка по другой (как в примерах от Masonry);
  4. //AN_Xml:
  5. Заполнение колонок по доступному месту (Masonry по умолчанию);
  6. //AN_Xml:
  7. Заполнение колонок по порядку по горизонтали (Masonry c horizontalOrder=true);
  8. //AN_Xml:
  9. … и т.д. (ждем ваших примеров в комментариях!)
  10. //AN_Xml:
//AN_Xml:

Подходы к решению

//AN_Xml:

CSS-колонки

//AN_Xml:

Это первое, что приходит на ум при виде макета а-ля Pinterest. Визуально — практически что надо. Куча статей в интернете прямо представляет их как «masonry на чистом CSS». Но главная загвоздка — порядок элементов совсем не тот, что мы ищем. Динамическую подгрузку так не сделать. И еще одна загвоздка — колонки нельзя объединять, разве что сразу все (по крайней мере, пока). Впрочем, раз порядок не подходит, это уже мелочи…

//AN_Xml:

Флексбоксы

//AN_Xml:

С flex-flow: column wrap; они похожи на мультиколонки, но у них есть мощный козырь для управления порядком: свойство order. К этому бы еще возможность явно заставлять колонки флекс-элементов переноситься (в Firefox ее уже можно эмулировать благодаря багу) — и получается решение 4-го варианта задачи, заполнение колонок по порядку. Ориоль Брюфо даже показал его на примере:

//AN_Xml:
#flex-container {
//AN_Xml:   display: flex;
//AN_Xml:   flex-flow: column wrap;
//AN_Xml:}
//AN_Xml:
//AN_Xml:#flex-container > :nth-child(3n + 1) { order: 1; } /* колонка 1 */
//AN_Xml:#flex-container > :nth-child(3n + 2) { order: 2; } /* колонка 2 */
//AN_Xml:#flex-container > :nth-child(3n + 3) { order: 3; } /* колонка 3 */
//AN_Xml:
//AN_Xml:#flex-container > :nth-child(-n + 3) {
//AN_Xml:   break-before: flex; /* так должно быть по текущей спеке */
//AN_Xml:   break-before: always; /* так работает в Firefox, хотя не должно:) */
//AN_Xml:}
//AN_Xml:
//AN_Xml:

Но… слишком много «но». Это лишь один вариант задачи, не самый востребованный. Про объединение колонок придется забыть — одномерные флексбоксы такого не умеют. Как и про «отзывчивость» — для каждого числа колонок придется отдельно прописывать n селекторов: громоздко и негибко.

//AN_Xml:

А может… старые добрые флоаты?

//AN_Xml:

Их поведение часто очень напоминает вариант 1 (как в заставке от Packery): стремятся расположиться как можно выше, а если нет места — ищут его рядом по горизонтали:

//AN_Xml:

See the Pen
//AN_Xml:abvqOVz
by Ilya Streltsyn (@SelenIT)
//AN_Xml:on CodePen.

//AN_Xml: