This question already has answers here:
CSS-only masonry layout
(4 answers)
Closed 4 years ago.
This is my problem:
I have different DIVs with all the same widths but different heights.
On a large viewport these DIVs should be arranged as a grid with two columns.
The margin between the DIVs should be equal (vertically and horizontally).
Since the DIVs should be displayed in one column with the correct order on mobile it is not possible to have its own parent elements for each column.
Here is an image of what I want to achieve:
Is there any way to solve this with pure html/css?
The only solution I found so far is to use some kind of masonry javascript. But I feel like there must be a better solution...
What I've tried so far:
Using float/inline-block: I get perfect rows but 4 always starts at the same height as 3. So the margins are not equal. (See: https://codepen.io/OsmaGiliath/pen/vaPqro)
// EXAMPLE I
.parent {
width:230px;
}
.children {
display:inline-block;
width:100px;
}
Flexbox: Same (See: https://codepen.io/OsmaGiliath/pen/ajMgjR)
// EXAMPLE II
.parent {
display:flex;
flex-wrap: wrap;
}
.children {
flex:none;
}
Vertical flexbox: Works – but only with a fixed height on the parent element which is not possible in my example since this would limit the elements in the growth (See: https://codepen.io/OsmaGiliath/pen/ZjPdVx)
// EXAMPLE III
.parent {
display:flex;
flex-wrap: wrap;
flex-direction:column;
}
.children {
flex:none;
}
You can add columns that will warp up in one column if there is no enough width. This will allow you to display it as one column on mobiles. See working example here: https://codepen.io/anon/pen/BPEaXQ . You can see it working by changing the width of parent "grid" element to simulate mobiles.
<div class="grid">
<div class="column">
<div class="element higher">1</div>
<div class="element">2</div>
</div>
<div class="column">
<div class="element">3</div>
<div class="element">4</div>
</div>
</div>
.grid {
display:flex;
flex-wrap:wrap;
flex-direction:row;
margin:0 auto;
width:230px;
border:1px solid blue;
}
.column {
display: flex;
flex-direction: column;
}
.element {
width:100px;
height:140px;
margin:5px;
background: red;
}
.higher {
height:160px;
}
I finally found a solution thanks to the comment by #tobias-k.
For Desktop:
Using columnt-count: 2 on the parent element
Change the order of the 2nd and 3rd element
For Mobile:
Position the elements in a column using flexbox
Use flexbox's order to swap back the 2nd and 3rd element
https://codepen.io/OsmaGiliath/pen/vaMYPY
Thank you for all the quick responses!
Related
This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 2 years ago.
I'm creating a nav menu using flex. I want all of the items in my menu to display in a single row when the screen is wide enough to support that, and to snap to two rows of items when it needs to wrap. I have this mostly working:
.content {
width: 400px;
height: 150px;
border: thin solid black;
}
.outer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.inner {
display: flex;
justify-content: space-around;
flex-grow: 1;
}
span {
font-size: 24pt;
}
<div class="content">
<div class="outer">
<div class="inner">
<span>one</span>
<span>two</span>
<span>three</span>
</div>
<div class="inner">
<span>four</span>
<span>five</span>
<span>six</span>
</div>
</div>
</div>
CodePen here.
This works perfectly when the page is wide enough:
And it works mostly perfectly when the page is narrow (try changing the width of .content to 250px):
However, now I'm trying to make it so the items in each row line up with each other. I'm going for something like this:
I've tried every combination of flex-grow, flex-shrink, and justify-content that I can think of, but I can't get the items to align.
I know I could probably use a media query and swap out the content for a grid when the window gets too narrow, but I'd like to simplify this as much as possible. Is there a way to align the children of two flex divs?
Alternatively, is there a way to use a grid layout that shows as 1 row until it needs to wrap, and then it shows as 2 rows?
It causes by span width.
if span width not fixed, span will have dynamic width;
set width on span;
Try this
Add to te span
span {
flex: 33%;
}
Or change the porcent acording to the amount of items the div has
This question already has answers here:
Make flex items take content width, not width of parent container
(3 answers)
Closed 5 years ago.
See attached snippet.
I need each item to take width space, with respect to content.
flex-items need to be stacked vertically, like in the example.
how to achieve it?
how to do that?
.container {
display:flex;
flex-direction:column;
}
.green {
background-color:green;
}
.red {
background-color:red;
}
<div class="container">
<div class="green"> hello world</div>
<div class="red"> hello world2</div>
</div>
Assuming they still should stack vertically, use display: inline-flex and they will size equally by the content of the widest item.
For each row to collapse to their individual content, use i.e. align-items: flex-start, and note, this will make them collapse when using display: flex too.
Why they stretch to equal width, is because align-items defaults to stretch, so by using any other value they will size by content
.container {
display: inline-flex;
flex-direction:column;
align-items: flex-start;
}
.green {
background-color:green;
}
.red {
background-color:red;
}
<div class="container">
<div class="green"> hello world</div>
<div class="red"> hello world2</div>
</div>
This question already has answers here:
How to Create Grid/Tile View? [duplicate]
(8 answers)
Closed 6 years ago.
I have boxes in which I'm using flexbox for their layout. Flexbox makes the rows 'organized'. Meaning, if 1 box's height is larger than all the others, all the boxes on the second row get pushed down, and there is space under the boxes first row that have a smaller height.
Here's an image of what I mean:
There's space under box #01 because box #2 has a larger height. I want box #4 to go right under box #1.
How can I make a all boxes to fill up space right above them?
JSFiddle
#wrapper {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
width: 400px;
}
.tile {
background-color: lightblue;
border: 1px solid black;
height: 100px;
width: 100px;
margin: 10px;
}
#n2 {
height: 200px;
}
<div id="wrapper">
<div class="tile" id="n1">01</div>
<div class="tile" id="n2">02</div>
<div class="tile" id="n3">03</div>
<div class="tile" id="n4">04</div>
<div class="tile" id="n5">05</div>
</div>
You can achieve this with flex-direction: column along with flex-wrap: wrap, but you won't be able to preserve the order of the elements.
A JavaScript library like Masonry might be worth looking into.
Like Darryl says, you want to do this with flex-flow: column wrap; and a fixed height on the parent element. This page on CSS-Tricks is invaluable to understanding the syntax, but basically changing the flex-direction flips it sideways. You can specify the order of children by setting the order: XX on the child tiles.
I am trying to make code from further down in the html show above code from above it by using CSS.
Basically my html is like this:
<div class="showbelow">
show below
</div>
<div class="showabove">
show above
</div>
I am wanting the showabove div to show above the showbelow div despite being below it in the html. Is there a way of doing this without using negative margins in the css? eg. giving showabove a negative top margin and show below a positive top margin? Both divs are 100% of the container.
Thanks in advance :)
There is a property order to place items on a specific place using flexbox.
See the following example:
.container {
display:flex;
flex-direction:column;
}
.container div {
border:1px solid red;
}
.showabove {
order:1;
}
.showbelow {
order:2;
}
<div class="container">
<div class="showbelow">show below</div>
<div class="showabove">show above</div>
</div>
Flex items are, by default, displayed and laid out in the same order as they appear in the source document. The order property can be used to change this ordering.
https://drafts.csswg.org/css-flexbox-1/#order-property
Be careful with using order:-1!
.container {
display:flex;
flex-direction:column;
}
.container div {
border:1px solid red;
}
.showabove {
order:-1;
}
<div class="container">
<div class="showbelow">show below</div>
<div class="showmiddle">show middle</div>
<div class="showabove">show above</div>
</div>
Explanation: The order:-1 set the item on the first position of your container, because all the other items has per default order:0. It doesn't move the item before the previous item! In your case this solution is working but if you add more items it can be a problem and you have to set the order for each item on the container like the example above.
With Flexbox you can change order of elements. So in this case you can use order: -1 on .showabove div.
body {
display: flex;
flex-direction: column;
}
.showabove {
order: -1;
}
<div class="showbelow">show below</div>
<div class="showabove">show above</div>
I try to use the following structure to generate the layout described below.
<div class="flexbox">
<div class="box box1">child 1</div>
<div class="box box2">child 2</div>
<div class="box box3">child 3</div>
<div class="box box4">child 4</div>
</div>
I made an example for that here.
The layout should be as follows:
if there is only one box inside the flexbox it should have 50% of the width inside the flexbox (see following figure)
if there are two boxes they both should take 50% of the space inside the flexbox
if there are three boxes, each box should take 50% of the space, while the first two boxes are in row 1 and the third box appears in row 2
How can I achieve this kind of layout with css?
Edit: The boxes might not have the same height. This means they should fill the remaining space vertically. The width is always the same. See the following image for an example.
Edit: I found a way to make masonry with pure css see here: http://jsfiddle.net/confile/aGXzU/
The problem is that the boxes are in the wrong order. They should be from left to right and from top to bottom like this:
1 2 3
4 5 6
7 8 9
Is there a way to get this with css and only little javascript?
Here is a new answer and hope it solves your problem , following two Fiddles , to handle this issue , the first script will throw all odd children in the left side , and all even children on the right side
side1=0,side2=0
$(".flexbox").children().each(function(index, element) {
if (index % 2 === 0) //odd children (starts with 0 )
{
$(this).css("top",side1+"px")
side1+=parseInt($(this).css("height"))
}
else //even children
{
$(this).css("top",side2+"px")
$(this).css("left","50%")
side2+=parseInt($(this).css("height"))
}
});
http://jsfiddle.net/prollygeek/QD9kZ/
while this second fiddle , will balance the two sides based on elements heights so that there is no big deviation in the columns heights all the time , use any script of them it is up to you.
side1=0,side2=0
$(".flexbox").children().each(function(index, element) {
if(side1<=side2)
{
$(this).css("top",side1+"px")
side1+=parseInt($(this).css("height"))
}
else if(side2<side1)
{
$(this).css("top",side2+"px")
$(this).css("left","50%")
side2+=parseInt($(this).css("height"))
}
});
http://jsfiddle.net/prollygeek/hP6fS/
Flexbox cannot be used to recreate the Masonry layout. Period.
Flexbox is for controlling how elements flow along either a horizontal row (flex-direction: row, which is the default) or vertical column (flex-direction: column). That means you can only eliminate excess space in one direction: left/right (row) or top/bottom (column). Because flex-direction: column requires an explicit height to enable wrapping, it is entirely unsuitable for this purpose.
The CSS Multi-column Layout Module is the closest you can get to recreating a Masonry layout using pure CSS, but it still only allows you to eliminate excess space between the elements in one direction: vertically. The key difference between this and Flexbox (using the column direction) is that the Multi-Column module does not require an explicit height and will distribute the contents equally between each of the columns as best it can (this can be controlled via the column-fill property). The gap between the columns is controlled by the column-gap property.
http://codepen.io/cimmanon/pen/CcGlE
.my-element {
-moz-columns: 15em;
-webkit-columns: 15em;
columns: 15em;
}
If there are only two columns, why not just use floats, alternating left and right floating/clearing for odd and even boxes?
.container {
background-color: yellow;
overflow: hidden;
width: 100%;
}
.box {
height: 100px;
width: 50%;
}
.box:nth-child(odd) {
float:left;
clear: left;
}
.box:nth-child(even) {
float:right;
clear: right;
}
.box1 {
background-color: lime;
}
.box2 {
background-color: blue;
height: 120px;
}
.box3 {
background-color: red;
height: 140px;
}
.box4 {
background-color: green;
}
<div class="container">
<div class="box box1">child 1</div>
<div class="box box2">child 2</div>
<div class="box box3">child 3</div>
<div class="box box4">child 4</div>
</div>
.flexbox {
background-color: yellow;
width: 100%;
height: 300px;
}
.box {
float:left;
position:realtive;
height: 100px;
width:50%;
}
try adding and removing children !!
http://jsfiddle.net/prollygeek/8hHDg/5/
For boxes of the same size:
If you're using flexbox, you'll want to use flex-direction: row; and flex-wrap: wrap;
I forked your JSFiddle. All flex-box properties I added are prefixed with -webkit- only
References:
A Complete Guide to Flexbox
How do I implement a multi-line flexbox?
For boxes of multiple sizes:
You'll need a 'masonry' layout. This article should help you with this issue. The last section is entitled 'Pure CSS'; if you want to avoid JavaScript plugins, that should be what you want.
Unfortunately, pure CSS is only able to make top-to-bottom left-to-right layouts. For left-to-right top-to-bottom layouts, you'll need JavaScript. Check out the jQuery suggestions in the article above.
If you want to do this with pure JavaScript (without jQuery), check out this masonry library.