Flexbox wrap items on demand? - html

I currently have a model like this
.parent
.child1
.child2
.child3
.child4
The request is: 'parent' is a row that takes full width of the device.
In big screen, there is one row with 4 children.
In smaller screen, there are 2 rows with 2 columns each.
And in the extra small screen there are 1 column with 4 rows.
Is there any way that I can achieve the request using only Flexbox? (because I hate Boostrap so much...)
I tried flex-wrap: wrap for the parent and flex: 1 for the children, but failed :(
Thank you :)

This is a SCSS mixin that does that:
#mixin n-columns($min-width, $gutter, $last-equal:false, $max-cols:5, $selector:'.colItem'){
display: flex;
flex-wrap: wrap;
margin-left: -$gutter;
// margin-top: -$gutter;
position: relative;
top: -$gutter;
> #{$selector} {
flex: 1 0 auto;
margin-left: $gutter;
margin-top: $gutter;
#if $last-equal {
#for $i from 2 through $max-cols {
$screen-width: ($min-width*$i)+($gutter*$i);
$column-width: (100%/$i);
#media( min-width: $screen-width) {
max-width: calc(#{$column-width} - #{$gutter});
}
}
$column-width: (100%/$max-cols);
#media( min-width: $min-width*$max-cols) {
min-width: calc(#{$column-width} - #{$gutter});
}
}
}
}
You use it like so:
.parent{
#include n-columns(200px, 3px, true, 5);
}
You'll understand all the things it can do after you use it with different settings and see the results, it's pretty straightforward.

.container {
display: flex;
}
.box {
flex: 1;
}
#media ( max-width: 800px ) {
.container { flex-wrap: wrap; }
.box { flex: 0 0 50%; box-sizing: border-box; }
}
#media ( max-width: 500px ) {
.box { flex-basis: 100%; }
}
/* non-essential decorative styles */
.box {
height: 50px;
background-color: lightgreen;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2em;
}
<div class="container">
<div class="box"><span>1</span></div>
<div class="box"><span>2</span></div>
<div class="box"><span>3</span></div>
<div class="box"><span>4</span></div>
</div>
jsFiddle

Related

How to show overflow content as full in a div

So I have this middle container (div) which consists of 2 smaller div.
Here's the code for the div that wraps both div:
.midContainer{
width: 100%;
height: 30vh;
max-height: 700px;
display: flex;
flex-wrap: wrap;
overflow: auto;
justify-content: space-between;
margin-bottom: 15px;
}
Here's the code for left div:
.tokenInfoBox{
width: 60%;
height: 100%;
max-height: 700px;
// padding: 20px 30px ;
background-color: #1b1b1c;
border-radius: 10px 0 0 10px;
}
Here's the code for right div:
.ticketBox{
width: 40%;
height : 100%;
background-color: #0e0304;
box-sizing: border-box;
border-radius: 0 10px 10px 0;
display: flex;
flex-direction: column;
}
Have this added as well:
#media only screen and (max-width: 1060px) {
.tokenInfoBox, .ticketBox {
width: 100%;
}
}
So the content for the left div and right div (both div) display normally in big screen but overflow and overlap div below them in small screen. How do I wrap all the overflow content inside the div?
Here's the image in bigger screen and here's the image in smaller screen where I have to scroll to see all content.
CSS:
.midContainer {
width: 100%;
height: 30vh;
display: flex;
flex-wrap: wrap;
}
.tokenInfoBox {
flex: 1 1 25rem;
height: 100%;
background-color: #1b1b1c;
border-radius: 10px 0 0 10px;
}
.ticketBox {
flex: 1 1 8rem;
height: 100%;
background-color: #0e0304;
border-radius: 0 10px 10px 0;
}
you can use flex in this case when applying flex-wrap.
If i understood well, the problem is because you have set the height of the .midContainer, try something like this:
.midContainer {
display: flex;
width: 100%;
align-self: flex-start;
}
.tokenInfoBox {
width: 60%;
flex-grow: 1;
display: flex;
flex-direction: column;
background: #1b1b1c;
}
.ticketBox {
flex-grow: 1;
display: flex;
flex-direction: column;
background: #0e0304;
width: 40%;
}
this will grow you div to fit the amount of height needed.
Also think about the use of media queries, small devices would be difficult to read 2 divs side by side, maybe should be better one over another
#media (max-width: 768px) {
.midContainer {
flex-direction: column;
}
.tokenInfoBox {
width: 100%;
}
.ticketBox {
width: 100%;
}
}
also I strongly recommend to use tailwind

