Staggering items in CSS with flexbox - html

I'm trying to create a staggered layout in CSS, where each row only has one item, but it will be offset from the items on the other rows.
I've made two working examples so far, but I'm wondering if there is a better way to achieve this.
Here's an example I made using spacer divs :
http://cdpn.io/e/EWrMgL
HTML :
<div class="container">
<div class="row">
<div class="spacer">(spacer)</div>
<div class="content col-2">content 2</div>
<div class="spacer">(spacer)</div>
</div>
<div class="row">
<div class="content col-1">content 1</div>
<div class="spacer">(spacer)</div>
<div class="spacer">(spacer)</div>
</div>
<div class="row">
<div class="spacer">(spacer)</div>
<div class="spacer">(spacer)</div>
<div class="content col-3">content 3</div>
</div>
<div class="row">
<div class="spacer">(spacer)</div>
<div class="spacer">(spacer)</div>
<div class="content col-3">content 3</div>
</div>
</div>
CSS :
.container, .spacer, .content, .row {
display: flex;
}
.container {
flex-flow: row wrap;
font-family: sans-serif;
}
.row {
width: 100%
}
.spacer {
color: #2c3e50;
flex: 1 1 0%;
}
.content {
color: #ecf0f1;
flex : 3 1 0%;
flex-basis: 60%
}
.content, .spacer {
justify-content: center;
align-items: center;
min-height: 5em;
margin: 0.5em;
}
.col-1 {
background-color: #96858F;
}
.col-2 {
background-color:#9099A2;
}
.col-3 {
background-color: #6d7993;
}
I made another attempt at a cleaner version using margins instead of wrapping
each item in a row : http://cdpn.io/e/xqMBmB
HTML:
<div class="container">
<div class="content col-2">content 2</div>
<div class="content col-1">content 1</div>
<div class="content col-3">content 3</div>
<div class="content col-3">content 3</div>
</div>
CSS:
.container, .content{
display: flex;
}
.container {
flex-flow: row wrap;
font-family: sans-serif;
}
.content {
color: #ecf0f1;
flex: 0 1 70%;
justify-content: center;
align-items: center;
min-height: 5em;
margin-bottom: 0.5em;
}
.col-1 {
background-color: #96858F;
}
.col-2 {
background-color:#9099A2;
margin-left: 7.5%;
}
.col-3 {
background-color: #6d7993;
margin-left: 15%;
}
Is there a cleaner way to do this than enclosing each row in a div or changing the margins? I'll want to add #media rules to make the rows 100% width below a certain screen size.

If you change to flex-direction: column and remove wrap, the 2:nd will behave as the 1:st
I also added a media query to drop the left margin at a small width.
With this markup it's also easier to change order and layout, and is most likely the best way to do it.
.container, .content{
display: flex;
}
.container {
flex-direction: column;
font-family: sans-serif;
}
.content {
color: #ecf0f1;
justify-content: center;
align-items: center;
min-height: 5em;
margin-bottom: 0.5em;
}
.col-1 {
background-color: #96858F;
}
.col-2 {
background-color:#9099A2;
margin-left: 7.5%;
}
.col-3 {
background-color: #6d7993;
margin-left: 15%;
}
#media screen and (max-width: 500px) {
.content {
margin-left: 0;
}
}
<div class="container">
<div class="content col-2">content 2</div>
<div class="content col-1">content 1</div>
<div class="content col-3">content 3</div>
<div class="content col-3">content 3</div>
</div>
You can also size them, like this
.container, .content{
display: flex;
}
.container {
flex-direction: column;
font-family: sans-serif;
}
.content {
width: 70%;
color: #ecf0f1;
justify-content: center;
align-items: center;
min-height: 5em;
margin-bottom: 0.5em;
}
.col-1 {
background-color: #96858F;
}
.col-2 {
background-color:#9099A2;
margin-left: 7.5%;
}
.col-3 {
background-color: #6d7993;
margin-left: 15%;
}
#media screen and (max-width: 500px) {
.content {
margin-left: 0;
width: 100%;
}
}
<div class="container">
<div class="content col-2">content 2</div>
<div class="content col-1">content 1</div>
<div class="content col-3">content 3</div>
<div class="content col-3">content 3</div>
</div>

