Responsive flexbox layout wrap issue - css

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>

Related

CSS: Is it possible to achieve the following layout?

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.

flexbox how to achieve this specific layout?

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>

How to split a column in a responsive view using Bootstrap?

I'm using Bootstrap v4 alpha4
Currently I have:
.row
.col-xs-12.col-md-8
div A
.col-xs-12.col-md-4
div B
div C
For the xs layout, I'd like the div order to be:
Div B
Div A
Div C
I have no idea how to do this or how to even ask about it. I'm not a front-end dev so I don't know what things are called.
We can change the HTML to whatever we want. It does not have to stay like it is now.
Bootstrap does have column ordering classes, but in this case you can simply use the responsive float classes..
<div class="row">
<div class="col-md-4 pull-md-right">
b
</div>
<div class="col-md-8">
a
</div>
<div class="col-md-4">
c
</div>
</div>
http://www.codeply.com/go/XL5zJELyLD
So using the classes from bootstrap and some general style you can achieve that like I did in this pen.
http://codepen.io/TunderScripts/pen/PGadpr
The Html:
<div class="row">
<div class="col-xs-12 col-md-4 pull-right col1"></div>
<div class="col-xs-12 col-md-8 pull-left col2"></div>
<div class="col-xs-12 col-md-4 pull-right col3"></div>
</div>
the css:
.col1{
background: red;
height: 200px;
}
.col2{
background: blue;
height: 600px;
}
.col3{
background: green;
height: 200px;
}
You can change the default behavior by using their classes for floats(pull-left, pull-right).
Instead of flexbox, I used combination of float and position css properties to get the expected result. Assuming large width as 150px and small width as 100px.
Working Fiddle
.container {
width: 250px;
position: relative;
}
.blue {
width: 150px;
height: 300px;
background: blue;
position: absolute;
}
.pink {
width: 100px;
height: 100px;
background: pink;
float: right;
}
.green {
width: 100px;
height: 100px;
background: green;
clear: right;
float: right;
}
#media (max-width: 450px) {
.blue {
position: relative;
}
.green,
.pink {
float: none;
width: 150px;
}
}
<div class="container">
<div class="pink"></div>
<div class="blue"></div>
<div class="green"></div>
</div>
As promised, a simple draft
HTML
<div class="row">
<div class="col1">DIV A</div>
<div class="col2">DIV B</div>
<div class="col3">DIV C</div>
</div>
CSS
.row {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
width: 400px;
margin: 0 auto;
}
.col1 {
width: 200px;
height: 400px;
background-color: #86a0ff;
}
.col2 {
width: 150px;
height: 150px;
background-color: #ff6cde;
}
.col3 {
margin-top: -200px;
margin-left: auto;
width: 150px;
height: 150px;
background-color: #35af6d;
}
#media (max-width: 768px) {
.row {
justify-content: center;
flex-direction: column;
}
.col1 {
order: 2;
width: 200px;
margin-top: 50px;
}
.col2 {
order: 1;
width: 200px;
}
.col3 {
order: 3;
width: 200px;
margin-top: 50px;
margin-left: 0;
}
}
As for explanation, here is a great guide to flexbox. The main idea in my example is that by using order property you can manipulate the order in which blocks are displaying. The main plus of using flexbox is that you won't need to load any library(such as Bootstrap) to achieve the desired result, such as responsiveness. And it also has a good browser support, unless you need to support older versions of browsers. I hope my answer will be helpful for you!

Make full-width without setting `width` [duplicate]