How to add elements around an already center-justified element?

I have created a form with some text elements aligned vertically like so:
They are centered horizontally and vertically on the page using flexbox:
.my-class {
display: flex;
justify-content: center;
align-items: center;
flex-direction:column;
}
What I'm trying to do now is maintain this alignment (i.e. keep everything that's on the page already exactly where it is) while adding some elements on either side of the first text box. I tried wrapping everything in a div but since the elements on either side of the text box are not the same width, the text box loses its alignment:
As you can see, the long text boxes are now out of alignment. How can I add elements before and after the first text box without moving where it is?
Assuming it is the url/pass/button that are the one's to be centered, and the https/path stick on each side, I would do it like this, where I use a flex row container and pseudo elements to break each group of item into lines of their own.
With this markup one also have full control to move around the items based on screen width's etc.
The 2 main things making this work is the pseudo elements, that, with their full width, force them into rows of their own, and at the same time push content down, together with the order property, enable to position them before the pass and auth respectively.
Stack snippet
.flex {
display: flex;
flex-flow: row wrap;
justify-content: center; /* horiz. center items */
align-content: center; /* vert. center wrapped items */
/*align-items: center;*/ /* vert. center unwrapped items */
}
.flex div:nth-child(1),
.flex div:nth-child(3) { /* https/path item */
flex: 1; /* share space left equal */
}
.flex div:nth-child(2),
.flex div:nth-child(4) { /* url/pass item */
flex-basis: 300px; /* need equal width */
}
.flex::before { /* 1st line breaker */
content: ''; width: 100%;
order: 1;
}
.flex div:nth-child(4) {
order: 2;
}
.flex::after { /* 2nd line breaker */
content: ''; width: 100%;
order: 3;
}
.flex div:nth-child(5) {
order: 4;
}
/* styling */
.flex {
height: 200px;
border: 1px solid red;
}
.flex span {
display: inline-block;
border: 1px solid gray;
padding: 2px;
margin: 2px;
}
.flex div:nth-child(2) span,
.flex div:nth-child(4) span {
width: calc(100% - 10px);
}
.flex div:nth-child(1) {
text-align: right;
}
<div class="flex">
<div><span>http(s)</span></div>
<div><span>url</span></div>
<div><span>path</span></div>
<div><span>***</span></div>
<div><span>authenticate</span></div>
</div>
If the width of the url/pass should scale with parent's width, use percent combined with CSS Calc.
Stack snippet
.flex {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-content: center;
}
.flex div:nth-child(1),
.flex div:nth-child(3) {
flex: 1;
}
.flex div:nth-child(2),
.flex div:nth-child(4) {
flex-basis: 60%;
}
.flex::before {
content: ''; width: 100%;
order: 1;
}
.flex div:nth-child(4) {
order: 2;
}
.flex::after {
content: ''; width: 100%;
order: 3;
}
.flex div:nth-child(5) {
order: 4;
}
/* styling */
.flex {
height: 200px;
border: 1px solid red;
}
.flex span {
display: inline-block;
border: 1px solid gray;
padding: 2px;
margin: 2px;
}
.flex div:nth-child(2) span,
.flex div:nth-child(4) span {
width: calc(100% - 10px);
}
.flex div:nth-child(1) {
text-align: right;
}
<div class="flex">
<div><span>http(s)</span></div>
<div><span>url</span></div>
<div><span>path</span></div>
<div><span>***</span></div>
<div><span>authenticate</span></div>
</div>
Another option would be to keep the initial flex column direction, and with an extra wrapper use absolute positioning for the http(s)/path items.
.flex {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.flex > div:nth-child(-n+2) {
position: relative;
width: 60%;
}
.flex div div:nth-child(1) {
position: absolute;
top: 0;
right: 100%;
}
.flex div div:nth-child(3) {
position: absolute;
top: 0;
left: 100%;
}
/* styling */
.flex {
height: 200px;
border: 1px solid red;
}
.flex span {
display: inline-block;
width: calc(100% - 10px);
border: 1px solid gray;
padding: 2px;
margin: 2px;
}
.flex div div:nth-child(1) {
text-align: right;
}
.flex div div:nth-child(1),
.flex div div:nth-child(3) {
width: auto;
}
<div class="flex">
<div>
<div><span>http(s)</span></div>
<div><span>url</span></div>
<div><span>path</span></div>
</div>
<div><span>***</span></div>
<div><span>authenticate</span></div>
</div>
Updated (based on another question with a similar need)
One can also keep the simpler markup, with no extra wrapper, and use inline-flex combine with making the flex parent also a flex container.
Stack snippet
body {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.flex {
position: relative;
display: inline-flex;
flex-direction: column;
align-items: center;
}
.flex div:nth-child(2),
.flex div:nth-child(4) {
width: 300px;
}
.flex div:nth-child(1) {
position: absolute;
top: 0;
right: 100%;
}
.flex div:nth-child(3) {
position: absolute;
top: 0;
left: 100%;
}
/* styling */
.flex {
border: 1px solid red;
}
.flex span {
display: inline-block;
width: calc(100% - 10px);
border: 1px solid gray;
padding: 2px;
margin: 2px;
text-align: left;
}
.flex div div:nth-child(1) {
text-align: right;
}
.flex div div:nth-child(1),
.flex div div:nth-child(3) {
width: auto;
}
<div class="flex">
<div><span>http(s)</span></div>
<div><span>url</span></div>
<div><span>path</span></div>
<div><span>***</span></div>
<div><span>authenticate</span></div>
</div>

Flex CSS with fixed width and equal height

I have three sections in a container. When I resize my browser to the max-width of 668px, I need to make the section 1 and section 3 in one row and the section 2 in the below row. The section 2 width should be proportional to the section 1 and section 3 width.
But now once I minimize the browser size to 668px and below, then section 3 is not visible.
This is what I tried.
#media (max-width: 668px) {
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-self: flex-start;
}
.container .section1 {
height: 300px;
}
.container .section1,
.container .section3 {
flex: 0 0 262px;
margin: 3px;
display: block;
flex-grow: 0;
flex-shrink: 0;
}
.container .section2 {
flex: 0 0 500px;
flex-grow: 0;
flex-shrink: 0;
order: 1;
min-height: 235px;
}
}
#media (max-width: 940px) {
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-self: flex-start;
}
.container .section1 {
height: 300px;
}
.container .section1,
.container .section3 {
flex: 0 0 262px;
margin: 3px;
display: block;
flex-grow: 0;
flex-shrink: 0;
}
.container .section2 {
flex: 0 0 500px;
flex-grow: 0;
flex-shrink: 0;
order: 1;
min-height: 235px;
}
}
<div class="container">
<div class="section1">Section 1</div>
<div class="section2">Section 2</div>
<div class="section3">Section 3</div>
</div>
You don't have any height specified on .section3.
On .section1 you have height: 300px.
On .section2 you have min-height: 235px.
But on .section3 you have nothing. Try this adjustment to your code:
.section1, .section3 {
height: 300px;
}
jsFiddle demo