Your second version of the code is fine, it's simple enough. What I would suggest though instead of using specific margins is to use auto margins, change the size of the items to 100% and then specify a max-width so that on smaller devices they will be full width and on larger screens they won't. Here's an example of the CSS for this:
.container, .content{
display: flex;
}
.container {
flex-flow: row wrap;
font-family: sans-serif;
}
.content {
color: #ecf0f1;
flex: 0 1 100%; /* CHANGE */
max-width: 800px; /* CHANGE */
justify-content: center;
align-items: center;
min-height: 5em;
margin-bottom: 0.5em;
}
.col-1 {
background-color: #96858F;
}
.col-2 {
background-color:#9099A2;
margin-left: auto; /* CHANGE */
margin-right: auto; /* CHANGE */
}
.col-3 {
background-color: #6d7993;
margin-left: auto;
}
Maybe that is the result you're after? If not something along those lines should be fine. Using media queries as you suggested would also work, changing the flex size from 70% to 100% below a certain width. You could do that by adding something like the below to the end of your CSS:
#media screen and (max-width: 600px) {
.content {
flex: 0 1 100%;
}
}
Hopefully this will point you in the right direction.

Related

How can I make responsive grid layout in html css

I searched over internet and couldn't find this kind of grid layout.
"grid-template-columns" doesnt do the thing, cant do one box bigger then the others. I want 4 equal boxes and 1 box with equal height and width = square box * 2 + gridgap.
here is the image I've illustrated to make you understand what i ment.
I also tried to use display flex but I didnt get the Idea of it. Please, help me. Thanks!
Illustation of my idea
The answer to the question ("How can I make responsive grid layout in html css") is this:
.wrapper {
display: grid;
justify-content: center;
}
.box {
border: 2px solid #000;
width: 128px;
min-height: 128px;
justify-content: center;
margin: 10px;
display: grid;
align-items: center;
}
.box5 {
grid-column: 2/5;
max-width: 280px;
width: 100%;
}
/*for this to be visible, the screen-width has to be under 600px*/
#media (max-width: 600px) {
.box5 {
grid-column: 2/1;
}
}
<div class="wrapper">
<div class="box1 box">128x128</div>
<div class="box2 box">128x128</div>
<div class="box3 box">128x128</div>
<div class="box4 box">128x128</div>
<div class="box5 box">280x128</div>
</div>
Like in the image
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 180px;
}
.row {
display: flex;
flex-direction: row;
justify-content: center;
}
.box {
width: 10vw;
height: 10vw;
margin: 12px;
border: 1px solid black;
}
.box.big {
width: calc(20vw + 24px);
}
<div class="container">
<div class="row">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="row">
<div class="box big"></div>
</div>
</div>
Fields 1-5 directly below each other are centered to the middle at the current width
.container {
display: flex;
flex-direction: column;
align-items: center;
width: 100vw;
height: 100vw;
}
.box {
width: 10vw;
height: 10vw;
margin: 12px;
border: 1px solid black;
}
.box.big {
width: calc(20vw + 24px);
}
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box big"></div>
</div>

Move central div to bottom on mobile

