[英]How can I create a row-based masonry layout using CSS?
我需要實施砌體布局。 但是,出於多種原因,我不想使用 JavaScript 來完成它。
參數:
有一個適用於現代瀏覽器的簡單解決方案,即column-count
屬性。
該解決方案的問題在於元素按列排序:
雖然我需要按行對元素進行排序,但至少大致如下:
我嘗試過但不起作用的方法:
現在我可以更改服務器端呈現並重新排序項目,將項目數除以列數,但這很復雜,容易出錯(基於瀏覽器決定將項目列表拆分為列的方式),所以我想盡可能避免它。
是否有一些 flexbox 魔法使這成為可能?
CSS Grid Layout Level 3 includes a masonry
feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
end update; original answer below
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap
, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap
, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
As a result, a column-direction container is not an option in this case, and in many other cases.
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Masonry is a JavaScript grid layout library. It works by placing elements in optimal position based on available vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure 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>
How it works
inline-grid
would be the other option)grid-auto-rows
property sets the height of automatically generated rows. In this grid each row is 50px tall.grid-gap
property is a shorthand for grid-column-gap
and grid-row-gap
. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)grid-template-columns
property sets the width of explicitly defined columns.The repeat
notation defines a pattern of repeating columns (or rows).
The auto-fill
function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap
.)
The minmax()
function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr
unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow
property.
Browser Support for CSS Grid
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
這是最近發現的涉及 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>
最后是一個純 CSS 的解決方案,可以輕松創建砌體布局,但我們需要耐心等待,因為目前不支持它。
此功能在CSS 網格布局模塊級別 3中引入
本模塊介紹了砌體布局作為 CSS 網格容器的附加布局模式。
然后
通過為其中一個軸指定值masonry來支持網格容器的砌體布局。 該軸稱為砌體軸,另一軸稱為網格軸。
一個基本的例子是:
.container { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-rows: masonry; /* this will do the magic */ grid-gap: 10px; } img { width: 100%; }
<div class="container"> <img src="https://picsum.photos/id/1/200/300"> <img src="https://picsum.photos/id/17/200/400"> <img src="https://picsum.photos/id/18/200/100"> <img src="https://picsum.photos/id/107/200/200"> <img src="https://picsum.photos/id/1069/200/600"> <img src="https://picsum.photos/id/12/200/200"> <img src="https://picsum.photos/id/130/200/100"> <img src="https://picsum.photos/id/203/200/100"> <img src="https://picsum.photos/id/109/200/200"> <img src="https://picsum.photos/id/11/200/100"> </div>
如果啟用此處解釋的功能,這將在 Firefox 上產生以下結果: https://caniuse.com/?search=masonry
如果我們把屏幕屏幕縮小,響應式部分就完美了
.container { -moz-column-count: 1; column-count: 1; -moz-column-gap: 20px; column-gap: 20px; -moz-column-fill: balance; column-fill: balance; margin: 20px auto 0; padding: 2rem; }.container.item { display: inline-block; margin: 0 0 20px; page-break-inside: avoid; -moz-column-break-inside: avoid; break-inside: avoid; width: 100%; }.container.item img { width: 100%; height: auto; } @media (min-width: 600px) {.container { -moz-column-count: 2; column-count: 2; } } @media (min-width: 900px) {.container { -moz-column-count: 3; column-count: 3; } } @media (min-width: 1200px) {.container { -moz-column-count: 4; column-count: 4; } }
CSS-Only Masonry Layout <div class="container"> <div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div> <div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div> <div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div> <div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div> <div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div> <div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div> <div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div> <div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div> <div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div> <div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div> <div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div> <div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div> </div>
試試這些簡單的 2 行 CSS
.parent-container{
column-count: 3;
column-gap: 30px;
}
.child-elements{
display: inline-block;
width: 100%;
}
而已! 我希望這可以幫助你~RDaksh
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.