Add a row to a nested flex container on media query

I have one primary container that holds all the divs using a flex-direction of row.
A second container that is nested holds two divs that have a flex-direction of column, to stack up two divs in one row in the outer container.
Using flex-box and media query, I was attempting to change the existing two row column div 'smaller-container' into a three row column div once the browser width is less than 1000px.
I tried doing this by creating a third empty div within smaller-container and swapping its order with a div outside the smaller-container once the browser width is less than 1000px.
It didn't work. I think this is because the two divs in question (the empty div and the outer div) are at a different nesting level.
It would be great if someone can find a solution to turn the two row in one column to three row in one column.
Even better if that solution has no need of a nested container. Javascript solution is also welcome if it doesn't require a plugin.
Image of how it should look:
/*Basic Reset*/
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
max-width: 1366px;
margin: auto;
width: 100%;
}
.container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.box-1 {
order: 1;
background-color: red;
height: 150px;
width: 50%;
}
.smaller-container {
display: flex;
flex-wrap: wrap;
flex-direction: column;
width: 50%;
order: 2;
}
.box-2 {
order: 3;
background-color: blue;
height: 75px;
width: 100%;
}
.box-3 {
order: 4;
background-color: green;
height: 75px;
width: 100%;
}
.box-4 {
order: 5;
width: 100%;
}
.box-5 {
order: 6;
background-color: orange;
height: 150px;
width: 100%;
}
#media screen and (max-width: 1000px) {
.box-2 {
height: 50px;
}
.box-3 {
height: 50px;
}
/******* Here we swap the empty div that hasbeen existing in the smaller container
with an outer div ********/
.box-5 {
order: 5;
height: 50px;
}
.box-4 {
order: 6;
background-color: purple;
height: 150px;
}
}
[image of desired solution][1] [1]:http://i.stack.imgur.com/vlvlx.png
<div class="container">
<div class="box-1"></div>
<div class="smaller-container">
<div class="box-2"></div>
<div class="box-3"></div>
<div class="box-4"></div>
</div>
<div class="box-5"></div>
</div>
https://jsfiddle.net/lukindo/nuv603h9/1/
Well, you're right that the order property doesn't work at different nesting levels. It only works among siblings.
Scripting is one option you can pursue. Another, a bit hackish, is to duplicate an HTML element. Specifically, place the orange box element (.box-5) in both the primary and nested container.
Then use display: none on both orange and purple boxes per your media query.
Here's an example:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
max-width: 1366px;
margin: auto;
width: 100%;
}
.container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.box-1 {
order: 1;
background-color: red;
height: 150px;
width: 50%;
}
.smaller-container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
width: 50%;
order: 2;
}
.box-2 {
order: 3;
background-color: blue;
height: 75px;
width: 100%;
}
.box-3 {
order: 4;
background-color: green;
height: 75px;
width: 100%;
}
.smaller-container > .box5 {
display: none;
}
.container > .box-5 {
order: 6;
background-color: orange;
height: 150px;
width: 100%;
}
#media screen and (max-width: 1000px) {
.box-2 {
height: 50px;
}
.box-3 {
height: 50px;
}
.container > .box-4 {
order: 6;
background-color: purple;
height: 150px;
width: 100%;
}
.smaller-container > .box-5 {
display: block;
height: 50px;
background-color: orange;
width: 100%;
order: 6;
}
.container > .box-5 {
display: none;
}
}
<div class="container">
<div class="box-1"></div>
<div class="smaller-container">
<div class="box-2"></div>
<div class="box-3"></div>
<div class="box-5"></div>
</div>
<div class="box-4"></div>
<div class="box-5"></div>
</div>
Revised Fiddle