On desktop side columns will take a max-width of 175px leaving the center dynamic but on mobile I want to have a 2x1 grid. Also top columns will be 50% width but the height will depend on their content.
How could I move this center element to the bottom taking 100% of the width and leave the side columns next to each other taking each 50% of the width? I don't want to have hidden and duplicated elements.
#container {
display: flex;
}
.column.left,
.column.right {
max-width: 175px;
}
.column.center {
flex: 1;
text-align: center;
background-color: red;
}
.column.left,
.column.right {
text-align: center;
}
<body>
<div id="container">
<div class="column left">this is a long long long long label</div>
<div class="column center">center</div>
<div class="column right">short label</div>
</div>
</body>
You can use flex-wrap and the order property:
#container {
display: flex;
}
.column.left,
.column.right {
max-width: 175px;
}
.column.center {
flex: 1;
text-align: center;
background-color: red;
}
.column.left,
.column.right {
text-align: center;
}
#media all and (max-width: 600px) {
#container {
flex-wrap: wrap;
}
.column.left, .column.right {
max-width: none;
width: 50%;
}
.column.left {
order: 1;
}
.column.right {
order: 2;
}
.column.center {
order: 3;
width: 100%;
}
}
<body>
<div id="container">
<div class="column left">this is a long long long long label</div>
<div class="column center">center</div>
<div class="column right">short label</div>
</div>
</body>
You can do this easily enough with CSS grid and a media query. See the snippet below
#container {
display: grid;
grid-gap: 1rem;
grid-template-columns: var(--gridColTemplate, 1fr 1fr);
}
.column { text-align: center }
.column.left, .column.right { max-width: var(--sideMaxWidth, none) }
.column.center {
grid-column: var(--centerCol, 1/-1);
grid-row: var(--centerRow, 2);
background-color: red;
}
#media only screen and (min-width: 600px) {
:root {
--gridColTemplate: auto 1fr auto;
--centerCol: 2/3;
--centerRow: 1;
--sideMaxWidth: 175px;
}
}
<div id="container">
<div class="column left">this is a long long long long label</div>
<div class="column center">center</div>
<div class="column right">short label</div>
</div>

How do I 'shuffle' a set of divs together using flexbox

