Is it possible to achieve the following responsive design layout shown in the image below using CSS3 Flexbox? I am able to achieve the desktop layout using the code below. However, I can't think of a way to make div #div3 and #div4 fill below #div1 and #div2
EDIT: I'm sorry that I forgot to mention that it is not restricted to CSS Flexbox only, and it seems like the grid solution would be more flexible so I will just mark it as the accepted answer. Thanks for the help guys!
My code
#div1 {
background-color: red;
width: 100px;
height: 100px;
}
#div2 {
background-color: green;
width: 100px;
height: 100px;
}
#div3 {
background-color: orange;
width: 100px;
height: 100px;
}
#div4 {
background-color: blue;
width: 100px;
height: 100px;
}
.container,
#flex-container {
display: flex;
}
#flex-container {
flex-direction: column;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="test.css">
</head>
<body>
<div class="container">
<div id='div1'></div>
<div id="flex-container">
<div id='div2'></div>
<div id='div3'></div>
<div id='div4'></div>
</div>
</div>
</body>
</html>
Using grid in this case would make it much easier.
Every div here has a grid-area set to some value that is used to indicate how it should behave in the grid according to layout rules defined in .container grid-template-areas every string there defines one row in the grid. The grid-template-rows and grid-template-columns are used to define number of rows and columns
* {
box-sizing: border-box;
}
body {
height: 100vh;
margin: 0;
}
#div1 {
background-color: red;
width: 100%;
height: 100%;
grid-area: div1;
}
#div2 {
background-color: green;
width: 100%;
height: 100%;
grid-area: div2;
}
#div3 {
background-color: orange;
width: 100%;
height: 100%;
grid-area: div3;
}
#div4 {
background-color: blue;
width: 100%;
height: 100%;
grid-area: div4;
}
.container {
display: grid;
height: 100%;
grid-gap: 10px;
padding: 10px;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(2, 1fr);
grid-template-areas: "div1 div2" "div3 div3" "div4 div4";
}
#media (max-width: 768px) {
.container {
grid-template-areas: "div1 div2" "div1 div3" "div1 div4";
}
}
<div class="container">
<div id='div1'></div>
<div id='div2'></div>
<div id='div3'></div>
<div id='div4'></div>
</div>
Yes. First, you could put all the divs inside the same container:
<div id="flex-container">
<div id='div1'></div>
<div id='div2'></div>
<div id='div3'></div>
<div id='div4'></div>
</div>
Then, in container you set flex-direction: column and flex-wrap: wrap. You put width 50% if you want half screen and 100% full screen. The flex-wrap setup will organize items as it should be.
In mobile #media, you change flex-direction to row and width of each div to match the layout you want.
It would be like this:
#div1 {
background-color: red;
height: 100%;
width: 50%;
}
#div2 {
background-color: green;
height: 100px; // or 33.333%
width: 50%;
}
#div3 {
background-color: orange;
width: 50%;
height: 100px; // or 33.333%
}
#div4 {
background-color: blue;
width: 50%;
height: 100px; // or 33.333%
}
#flex-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 300px;
}
#media (max-width: 480px) { // screen width you prefer
#flex-container {
display: flex;
flex-direction: row;
}
#div1 {
width: 50%;
height: 100px;
}
#div2 {
width: 50%;
}
#div3 {
width: 100%;
}
#div4 {
width: 100%;
}
}
Hope it helps.
You could even simplify CSS using classes for repeated properties.
Related
I was trying to make a design in which there are 2 grid items i.e. left and right. I was trying to make the design fluid so that left can take a minimum of its width or 50%
something like min of(width, 50%)
I've tried minmax but it is just the opposite as I want. Now I'm out of options
Remember: first column would be of dynamic width. Just for testing, I've taken it 200px. It should be responsive as well.
In the below snippet I would like the second column to fill the white space between first and
second
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.left {
width: 200px;
background-color: cornflowerblue;
}
.right {
background-color: cadetblue;
}
.container {
display: grid;
height: 100%;
grid-template-columns: minmax(auto, 1fr) 1fr;
}
<div class="container">
<div class="left">LEFT</div>
<div class="right"> Right </div>
</div>
im not sure, if i got your point but you could do this:
grid-template-columns: minmax(auto, auto) 1fr;
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.left {
width: 200px;
background-color: cornflowerblue;
}
.right {
background-color: cadetblue;
}
.container {
display: grid;
height: 100%;
grid-template-columns: minmax(auto, auto) 1fr;
}
<div class="container">
<div class="left">LEFT</div>
<div class="right"> Right </div>
</div>
Flex might be what you are looking for :
Use flex which is the latest trend in CSS
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.left {
width: 200px;
background-color: cornflowerblue;
}
.right {
width: 100%;
background-color: cadetblue;
}
.container {
display: flex;
height: 100%;
width: 100%;
}
<div class="container">
<div class="left">LEFT</div>
<div class="right"> Right </div>
</div>
hello i want to make my site responsive.I have divide body in 4 divs. Every 2 divs has the 100% of the screen and the other two has margin-top : 50%;. Now i want everytime max-width = 800px, I want every div to has the fullscreen and the user scroll down to see the other divs. My site is https://frontjim.github.io if you want to see it. thanks is advance and sorry for my bad english.
i have used this but it didnt work
#media screen and (max-width: 800px) {
body,
html {
margin: 0;
padding: 0;
height: 100%;
max-height: 100vh;
display: flex;
flex-direction: row;
flex: 1 1 auto;
min-height: 0;
}
}
.back {
display: flex;
flex-direction: column;
}
.navbar {
width: 100vw;
height: 100vh;
}
.mater {
width: 100vw;
height: 100vh;
}
.cb {
width: 100vw;
height: 100vh;
}
.scroll {
width: 100vw;
height: 100vh;
}
You can have a general container that has child elements. This container has width: 100vw and height: 100vh, and display: flex. You don't need to add flex-direction: row since it's the default.
The children will have width: 100%.
Snippet:
* {
margin: 0;
padding: 0;
}
.flex {
width: 100vw;
height: 100vh;
display: flex;
}
.div1 {
background-color: red;
width: 100%;
}
.div2 {
background-color: blue;
width: 100%;
}
.div3 {
background-color: green;
width: 100%;
}
.div4 {
background-color: grey;
width: 100%;
}
<div class="flex">
<div class="div1"></div>
<div class="div2"></div>
</div>
<div class="flex">
<div class="div3"></div>
<div class="div4"></div>
</div>
Use CSS Grid, it can get the job done easily
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Responsive Grid</title>
</head>
<body>
<div class="main">
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
<div class="div4"></div>
</div>
</body>
</html>
CSS:
* {
margin: 0;
padding: 0;
}
.main {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 100vh 100vh;
}
.div1 {
background-color: lightgreen;
}
.div2 {
background-color: lightseagreen;
}
.div3 {
background-color: coral;
}
.div4 {
background-color: lightblue;
}
#media screen and (max-width: 800px) {
.main {
grid-template-columns: 1fr;
grid-template-rows: 100vh 100vh 100vh 100vh;
}
}
Live view: https://codepen.io/zgheibali/pen/ZEWWVvr
I hope that my answer was helpful :)
change the design.use like this:
in html::
<div class='flexyy'>
<div class='div1'>....</div>
<div class='div2'>....</div>
<div class='div3'>....</div>
<div class='div4'>....</div>
</div>
in css::
div1{
width:100%;
}
div2{
width:100%;
}
div3{
width:100%;
}
div4{
width:100%;
}
#media(min-width:800px){
.div1,.div2,.div3,.div4{
width:auto;
}
.flexyy{
display:flex;
flex-direction:row;
flex: 0.5 1 auto;
flex-wrap:wrap;
}
}
I'm developing an app with the interface that is supposed to fit the page (only some internal elements may have scrolling). The basic layout consists of a header and the main section:
<div class="page">
<Navigation/> <!-- a Vue component -->
<main class="page__main">
...
</main>
</div>
currently, CSS has hardcoded height of the header (Navigation):
.page {
height: 100vh;
}
.page__main {
height: calc(100vh - 80px); /* 80px is the height of the header */
}
I'd like to get rid of this hardcoded bit but make sure .page__main's height gets no larger than 100vh - height of Navigation. Is there a way to do this without JS? I suspect that there are some options that can be used with
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
but just using that with
.page__main {
flex-shrink: 1;
}
doesn't work: .page__main has children which use height in percents and once I set flex-shrink: 1; instead of height: calc(100vh - 80px); those grow and the interface is broken.
To illustrate the problem better, here's the current state:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
height: calc(100vh - 80px);
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
and here's what happen when I try to "set height" via flex:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-shrink: 1;
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
You can consider a nested flexbox container and don't forget the use of min-height:0; to allow the elements to shrink.
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-grow: 1; /* Fill the remaining space*/
display:flex; /* Nested Container*/
flex-direction:column;
min-height:0; /* Allow the element to shrink */
}
.part1 {
flex-basis: 50%;
background: #eeeeee;
overflow-y: scroll; /* Allow the element to shrink */
}
.part2 {
flex-basis: 50%;
min-height:0; /* Allow the element to shrink */
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
Use flex-grow. Keep everything as the second one (flex one) and change:
Edit
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__main {
height: 100%;
min-height: 0;
flex: 1 1 auto;
}
Three value flex means flex: flex-grow | flex-shrink | flex-basis.
Flex-grow tells our element whether or not it can take up additional space.
Flex-shrink works very similarly to flex-grow, only instead of dealing with extra space, it deals with space not needed by an elements content.
Flex basis is best used when in conjunction with either flex-shrink or flex-grow.
You can check this article to understand better.
I would suggest css-grid approach : -
.page {
background: gray;
display: grid;
grid-template-rows: 100px auto;
height: 100vh;
color: white;
}
.nav {
grid-row: 1/2;
background: brown;
}
.main {
grid-row: 2/3;
background: green;
display: grid;
grid-template-rows: 30% 70%;
}
.part1 {
overflow: auto
}
.part2 {
background: blue
}
<div class="page">
<div class="nav">Nav</div>
<div class="main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</div>
</div>
</div>
Like in the image - http://i65.tinypic.com/aa7ndw.png Examples and live flex configurators are explain only simple examples, or I just don't get it.
Will I be able to use media queries to for example not display a4 when < 800px?
I have always used float and flex is somehow 'different' anyway I would like to know it better, so any help is appreciated.
flex specific example
Apply display: flex to a container and its child elements will be displayed in flex. For this layout, you will want to wrap the elements when width is already filled for the current row.
The header and footer will be width: 100%, taking a full row. #a3 and #a4 will have flex: 1 to distribute the width of their row, taking each one 50% of the width.
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>
And yeah, you can use media queries as normal
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
#media (max-width: 800px){
#a4{
display: none;
}
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>
I have these two different layouts illustrated in the code below. My issue is that I can't replicate these layouts without changing the markup. I was wondering if there was some fancy flexbox way I can accomplish exactly this while only using one html scheme. Note: the container will need to have a dynamic height. The solution doesn't necessarily have to use flexbox as long as the desired layout is achieved.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
}
.a {
background: red;
width: 40%;
}
.b {
background: blue;
width: 60%;
}
.c {
background: green;
}
.a-mobile {
background: red;
width: 40%;
}
.b-mobile {
background: blue;
width: 60%;
}
.c-mobile {
background: green;
width: 100%;
}
<h2>Desktop</h2>
<main>
<div class="a">a</div>
<div class="b">b
<div class="c">c</div>
</div>
</main>
<h2>Mobile</h2>
<main>
<div class="a-mobile">a-mobile</div>
<div class="b-mobile">b-mobile</div>
<div class="c-mobile">c-mobile</div>
</main>
display:grid will be useful for this kind of layout:
but this is still experimental and(2020) can be tested in few browsers, see also http://caniuse.com/#search=grid
A tutorial among others https://css-tricks.com/snippets/css/complete-guide-grid/
main {
display: grid;
grid-template-columns: 30% auto;
}
.a {
background: red;
grid-row-end: span 2
}
.b,
.c {
background: green;
}
.c {
background: lightblue
}
#media screen and (max-width: 700px) {/* value setted for the demo */
.a {
grid-row-end: span 1/* reset optionnal in this very case */
}
.c {
grid-column-end: span 2
}
}
<main>
<div class="a"> break point set at 700px for demo</div>
<div class="b"> i don't move much myself :)</div>
<div class="c"> see in full page to see me aside the red box and below the green one</div>
</main>
codepen to play with
Here's the float-flexbox method I described in the comments. Not particularly fond of it, but it does exactly what you asked for.
It's hacky and, from my POV, goes in the same category as Bootstrap 3's .clearfix::before|after hack — {display:table; content: " ";} — it is a practical solution to a real layout problem, usable until a better, cleaner one will have better browser support and render this one obsolete.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
margin-bottom: 1em;
color: white;
}
.a {
background: red;
flex-basis: 40%;
}
.b {
background: blue;
flex-basis: 60%;
}
.c {
background: green;
flex-basis: 100%;
}
#media (min-width: 800px) {
main {
display: block;
overflow: hidden;
}
.a {
float: left;
min-width: 40%;
}
.b,.c {
padding-left: 40%;
}
.a,.c {
padding-bottom: 32768px;
margin-bottom: -32768px;
}
}
<main>
<div class="a">a<br />a<br />a<br/>a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b<br />b<br />b<br/>b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c<br />c<br />c<br/>c</div>
</main>
Another solution, it's independent of flex box, and does not need fixed height.
Flexbox does not do a good job of adjusting to two dimensional layouts!
html {
height: 100%;
}
body {
height: 100%;
}
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
height: 100%;
}
.a {
background: red;
width: 40%;
height: 100%;
float: left;
}
.b {
background: blue;
width: 60%;
height: 50%;
float: left;
}
.c {
background: green;
width: 60%;
height: 50%;
float: left;
}
#media (max-width: 800px) {
.a {
width: 40%;
height: 50%;
}
.c {
width: 100%;
}
}
<h2>Desktop and Mobile</h2>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>