Adjusting grid from desktop to mobile using flexbox

I'm trying to take content that is laid out with desktop as the priority, and re-flow it for mobile based on that clients wishes, but I'm not able to completely get the elements to fit. Here's the layout on desktop:
+----+----+
| 1 | 2 |
| | |
+---------+
| 3 | 4 |
| | 5 |
+---------+
Elements 4 and 5 are in a wrapping div together because they're each half the height of element 3. Desktop is the priority, so it's be developed with that in mind. Here's what I want to accomplish for mobile:
+----+----+
| 1 |
| |
+---------+
| 4 | 2 |
| 5 | 3 |
+---------+
Using flexbox I've managed to get all the elements repositioned except 2. It just wraps to the next line.
I realize it's not ideal, but is there any way to get the 2nd element to line up under the 3rd to make a 1x2 grid?
Here's the code that I've gotten close with:
#wrapper { display: -webkit-flex; flex-wrap: wrap; align-content: stretch; }
#1 { order: 1; flex: 1 100%; }
#2 { order: 3; flex: 3 50%; }
#3 { order: 4; flex: 4 50%; }
#4&5wrapper { order: 2; flex: 2 50%; }
Is this even possible?
I believe the answer to your question is no. Here's why:
The desktop layout is not a problem with flexbox. You simply need to wrap boxes 4 and 5 in a nested column-direction flex container, and you're done.
.inner-container {
display: flex;
flex-direction: column;
order: 4;
flex: 0 1 calc(50% - 10px - 2px); /* width less margin less borders */
}
However, for the mobile layout, which requires boxes 2 and 3 to adjust from a row-based wrap in the outer flex container to a column-direction stack in an inner flex container (like with boxes 4 and 5), you would need to change the mark-up.
The best you can do (or at least I could do) without changing the mark-up is this:
Here's the code from the demos in case you're interested in playing with it:
HTML
<div class="outer-container">
<span class="box box1">1</span>
<span class="box box2">2</span>
<span class="box box3">3</span>
<div class="inner-container">
<span class="box box4">4</span>
<span class="box box5">5</span>
</div>
</div>
CSS (includes non-essential decorative styles)
body { display: flex; align-items: flex-start; }
.outer-container {
display: flex;
flex-wrap: wrap;
padding: 6px 0;
background-color: #f5f5f5;
border: 1px solid #ccc;
width: 250px;
box-sizing: border-box;
margin-right: 15px;
}
.box {
height: 100px;
width: 50px;
margin: 5px;
background-color: lightgreen;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2em;
}
.inner-container {
display: flex;
flex-direction: column;
order: 4;
flex: 0 1 calc(50% - 10px - 2px); /* width less margin less borders */
}
.box1 { flex: 0 1 calc(50% - 10px - 2px); order: 1; }
.box2 { flex: 0 1 calc(50% - 10px - 2px); order: 2; }
.box3 { flex: 0 1 calc(50% - 10px - 2px); order: 3; }
.box4 { flex: 0 1 calc(50% - 10px - 2px); width: 100%; }
.box5 { flex: 0 1 calc(50% - 10px - 2px); width: 100%; }
div.outer-container:last-of-type > .box1 { flex: 0 1 calc(100% - 10px - 2px); order: 1;}
div.outer-container:last-of-type > .inner-container { order: 2; margin-right: 10px; }
div.outer-container:last-of-type > .box2 { order: 3; }
div.outer-container:last-of-type > .box3 { order: 4; flex: 1 1 100%; }
DEMO: http://jsfiddle.net/dLgjuyw6/1/ (Firefox)
EDIT: Just noticed that demo code (as pictured) works in FF but not Chrome. As this demo is solely for illustration purposes and non-essential to the answer I'm not pursuing browser compatibility.
I realise you've already accepted no as an answer but I'm not yet convinced.
I think the following solution answers the question. Note that I've chosen the flex-bases(?) so that their sum is 100% but you don't have to do that. That way there is some leeway to adjust to the content.
To see what happens watch the solution in full screen and make your browser window narrow (< 600 px). Or watch it on codepen.
#one {background: lightblue;}
#two {background: skyblue;}
#three {background: blue;}
#four {background: aqua;}
#five {background: lime;}
div {flex: 1;}
#wrapper {width: 100%; height: 95vh; border: 1px solid;}
#media (min-width:600px){
#wrapper {
display: flex;
flex-flow: column wrap;
padding: 0;
margin: 0;
}
div {width: 50%;}
#one{
order: 1;
flex-basis: 66%;
}
#two{
order: 2;
flex-basis: 66%;
}
#three{
order: 1;
flex-basis: 34%;
}
#four{
order: 2;
flex-basis: 17%;
}
#five{
order: 2;
flex-basis: 17%
}
}
#media (max-width:599px){
#wrapper {
display: flex;
flex-flow: row wrap;
padding: 0;
margin: 0;
}
#one{
order: 1;
flex-basis: 100%;
min-height: 40vh;
}
#two{
order: 3;
flex-basis: 50%;
}
#three{
order: 5;
flex-basis: 50%;
}
#four{
order: 2;
flex-basis: 50%;
}
#five{
order: 4;
flex-basis: 50%
}
}
<div id='wrapper'>
<div id='one'>1</div>
<div id='two'>2</div>
<div id='three'>3</div>
<div id='four'>4</div>
<div id='five'>5</div>
</div>
- UPDATED -
The answer is YES,
...but with some trickery and maybe not the flexing you might like with 2 flex wrappers side-by-side. Splitting the problem in two, a regular flex container (1&2&3) and some relative positioning of a second (4&5) you will get the required layout.
I am not sure this is the best to do or even the answer you wanted, but maybe it is just what you needed.
Have a look at the snippet and let me know!
/* Global stuff */
html, body { box-sizing: border-box; height: 100%; width: 100%;
margin: 0; padding: 0; border: 0 }
*, *:before,
*:after { box-sizing: inherit }
/* Solution */
#w1 { display: flex;
flex-flow: column wrap; /* vertical arrangement */
align-items: flex-end; /* forces 2&3 to lower right */
with: 100%; height: 100% } /* full screen */
#i1 { width: 100%; height: 50% } /* full width, half height of #w1 */
#i2,#i3 { width: 50%; height: 25% } /* half width, half height of #w1 */
#w2 { display: flex; flex-direction: column;/* stay unchanged */
position: absolute; top: 50%; /* nasty, but works */
width: 50%; height: 50% } /* stay unchanged */
#i4,#i5 { width: 100%; height: 50% } /* stay unchanged */
#i1::before { content: 'mobile '}
#media all and (min-width: 720px) {
#i1::before { content: 'desktop '}
/* become equal in size */
#i1,#i2,#i3 { width: 50%; height: 50% } /* half width, half height of #w1 */
#w1 { flex-flow: row wrap; /* horizontal arrangement */
justify: content: flex-start }/* forces 1&2&3 to upper left */
#w2 { right: 0 } /* reposition, nasty, but works */
}
/* Demo */
#w1 *, #w2 * { text-align: center; font-size: 40px; font-weight: bold;
background: #f0f0f0; border: 2px solid black }
<div id="w1">
<div id="i1">1</div>
<div id="i2">2</div>
<div id="i3">3</div>
</div>
<div id="w2">
<div id="i4">4</div>
<div id="i5">5</div>
</div>