I'm learning responsive web-development using media queries and I want to know if it's possible to move an element from one div to another without using a script.
On a desktop display it's arranged like
---------
div1 | | div2
div3 | image | div4
div5 | | div6
---------
which is what I was going for.
and on mobile screens I want
---------
| |
| image |
| |
---------
div1
div2
div3
div4
div5
div6
But I can't seem to move divs past their parent divs.
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shuffle</title>
</head>
<body>
<div class="header">
<h1>Shuffle</h1>
</div>
<div id="main">
<div class="leftBox">
<div class="boxItem" id="first">
<p>1</p>
</div>
<div class="boxItem" id="third">
<p>3</p>
</div>
<div class="boxItem" id="fifth">
<p>5</p>
</div>
</div>
<div class="image">
<img src="https://images.unsplash.com/photo-1605842581240-a0e2527d200b?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ">
</div>
<div class="rightBox">
<div class="boxItem" id="second">
<p>2<p>
</div>
<div class="boxItem" id="fourth">
<p>4</p>
</div>
<div class="boxItem" id="sixth">
<p>6</p>
</div>
</div>
</div>
</body>
</html>
CSS
/*
_______________________________________
MOBILE SCREEN
_______________________________________
*/
* {
box-sizing: border-box;
font-family: "Comic Sans MS", Times, serif;
}
#main {
display: -webkit-flex;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
html {
text-align: center;
}
img{
display: inline-block;
max-width: 100%;
height: auto;
}
.image {
display: inline-block;
width: auto;
max-width: 50%;
border: 1px solid gold;
align-self:center;
order: -1;
}
.header {
text-align: center;
}
.boxItem{
border: 1px solid blue;
padding: 2px;
margin: 5px;
}
.leftBox{
display: flex;
flex-direction: column;
width: 50%;
}
.rightBox{
display: flex;
flex-direction: column;
width: 50%;
}
#first{
order: 1;
}
#second{
order: 2;
}
#third{
order: 3;
}
#fourth{
order: 4;
}
#fifth{
order: 5;
}
#sixth{
order: 6;
}
/*
_______________________________________
DESKTOP SCREEN
_______________________________________
*/
#media only screen and (min-width: 768px) {
#first{
order: 1;
}
#second{
order: 2;
}
#third{
order: 3;
}
#fourth{
order: 4;
}
#fifth{
order: 5;
}
#sixth{
order: 6;
}
img{
align-self: center;
}
.image{
align-self: center;
justify-content: center;
align-items: center;
order: 0;
}
#main{
flex-direction: row;
justify-content: space-between;
}
.leftBox{
display:flex;
flex-direction: column;
justify-content: space-between;
min-height: 100%;
align-self: stretch;
}
.rightBox{
display:flex;
flex-direction: column;
justify-content: space-between;
min-height: 100%;
align-self: stretch;
}
}
If it's not possible to do this with css as it's written here, then is there another way to achieve this style using one flexbox?
I also have this on codepen https://codepen.io/johntarvis/pen/LYRYVmd?editors=1100 if that helps.
You can do it like this. by using columns property and set it to 2. It's really difficult to achieve your approach without jquery. but in the image part you can set it to absolute and make it center part.
Here's a sample code.
.wrapper {
position: relative;
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 0;
}
#main {
position: relative;
}
.column {
-webkit-columns: 2;
columns: 2;
text-align: center;
display: flex;
justify-content: space-between;
width: 100%;
flex-wrap: wrap;
}
.sub_col {
display: block;
width: 34%;
min-height: 100px;
border: 1px solid red;
margin: 0 0 1rem;
position: relative;
z-index: 15;
}
.image {
width: 30%;
margin: 0 auto;
padding: 0;
left: 0;
right: 0;
top: 50%;
position: absolute;
transform: translateY(-50%);
}
.image img {
max-width: 100%;
}
#media only screen and (max-width:768px) {
.column {
-webkit-columns: 1;
columns: 1;
}
.sub_col {
width: 100%;
}
.image {
top: 0;
transform: none;
margin-bottom: 1rem;
position: relative;
width: 100%;
}
}
<div class="wrapper">
<div id="main">
<div class="image">
<img src="https://images.unsplash.com/photo-1605842581240-a0e2527d200b?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ">
</div>
<div class="column">
<div class="sub_col">1</div>
<div class="sub_col">2</div>
<div class="sub_col">3</div>
<div class="sub_col">4</div>
</div>
</div>
</div>
In this way your div elements are still in tact by numbering 1,2,3,4 and so on.
You can use #media queries and flexbox to achieve the desired result:
#main {
display: flex;
width: 100%;
flex-direction: row;
height: 300px;
}
#main > div { width: 33%;}
.leftBox, .rightBox {
height: 100%; text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
img {max-width: 100%; height: auto;}
#media screen and (max-width: 768px) {
#main {
flex-direction: column;
height: auto;
}
#main > div { width: 100%;}
.image {order: -1;}
}
<div class="header">
<h1>Shuffle</h1>
</div>
<div id="main">
<div class="leftBox">
<div class="boxItem" id="first">
<p>1</p>
</div>
<div class="boxItem" id="third">
<p>3</p>
</div>
<div class="boxItem" id="fifth">
<p>5</p>
</div>
</div>
<div class="image">
<img src="https://images.unsplash.com/photo-1605842581240-a0e2527d200b?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ">
</div>
<div class="rightBox">
<div class="boxItem" id="second">
<p>2<p>
</div>
<div class="boxItem" id="fourth">
<p>4</p>
</div>
<div class="boxItem" id="sixth">
<p>6</p>
</div>
</div>
</div>
Read more about ordering elements using flex on MDN
This SO related: how can I reorder HTML using media queries?
CSS Grid might be the way to go.
You can maintain a more logical HTML ordering of 1 - 6 and use CSS to organize the display. This also avoids messing around with absolute positioning. The one downside is if you have a dynamic number of rows and want to span the image across all of them, in which case see this answer: https://stackoverflow.com/a/42240114/4665
You will only need to give minimal styling for mobile then replace the code in your desktop media query with the below. Then tweak the style as needed.
#main {
/*Set Grid*/
display: grid;
/*We want 3 equal columns*/
grid-template-columns: 1fr 1fr 1fr;
/*And 3 equal rows -- Can be omitted*/
grid-template-rows: 1fr 1fr 1fr;
/*With a named area for the picture in the middle cell*/
/*grid-template-areas: ". Pic ." ". Pic ." ". Pic .";*/
}
#main>.image {
/*Place the image in column 2*/
grid-column-start: 2;
/*Place the image in the first row, span 3 rows*/
grid-row: 1 / span 3;
/*If Using named area, assign to the named area*/
/*grid-area: Pic; */
}
/*Just for demo purposes, don't move this into your media query!*/
.image>img {
width: 200px;
}
.boxItem {
text-align: center;
}
<div class="header">
<h1>Shuffle</h1>
</div>
<div id="main">
<div class="image">
<img src="https://images.unsplash.com/photo-1605842581240-a0e2527d200b?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ">
</div>
<div class="boxItem"><p>1</p></div>
<div class="boxItem"><p>2</p></div>
<div class="boxItem"><p>3</p></div>
<div class="boxItem"><p>4</p></div>
<div class="boxItem"><p>5</p></div>
<div class="boxItem"><p>6</p></div>
</div>

