it-roy-ru.com

Только для CSS макет кладки

Мне нужно реализовать довольно заурядный макет кладки. Однако по ряду причин я не хочу использовать JavaScript для этого.

A grid of multiple columns of rectangles of varying height.

Параметры:

  • Все элементы имеют одинаковую ширину
  • Элементы имеют высоту, которая не может быть рассчитана на стороне сервера (изображение плюс различные объемы текста)
  • Я могу жить с фиксированным количеством столбцов, если мне нужно

существует тривиальное решение, которое работает в современных браузерах, свойство column-count.

Проблема с этим решением состоит в том, что элементы упорядочены в столбцах:

Starting from the top leftmost box, they're numbered 1 through 4 straight down, the topmost box in the next column is 5, and so on.

Хотя мне нужно упорядочить элементы в строках, хотя бы примерно:

Starting from the top leftmost box, they're numbered 1 through 6 straight across, but because box 5 is the shortest the box underneath it is 7 as it has the appearance of being on a row higher than the next box on the far left.

Подходы, которые я пробовал, не работают:

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

Есть ли какое-то новое волшебство flexbox, которое делает это возможным?

87
Pekka 웃

Flexbox

Динамическое расположение каменной кладки невозможно с flexbox, по крайней мере, не в чистом и эффективном виде.

Flexbox - это система одномерного макета. Это означает, что он может выравнивать элементы по горизонтальным OR вертикальным линиям. Сгибаемый элемент ограничен его строкой или столбцом.

Истинная сеточная система является двумерной, то есть она может выравнивать элементы по горизонтальным и вертикальным линиям. Элементы содержимого могут одновременно охватывать строки и столбцы, чего не могут делать элементы flex.

Вот почему flexbox обладает ограниченными возможностями для построения сеток. Это также причина, почему W3C разработал еще одну технологию CSS3, Grid Layout .


row wrap

В контейнере flex с flex-flow: row wrap элементы flex должны переноситься на новые строки .

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

Обратите внимание выше, как div # 3 переносится ниже div # 1 , создавая новую строку. Он не может переноситься ниже div # 2 .

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


column wrap

Если вы переключитесь на flex-flow: column wrap, сетчатый макет станет более доступным. Однако у контейнера в направлении столбца есть четыре потенциальных проблемы:

  1. Гибкие элементы текут вертикально, а не горизонтально (как вам нужно в этом случае).
  2. Контейнер расширяется горизонтально, а не вертикально (как макет Pinterest).
  3. Требуется, чтобы контейнер имел фиксированную высоту, чтобы элементы знали, куда их переносить.
  4. На момент написания статьи он имел недостаток во всех основных браузерах, где контейнер не расширяется для размещения дополнительных столбцов .

В результате контейнер в направлении столбца не является опцией в этом случае и во многих других случаях.


CSS Grid с неопределенными размерами элементов

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

Ширина и высота элементов сетки должны быть известны, чтобы закрыть промежутки с окружающими элементами.

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

Фактически, пока не появится технология CSS с возможностью автоматического устранения пробелов, у CSS в целом нет решения. Что-то вроде этого, вероятно, потребует перефразирования документа, поэтому я не уверен, насколько он будет полезен или эффективен.

Вам понадобится сценарий.

Решения JavaScript, как правило, используют абсолютное позиционирование, которое удаляет элементы контента из потока документов, чтобы переставить их без пропусков. Вот два примера:


CSS Grid с определенными размерами элемента

Для макетов, где известны ширина и высота элементов содержимого, вот горизонтально-плавный макет кладки в чистом CSS:

grid-container {
  display: grid;                                                /* 1 */
  grid-auto-rows: 50px;                                         /* 2 */
  grid-gap: 10px;                                               /* 3 */
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));   /* 4 */
}

[short] {
  grid-row: span 1;                                             /* 5 */
  background-color: green;
}

[tall] {
  grid-row: span 2;
  background-color: crimson;
}

[taller] {
  grid-row: span 3;
  background-color: blue;
}

[tallest] {
  grid-row: span 4;
  background-color: gray;
}

