Is there a way of doing this with flexbox? - css

My main <div> have a fixed height, but when I try to use box-orient: horizontal on it, they stay all above the first <div>, even with an overflow hack.
I'm stuck. This is what I need:
and this code:
<style>
.box {
outline: 1px solid red;
width: 1000px;
height: 450px;
overflow: hidden;
display: box;
box-pack: center;
box-align: center;
box-orient:vertical;
}
.boxitem {
width:150px;
height:200px;
background:#ccc;
}
</style>
<div class="box">
<div id="box1" class="boxitem">flexbox item 1</div>
<div id="box2" class="boxitem">flexbox item 2</div>
<div id="box3" class="boxitem">flexbox item 3</div>
</div>

You're using properties from the 2009 spec, which is being phased out in favor of this draft: http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/. You actually need box-orient: vertical from the 2009 spec, but that still won't help you because as far as I can tell, no one ever implemented box-lines: multiple to enable wrapping. You need the ability to wrap if you only want to use one flex container element.
So, the code below will cover all of your bases for browsers that supports the Flexbox spec in its entirety: Opera, Chrome, IE10.
http://jsfiddle.net/FwfDV/
.box {
outline: 1px solid red;
width: 1000px;
height: 450px;
display: -webkit-flexbox;
display: -ms-flexbox;
display: -webkit-flex;
-webkit-flex-flow: column wrap;
-ms-flex-flow: column wrap;
flex-flow: column wrap;
-webkit-flex-pack: justify; /* optional */
-ms-flex-pack: justify; /* optional */
-webkit-justify-content: space-between; /* optional */
justify-content: space-between; /* optional */
}
#supports (display: flex) and (flex-wrap: wrap) {
.box {
display: flex;
}
}
.boxitem {
width: 150px;
height: 200px;
background: #ccc;
}
<div class="box">
<div id="box1" class="boxitem">flexbox item 1</div>
<div id="box2" class="boxitem">flexbox item 2</div>
<div id="box3" class="boxitem">flexbox item 3</div>
<div id="box4" class="boxitem">flexbox item 4</div>
<div id="box5" class="boxitem">flexbox item 5</div>
<div id="box6" class="boxitem">flexbox item 6</div>
</div>
However, if your "boxitem" elements are regular/fixed sizes like this, I recommend using CSS Columns instead, which has a bit wider support and can do nearly the same job.

Related

Nested Flexbox - outer container doesn't flex

Update : I have edited the snippet to show better what I'm trying to achieve...
I have a number of tables of data, each of variable length, on a kiosk display. I want to fill the viewport as columns then overflow to pages below ie paging down would give me next screen of data. I thought Nested Flexbox would allow me to do this but the outer Container doesn't do what I hoped and data just flows to right - see below. Am I just inept or should I be doing it another way? Thx!
.container1 {
background: lightgrey;
display: flex;
width:300px;
flex-direction: column;
flex-wrap:wrap;
}
.container2 {
background: orangered;
display: flex;
flex-direction: column;
height:200px;
width: 300px;
flex-wrap: wrap;
}
.container2 > div{
font-size: 40px;
width: 100px;
}
.green {
background: yellowgreen;
}
.blue {
background: steelblue;
}
My effort doesn't work ...
<div class="container1">
<div class="container2">
<div class="green">1a<br>1b<br>1c</div>
<div class="blue">2a<br></div>
<div class="green">3a<br>3b</div>
<div class="blue">4a<br>4b<br>4c</div>
<div class="green">5a<br>5b</div>
<div class="blue">6a<br></div>
<div class="green">7a<br>7b</div>
<div class="blue">8a<br>8b<br>8c</div>
<div class="green">9a<br>9b<br>9c</div>
<div class="blue">10a<br></div>
<div class="green">11a<br>11b</div>
<div class="blue">12a<br>12b<br>12c</div>
</div>
</div>
I want output like this but ...
<div class="container2">
<div class="green">1a<br>1b<br>1c</div>
<div class="blue">2a<br></div>
<div class="green">3a<br>3b</div>
<div class="blue">4a<br>4b<br>4c</div>
</div>
<div class="container2">
<div class="green">5a<br>5b</div>
<div class="blue">6a<br></div>
<div class="green">7a<br>7b</div>
<div class="blue">8a<br>8b<br>8c</div>
</div>
<div class="container2">
<div class="green">9a<br>9b<br>9c</div>
<div class="blue">10a<br>10a<br></div>
<div class="green">11a<br>11b</div>
<div class="blue">12a<br>12b<br>12c</div>
</div>
You don't want to use flex-direction: column on the inner container2. You still want that to be row.
Setting flex-direction: column only establishes that the direction of children should flow from top to bottom (or reverse with column-reverse).
Setting flex-wrap: wrap on a parent with flex-direction: column wraps the elements on the cross axis (row in this case).
You don't even need the outer parent container, since there was only one flex child container2.
.container2 {
background: orangered;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 300px;
height: 200px;
overflow: scroll;
}
.container2 > div {
font-size: 40px;
flex: 0 0 33.33333%;
min-height: 200px;
}
.green {
background: yellowgreen;
}
.blue {
background: steelblue;
}
<div class="container2">
<div class="green">1a<br>1b<br>1c</div>
<div class="blue">2a<br></div>
<div class="green">3a<br>3b</div>
<div class="blue">4a<br>4b<br>4c</div>
<div class="green">1a<br>1b<br>1c</div>
<div class="blue">2a<br></div>
<div class="green">3a<br>3b</div>
<div class="blue">4a<br>4b<br>4c</div>
<div class="green">1a<br>1b<br>1c</div>
<div class="blue">2a<br></div>
<div class="green">3a<br>3b</div>
<div class="blue">4a<br>4b<br>4c</div>
</div>