Is there a way to build this layout with flexbox?

Hi I am trying to build this layout with flexbox.I provided my current code because i dont know how to move further.Even i posted image how iut should look like under the code.I tried everything but i cant achieve these result. Columns 2,3,5,6,7,8 must be same size. Im new to flex box and i really want to achieve this goal. Thanks for any help.
.tall {
height: 300px;
}
.content {
display: flex;
height: 100%;
}
.left {
display: flex;
flex-direction: column;
flex: 1;
}
.box {
padding-bottom: 50px;
}
.right3collumns {
display: flex;
flex-direction: column;
flex: 2;
}
.box2:nth-child(1) {
background-color: teal;
}
.box2:nth-child(2) {
background-color: red;
}
.box2:nth-child(3) {
background-color: blue;
}
.right {
flex: 2;
background: #22B14C;
}
.right2 {
display: flex;
flex-basis: 200px;
flex-direction: column;
background-color: red;
}
.right2small {
flex-basis: 100px;
background-color: turquoise;
}
.box:nth-child(1) {
background: #ED1C24;
}
.box:nth-child(2) {
background: #00A2E8;
}
.box:nth-child(3) {
background: #FFAEC9;
}
<div class="content">
<div class="right">
<img src="assets/group.png" alt="group">
</div>
<div class="left">
<div class="box">Small DIv</div>
<div class="box">Small DIv</div>
</div>
<div class="right2">bigger</div>
<div class="right2small">smaller</div>
<div class="right3collumns">
<div class="box2">Small DIv</div>
<div class="box2">Small DIv</div>
<div class="box2">Small DIv</div>
</div>
</div>
Here is one way of achieving the layout, I strongly advise, if you can, to use CSS Grid instead.
.grid {
display: flex;
flex: 1;
}
.grid--col {
flex-direction: column;
}
.grid__item {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
border: 1px solid #ddd;
}
.grid__item--x2 {
flex: 2;
}
.grid--main {
background: #f5f5f5;
border: 1px dashed #999;
max-width: 960px;
margin: 50px auto;
}
<div class="grid grid--main">
<div class="grid__item">1</div>
<div class="grid__item grid__item--x2">
<div class="grid grid--col">
<div class="grid">
<div class="grid__item">2</div>
<div class="grid__item grid__item--x2">4</div>
<div class="grid__item">8</div>
</div>
<div class="grid">
<div class="grid__item">3</div>
<div class="grid__item">5</div>
<div class="grid__item">6</div>
<div class="grid__item">7</div>
</div>
</div>
</div>
</div>
You can modify the CSS/SCSS code to change the layout for different breakpoints using the CSS #media rules.
For example, you can have everything stacked, when the viewport is less than or equal to 960px.
#media only screen and (max-width: 960px) {
.grid {
flex-direction: column;
}
}
.grid {
display: flex;
flex: 1;
}
.grid--col {
flex-direction: column;
}
.grid__item {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
border: 1px solid #ddd;
}
.grid__item--x2 {
flex: 2;
}
.grid--main {
background: #f5f5f5;
border: 1px dashed #999;
max-width: 960px;
margin: 50px auto;
}
#media only screen and (max-width: 960px) {
.grid {
flex-direction: column;
}
}
<div class="grid grid--main">
<div class="grid__item">1</div>
<div class="grid__item grid__item--x2">
<div class="grid grid--col">
<div class="grid">
<div class="grid__item">2</div>
<div class="grid__item grid__item--x2">4</div>
<div class="grid__item">8</div>
</div>
<div class="grid">
<div class="grid__item">3</div>
<div class="grid__item">5</div>
<div class="grid__item">6</div>
<div class="grid__item">7</div>
</div>
</div>
</div>
</div>