grid-item {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3em;
  font-weight: bold;
  color: white;
}
<grid-container>
  <grid-item short>01</grid-item>
  <grid-item short>02</grid-item>
  <grid-item tall>03</grid-item>
  <grid-item tall>04</grid-item>
  <grid-item short>05</grid-item>
  <grid-item taller>06</grid-item>
  <grid-item short>07</grid-item>
  <grid-item tallest>08</grid-item>
  <grid-item tall>09</grid-item>
  <grid-item short>10</grid-item>
  <grid-item tallest>etc.</grid-item>
  <grid-item tall></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
</grid-container>

jsFiddle demo


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

  1. Установить контейнер сетки уровня блока. (другой вариант - inline-grid)
  2. Свойство grid-auto-rows устанавливает высоту автоматически генерируемых строк. В этой сетке каждый ряд имеет высоту 50px.
  3. Свойство grid-gap является сокращением для grid-column-gap и grid-row-gap. Это правило устанавливает разрыв в 10px между элементами сетки. (Это не относится к области между предметами и контейнером.)
  4. Свойство grid-template-columns устанавливает ширину явно определенных столбцов.

    Обозначение repeat определяет шаблон повторяющихся столбцов (или строк).

    Функция auto-fill заставляет сетку выстраивать как можно больше столбцов (или строк) без переполнения контейнер. (Это может создать поведение, аналогичное flex-wrap: wrap гибкого макета.)

    Функция minmax() устанавливает минимальный и максимальный диапазон размеров для каждого столбца (или строки). В приведенном выше коде ширина каждого столбца будет составлять не менее 30% от контейнера и максимально доступного свободного пространства.

    fr unit представляет часть свободного пространства в сеточном контейнере. Это сопоставимо со свойством flexbox flex-grow.

  5. С grid-row и span мы сообщаем элементам сетки, на сколько строк они должны проходить.


Браузерная поддержка CSS Grid

  • Chrome - полная поддержка по состоянию на 8 марта 2017 г. (версия 57)
  • Firefox - полная поддержка с 6 марта 2017 г. (версия 52)
  • Safari - полная поддержка с 26 марта 2017 года (версия 10.1)
  • Edge - полная поддержка по состоянию на 16 октября 2017 г. (версия 16)
  • IE11 - нет поддержки текущей спецификации; поддерживает устаревшую версию

Вот полная картина: http: //caniuse.com/#search=grid


Классная функция наложения сетки в Firefox

В инструментах разработки Firefox, когда вы проверяете контейнер сетки, в объявлении CSS есть маленький значок сетки. При нажатии он отображает схему вашей сетки на странице.

Подробнее здесь: https: //developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

122
Michael_B

Это недавно обнаруженная техника с использованием flexbox: https://tobiasahlin.com/blog/masonry-with-css/ .

Статья имеет смысл для меня, но я не пытался ее использовать, поэтому я не знаю, есть ли какие-то предостережения, кроме упомянутых в ответе Майкла.

Вот пример из этой статьи, использующий свойство order в сочетании с :nth-child.

Фрагмент стека

.container {
  display: flex;
  flex-flow: column wrap;
  align-content: space-between;
  /* Your container needs a fixed height, and it 
   * needs to be taller than your tallest column. */
  height: 960px;
  
  /* Optional */
  background-color: #f7f7f7;
  border-radius: 3px;
  padding: 20px;
  width: 60%;
  margin: 40px auto;
  counter-reset: items;
}

.item {
  width: 24%;
  /* Optional */
  position: relative;
  margin-bottom: 2%;
  border-radius: 3px;
  background-color: #a1cbfa;
  border: 1px solid #4290e2;
  box-shadow: 0 2px 2px rgba(0,90,250,0.05),
    0 4px 4px rgba(0,90,250,0.05),
    0 8px 8px rgba(0,90,250,0.05),
    0 16px 16px rgba(0,90,250,0.05);
  color: #fff;
  padding: 15px;
  box-sizing: border-box;
}

 /* Just to print out numbers */
div.item::before {
  counter-increment: items;
  content: counter(items);
}

/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n)   { order: 4; }

/* Force new columns */
.break {
  flex-basis: 100%;
  width: 0;
  border: 1px solid #ddd;
  margin: 0;
  content: "";
  padding: 0;
}

body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  
  <span class="item break"></span>
  <span class="item break"></span>
  <span class="item break"></span>
</div>
3
Oliver Joseph Ash