This question already has answers here:
Setting div width to 100% minus certain amount of px
(5 answers)
Expand a div to fill the remaining width
(21 answers)
Closed 6 years ago.
I will simulate what i need to achieve.
for example, i want that #2 took the whole space, remaining of 100% - 180px.. how to achieve that?
p.s. seems flexbox is more supported over devices than calc - http://css3clickchart.com/#flexbox
You can use flexbox model as shown below. Adding flex: auto; will allow the right content to use remaining width.
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#parent {
display: flex;
height: 100%;
}
#left {
width: 180px;
background-color: hotpink;
}
#right {
flex: auto;
background-color: dodgerblue;
}
<div id="parent">
<div id="left"></div>
<div id="right"></div>
</div>
Use css calc
Here with a example.. This might help:
.class {
width: -moz-calc(100% - 100px);
width: -webkit-calc(100% - 100px);
width: calc(100% - 100px);
}​
You can use float: left and overflow: hidden.
aside {
float: left;
width: 30%;
background: beige;
}
article {
overflow: hidden;
background: brown;
color: white;
}
<aside>
sidebar
</aside>
<article>
content
</article>
There are many ways to do this. One simple way is below.
1st way: Simple inline-block
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
float: left;
}
.main-content {
display: inline-block;
background-color: green;
}
<div class="container">
<div class="main-content">Main Content</div>
<div class="sidebar">Sidebar</div>
</div>
Fair warning though: In this case the .main-content will only take the space it needs, and will not actually be full width. So If you want to set background to it, you should actually set the backround to .container.
2nd way: Use calc for width
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
position: relative;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
float: left;
}
.main-content {
float: right;
background-color: green;
width: calc(100% - 180px);
height: 600px;
}
<div class="container">
<div class="main-content">Main Content</div>
<div class="sidebar">Sidebar</div>
</div>
3rd way: use Flex
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
display: flex;
}
.sidebar {
background-color: red;
width: 180px;
height: 600px;
}
.main-content {
background-color: green;
flex: auto;
}
<div class="container">
<div class="sidebar">Sidebar</div>
<div class="main-content">Main Content</div>
</div>
Flexbox is probably the nicest solution, but saidly old browsers don't support it.
4th way of doing this is the oldfasioned way with faking tables:
.container {
width: 100%;
height: 600px;
background-color: #f2f2f2;
display: table;
}
.sidebar {
background-color: red;
width: 180px;
display: table-cell;
}
.main-content {
display: table-cell;
background-color: green;
}
<div class="container">
<div class="sidebar">Sidebar</div>
<div class="main-content">Main Content</div>
</div>

First div fixed, second full width. Cant change structure of html

Have problem. I have this code.
<div class="main">
<div class="sidebar"></div>
<div class="content"></div>
</div>
I need to make two colums.
"Sidebar" must have fixed width 200px;
And "content" all remaining width to fullscreen.
I cant change the structure of html code, just css.
if absolute position is ok, you can use it to say left:200px; right:0 and get all the space you need
fiddle : http://jsfiddle.net/h2udmqhn/
.main {
position: relative;
height: 300px;
width: 300px;
border: 1px solid black;
}
.sidebar {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
top: 0;
left: 200px;
right: 0;
height: 200px;
background: blue;
}
<div class="main">
<div class="sidebar"></div>
<div class="content"></div>
</div>
Use float: left for .sidebar and left margin for .content:
.sidebar {float: left; width: 200px; background: red;}
.content {background: green; margin: 0 0 0 200px;}
http://jsfiddle.net/orty5qtj/1/
Another option is to use calc, which is unsupported in IE8. The solution above works fine in all browsers.
Try this :
.sidebar {
float: left;
min-height: 50px;
background: red;
width: 200px;
}
.content {
background : yellow;
margin-left: 200px;
min-height: 50px;
}
https://jsfiddle.net/Saiyam/5krmkkkx/3/
There a couple of simple ways to do this without the need for calc, margins or absolute positioning. Both of the following ways have the added bonus of keeping the columns the same height as each other
Using display table (compatible to back ie8)
.main {
display: table;
width: 100%;
}
.main > div {
display: table-cell;
}
.sidebar {
width: 200px;
background: blue;
}
.content {
background: red;
}
<div class="main">
<div class="sidebar">200px</div>
<div class="content">the rest</div>
</div>
Using flex (for newer browsers only unless used with the browser prefix):
.main {
display: flex;
width:100%;
max-width:100%;
}
.sidebar {
width: 200px;
flex: 0 0 200px;
background-color:blue;
}
.content {
background-color:red;
flex: 1 0 auto;
}
<div class="main">
<div class="sidebar">200px</div>
<div class="content">the rest</div>
</div>

Resources