How can I get `column-gap`'s effect with `display: flex` in Chrome?

According to this0, Chrome doesn't support column-gap with display: flex.
Unfortunately, I have to support Chrome too.
What's the cleanest way to have the gap in Chrome without messing with Firefox (which understands column-gap with display: flex properly)?
.flex-container {
display: flex;
colum-gap: 10px;
justify-content: space-between;
}
<div class="flex-container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
The above displays fine in Firefox, with a 10px gutter between .flex-item elements. Chrome has no such gap because it can't do column-gap on display: flex.
Something like this?
.flex-container {
display: flex;
justify-content: space-between;
border: 1px solid black;
}
.flex-item {
flex-basis: 33%;
height: 30px;
margin-left: 10px;
background-color: #cccccc;
}
.flex-item:first-child{
margin-left: 0
}
<div class="flex-container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
*{
margin:0;
padding:0;
}
:root{
--gutter-size:.3em;
}
.flex {
display: flex;
flex-wrap: wrap;
align-items:center;
}
.flex > * {
margin: var(--gutter-size);
}
<div class="flex">
<h1>lorem</h1>
<p>ipsume</p>
<div>Dolor</div>
</div>

Shrink grid items just like flex items in css

Is it possible to shrink grid items just like flex items in css?
Grid items
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
jsfiddle
Flex items
.container {
display: flex;
margin-left: -10px;
flex-flow: row wrap;
}
.child {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
flex: 200px 1 1;
margin-left: 10px;
margin-bottom: 10px;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
jsfiddle
In a nutshell I can have the following positioning of the elements with the flex above:
While I can not achieve the same behaviour by using a grid layout. Flex layout allows items to shrink on small screen, while grid layout does not allow. At the same time I would like to preserve the behavior that the item will move to the next line with another item only when after such a placement each one of them will be no shorter than a specific size (200px in our case).
I am using grid layout because it allows to preserve the invariant that widths of all the children will be the same. With flex layout the last item will be stretched to the whole line if it will be alone on the line.
New solution
An optimized version of the initial solution using min()
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(min(200px,100%), 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
}
body {
margin:0;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
Old solution
One solution is to specify a max-width to the child element relying on the viewport unit since percentage values are relative to the size of the track defined by the minmax() and cannot be used. This solution isn't generic and you need to adjust the value depending on each situation.
In you case for example, we can use 100vw since the container is the only element in the body and is taking the whole width:
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
max-width:100vw;
box-sizing:border-box; /* Don't forget this !*/
}
body {
margin:0;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
In case there is more element or some padding/margin you need to consider them within the max-width calculation:
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.child {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border: 3px solid #a07;
max-width:calc(100vw - 40px); /*we remove the body margin*/
box-sizing:border-box;
}
body {
margin:0 20px;
}
<div class="container">
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
<div class="child">
text
</div>
</div>
It's like we no more have 2 constraints but 3:
The grid cell has a minimum size of 200px
The grid cell fill the remain space
The element inside the grid cell has a maximum size defined relatively to the screen size. (the shrink constraint we were missing)

How to make a flex box width the same as content when content wraps

I need to make a div's width with a class grid the same as content (items).
But when the items wrap to the next line I need to shrink the div accordingly, so I don't have any extra space on the left and of the right of items.
Thanks in advance !
.home {
height: 100vh;
display: flex;
align-items: center;
}
.grid {
flex-basis: content;
display: flex;
background-color: red;
flex-wrap: wrap;
}
.gridItem {
margin: 2px;
width: 90px;
height: 60px;
background: #FFF;
display: flex;
align-items: center;
justify-content: center;
};
<div class='home'>
<div class='grid'>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
<div class='gridItem'>Item 1</div>
</div>
</div>

flexbox vertical align child top, center another

I've got the following markup:
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>
Unfortunatly the second header isn't align vertically to the top. Is there a way to archive this with flexbox? I need the ".header" to be aligned the the top and the ".content" to be centered within the rest of the box.
Greetings!
No, not really, not without another wrapper which is a flex-container.
As flexbox is, to a certain extent based on manipulting margins, there is no method (AFAIK, although I'd be interested to find out if there is) to justify-content: center and then align-self a child element to somewhere else other than center.
I'd go with something like this: Add a wrapper to the "content" div, give it flex:1 to fill the remaining space below the header, then make that wrapper display:flex with justify-content:center.
This seems to be the most logical method
.col {
height: 150px;
width: 80%;
margin: 1em auto;
border: 1px solid grey;
display: flex;
flex-direction: column;
}
.header {
background: lightblue;
}
.content {
background: orange;
}
.flexy {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
background: plum;
}
<div class="col">
<div class="header">Header #2</div>
<div class="flexy">
<div class="content">Lorem Ipsum
<br />Dolor</div>
</div>
</div>
Codepen Demo
Flexbox opens up all sorts of opportunities with margin: auto; this is one of them. Setting margin to auto along the flex axis (vertical in this case) will absorb any extra space before dividing it up between the flex items. Finally it's possible to vertically center stuff without creating a div soup.
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
.content {
margin-top: auto;
margin-bottom: auto;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>

Resources