How to set a margin in a HTML element only when there are elements to the right

My question is: How can I put a margin between the 2 elements, without misaligning them in smaller screens?
I'm creating an HTML page with 2 elements disposed along a line, like this:
I made it responsive, so when I have a smaller screen, the elements are wrapped to another line:
Here's a fiddle to this: https://jsfiddle.net/5ye2sc4b/1/
Html:
<div class="container">
<div class="header">Header</div>
<div class="line">
<div class="element element1">Element 1</div>
<div class="element element2">Element 2</div>
</div>
<div class="footer">Footer</div>
</div>
CSS:
.container {
display:flex;
flex-direction: column;
margin-top: 10px;
}
.header, .footer {
background-color: lightblue;
padding: 5px;
margin-bottom: 5px;
margin-top: 5px;
}
.line {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.element {
border: 1px solid gray;
flex-grow: 1;
height: 100px;
}
If I put a right margin in element 1, it will be displayed correctly in bigger screens:
element1 { margin-right: 20px; }
But it will be misaligned to the header on smaller screens:
On the fiddler above I put some buttons to change the global container size, to simulate the problem.
While i think your approach is not the best way to create a responsive layout you might want to simply remove the margin on smaller screens:
#media (max-width: 620px) {
margin-right: 0px
}
I think this is more suitable for CSS grid where you can use gaps:
.container {
/*display: flex;
flex-direction: column; not really useful in this case*/
margin-top: 10px;
}
.header,
.footer {
background-color: lightblue;
padding: 5px;
margin-bottom: 5px;
margin-top: 5px;
}
.line {
display: grid;
/* adjust the 200px to control when elements will wrap */
grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
/* margin only between columns */
grid-column-gap:16px;
}
.element {
border: 1px solid gray;
height: 100px;
}
<div class="container">
<div class="header">Header</div>
<div class="line">
<div class="element element1">Element 1</div>
<div class="element element2">Element 2</div>
</div>
<div class="footer">Footer</div>
</div>
You could do this using media queries:
Make sure your .line has flex-flow: row nowrap; the shorthand code for flex-direction: row;
flex-wrap: nowrap; initially. The children should have a flex-basis of 50%
Then let the media query (#media) do the rest.
As soon as your screen goes below 900px, apply the CSS inside the media query like so:
#media(max-width: 900px){
.line{
flex-flow: row wrap;
}
.element{
flex-basis: 100%;
}
.element1 {
margin-right: 0px;
}
this will remove the margin from your element1 aswell as set the elements to 100% flex basis, aswell as the flex wrap on the .line for it to wrap.
.container {
display:flex;
flex-direction: column;
margin-top: 10px;
}
.header, .footer {
background-color: lightblue;
padding: 5px;
margin-bottom: 5px;
margin-top: 5px;
}
.line {
display: flex;
flex-flow: row nowrap;
}
.element {
border: 1px solid gray;
flex-grow: 1;
height: 100px;
flex-basis: 50%;
}
.element1 { margin-right: 20px; }
#media(max-width: 900px){
.line{
flex-flow: row wrap;
}
.element{
flex-basis: 100%;
}
.element1 {
margin-right: 0px;
}
Html:
<div class="container">
<div class="header">Header</div>
<div class="line">
<div class="element element1">Element 1</div>
<div class="element element2">Element 2</div>
</div>
<div class="footer">Footer</div>
</div>