I created a responsive four-column layout by using a mobile-first approach. The smallest screen shows 1 column, the larger screen 2 columns, and the largest screen 4 columns.
It seems to work so far, but I'd like you to take a look at my code and tell me if there's anything wrong with my approach. I would be grateful for your opinions.
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FlexBox Test</title>
<style>
:root {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
/* mobile phone */
.flex-container {
display: flex;
flex-wrap: wrap;
max-width: 1400px;
margin: 0 auto;
border: 1px solid red;
padding: 1em;
}
.flex-item-1 {
background: indianred;
}
.flex-item-2 {
background: blue;
}
.flex-item-3 {
background: tomato;
}
.flex-item-4 {
background: coral;
}
.flex-item {
flex: 100%;
height: 100px;
}
/* tablet */
#media screen and (min-width: 640px) {
.flex-item {
flex: calc(50% - 1em);
}
.flex-item:nth-child(2n) {
margin-left: 1em;
}
}
/* desktop */
#media screen and (min-width: 960px) {
.flex-item {
flex: calc(25% - 1em);
}
.flex-container > * + * {
margin-left: 1em;
}
}
</style>
</head>
<body>
<div class="flex-container">
<div class="flex-item flex-item-1">
1
</div>
<div class="flex-item flex-item-2">
2
</div>
<div class="flex-item flex-item-3">
3
</div>
<div class="flex-item flex-item-4">
4
</div>
</div>
</body>
</html>
If you want remove calc from the css you can do something like that.
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FlexBox Test</title>
<style>
:root {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
/* mobile phone */
.flex-container {
display: flex;
flex-wrap: wrap;
max-width: 1400px;
margin: 0 auto;
border: 1px solid red;
padding: 1em;
}
.flex-item-1 {
background: indianred;
}
.flex-item-2 {
background: blue;
}
.flex-item-3 {
background: tomato;
}
.flex-item-4 {
background: coral;
}
.flex-item {
flex: 100%;
height: 100px;
}
/* tablet */
#media screen and (min-width: 675px) and (max-width: 960px) {
.flex-item {
flex: 1 0 19em;
}
.flex-item:nth-child(2n) {
margin-left: 1em;
}
}
/* desktop */
#media screen and (min-width: 960px) {
.flex-item {
flex: 1 0;
}
.flex-container > * + * {
margin-left: 1em;
}
}
</style>
</head>
<body>
<div class="flex-container">
<div class="flex-item flex-item-1">
1
</div>
<div class="flex-item flex-item-2">
2
</div>
<div class="flex-item flex-item-3">
3
</div>
<div class="flex-item flex-item-4">
4
</div>
</div>
</body>
</html>
However to keep the margin as you have on your initial example, I have to change #media screen and (min-width: 675px) and (max-width: 960px) for tablet screen. If not, three block appears on the first line for specific browser width (not the same behaviour as you want).
What do you think about that ?
Related
so i want to resize the flex layout when the screen get smaller but the media query doesnt work and im not sure why.
Im new to this i've tried looking on this site but I don't know enough of this media query system to understand the problem im getting
*{
box-sizing: border-box;
}
body{
padding: 0;
margin: 0;
}
.layout {
display: flex;
flex-wrap: wrap;
}
.nav {
flex-basis: 100%;
border-bottom: 1px solid #aaa;
padding: 20px;
}
.sidebar {
flex-basis: 20%;
border-right: 1px solid #aaa;
padding: 20px;
border-bottom: 1px solid #aaa;
}
.content {
flex-basis: 80%;
padding: 20px;
border-bottom: 1px solid #aaa;
}
#media (max-with: 640px){
.sidebar {
flex-basis: 100%;
border-right: 0;
}
.content {
flex-basis: 100%;
}
}
i have the this in the head
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
and this in the body
<div class="layout">
<div class="nav">
navigation in here
</div>
<div class="sidebar">
sidebar in here
</div>
<div class="content">
content in here
</div>
</div>
A spelling error is tripping you up.
You wrote:
#media (max-with: 640px)
It should be max-width with a ādā.
This how I would do:
/*------------------------------------
css media quories start
-------------------------------------*/
#media only screen and (max-width: 640px) {
.sidebar {
flex-basis: 100%;
border-right: 0;
}
.content {
flex-basis: 100%;
}
}
/*------------------------------------
css media quories end
-------------------------------------*/
I created a small sample that shows movie covers and I like the "flex: calc(...)" in action. As the browser window is reduced the size of the images are also reduced a bit. However notice when the image wraps, the wrapped image is in full width. Is it possible to make the wrapped image to be the same size as the images above it?
:root {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
}
.movies {
max-width: 1300px;
margin: 0 auto;
}
.flex-container {
display: flex;
flex-flow: row wrap;
}
.flex-item {
margin: 10px 15px 0;
}
.flex-item > img {
width: 100%;
height: 100%;
display: block;
}
/* Tablet */
#media screen and (min-width: 40em) {
body {
background: limegreen;
}
.movies {
max-width: 700px;
}
.flex-item {
margin: 0 15px 32px;
flex: calc(50% - 30px);
}
}
/* Desktop */
#media screen and (min-width: 70em) {
body {
background: lightyellow;
}
.movies {
max-width: 1200px;
}
.flex-item {
margin: 0 6px 15px;
flex: calc(33.3333% - 20px);
}
}
<!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="learn-flex.css">
<title>Learn Flex</title>
</head>
<body>
<div class="movies">
<div class="flex-container">
<div class="flex-item-1 flex-item">
<img src="https://images-na.ssl-images-amazon.com/images/I/81PWF-yAEyL._AC_SL1100_.jpg" alt="">
</div>
<div class="flex-item-2 flex-item">
<img src="https://images-na.ssl-images-amazon.com/images/I/71VDlRubWtL._AC_SY741_.jpg" alt="">
</div>
<div class="flex-item-3 flex-item">
<img src="https://fanart.tv/fanart/movies/12230/movieposter/101-dalmatians-5a529ef29b36c.jpg" alt="">
</div>
</div>
</div>
</body>
</html>
I want the image with the dogs to be the same size as the ones above and leave the space on the right side empty, since there is no fourth cover. Is it possible to achieve that with flexbox?
If you are setting the width of a flex item you can also ask that it neither shrink nor grow. e.g. in your tablet case:
.flex-item {
margin: 0 15px 32px;
flex: 0 0 calc(50% - 30px);
:root {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
}
.movies {
max-width: 1300px;
margin: 0 auto;
}
.flex-container {
display: flex;
flex-flow: row wrap;
}
.flex-item {
margin: 10px 15px 0;
}
.flex-item > img {
width: 100%;
height: 100%;
display: block;
}
/* Tablet */
#media screen and (min-width: 40em) {
body {
background: limegreen;
}
.movies {
max-width: 700px;
}
.flex-item {
margin: 0 15px 32px;
flex: 0 0 calc(50% - 30px);
}
}
/* Desktop */
#media screen and (min-width: 70em) {
body {
background: lightyellow;
}
.movies {
max-width: 1200px;
}
.flex-item {
margin: 0 6px 15px;
flex: 0 0 calc(33.3333% - 20px);
}
}
<!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="learn-flex.css">
<title>Learn Flex</title>
</head>
<body>
<div class="movies">
<div class="flex-container">
<div class="flex-item-1 flex-item">
<img src="https://images-na.ssl-images-amazon.com/images/I/81PWF-yAEyL._AC_SL1100_.jpg" alt="">
</div>
<div class="flex-item-2 flex-item">
<img src="https://images-na.ssl-images-amazon.com/images/I/71VDlRubWtL._AC_SY741_.jpg" alt="">
</div>
<div class="flex-item-3 flex-item">
<img src="https://fanart.tv/fanart/movies/12230/movieposter/101-dalmatians-5a529ef29b36c.jpg" alt="">
</div>
</div>
</div>
</body>
</html>
I have to achieve below three layout - in a responsive way.
1st layout - default layout
2nd Layout - with "min-width:600px"
3rd Layout - with "min-width:700px"
Above three layout I have already achieved.
I have mentioned height "200px" for dark-blue and red colored divs, which is actually somewhat fixed. If at a later stage, content in it increases (hypothetically) - the design layout will fail I think.
Is there any better way of doing it dynamically and my design doesn't fail if content increases.
I tried to think of it but couldn't get any.
Just Asked this question for better learning.
I wanted to achieve it by using flexbox. Any other way is also appreciated.
Can someone point in right direction?
I have added my HTML and css code.
/* default color of background */
.red {
background: red;
}
.dark-blue {
background: darkblue;
}
.light-blue {
background: lightblue;
}
.green {
background: green;
}
/* Container properties */
.container {
/* mentioned 100% so that element inside takes full width i.e with id = container2 */
width: 100%;
display: flex;
flex-wrap: wrap;
}
.box {
width: 100%;
height: 100px;
}
/* Responsive design proprties */
#media screen and (min-width: 600px) {
.dark-blue {
width: 50%;
height: 200px;
}
#container2 {
width: 50%;
height: 50%;
}
}
#media screen and (min-width: 700px) {
.dark-blue,
.red {
height: 200px;
}
.dark-blue {
width: 25%;
order: 2;
}
#container2 {
width: 50%;
flex-wrap: wrap;
}
.red {
width: 25%;
order: -1;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Layout shifter</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container">
<div class="box dark-blue"></div>
<div class="container" id="container2">
<div class="box light-blue"></div>
<div class="box green"></div>
</div>
<div class="box red"></div>
</div>
</body>
</html>
Flexbox has some advanatges and some downsides. one of the downsides is, that it is only good in controlling either height or width. Not both.
If you need to control both, CSS-Grid is the way to go.
Use grid-template-areas to place the divs. Its the equivalent to flex order.
body {
margin: 0;
width: 100vw;
min-height: 100vh;
box-sizing: border-box;
display: grid;
}
.dark-blue {
grid-area: dark-blue;
background-color: darkblue;
}
.light-blue {
grid-area: light-blue;
background-color: lightblue;
}
.green {
grid-area: green;
background-color: green;
}
.red {
grid-area: red;
background-color: red;
}
#media only screen
and (max-width: 600px) {
body {
grid-template-areas:
"dark-blue"
"light-blue"
"green"
"red"
}
}
#media only screen
and (max-width: 600px) {
body {
grid-template-areas:
"dark-blue"
"light-blue"
"green"
"red";
}
}
#media only screen
and (min-width: 601px)
and (max-width: 700px) {
body {
grid-template-areas:
"dark-blue light-blue"
"dark-blue green"
"red red";
}
}
#media only screen
and (min-width: 701px) {
body {
grid-template-areas:
"red light-blue light-blue dark-blue"
"red green green dark-blue"
}
}
<div class="dark-blue"></div>
<div class="light-blue"></div>
<div class="green"></div>
<div class="red"></div>
I have a container with four boxes. The container all together should be the width of the window.
Above 720px, there should be one row of four boxes.
Below 720px, there should be two rows of two boxes.
Below 600px, there should be four rows of one box.
I'm confused what I should put in the media queries.
html,
body {
width: 100%;
height: 100%;
}
.container {
border: 1px solid black;
display: flex;
height: 100%;
width: 100%;
}
.column {
border: 1px solid red;
flex: 1;
}
#media (max-width: 720px) {
.container {
?
}
}
#media (max-width: 600px) {
.container {
?
}
}
<div class="container">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
Set the flex items to wrap at your breakpoints.
Here's a fiddle demo.
.container {
display: flex;
flex-wrap: wrap;
height: 100vh;
}
.column {
flex: 1;
border: 1px solid black;
background-color: lightgray;
}
#media (max-width: 720px) {
.column {
flex-basis: 34%;
background-color: orange;
}
}
#media (max-width: 600px) {
.column {
flex-basis: 51%;
background-color: lightgreen;
}
}
body {
margin: 0;
}
<div class="container">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
Note that with flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis to be exact (25%, 50%, 100%), which can result in unequal wrapping if you were to add margin space.
Since flex-grow will consume free space on the row, flex-basis only needs to be large enough to enforce a wrap. This will ensure plenty of space for margins, but not enough space for an extra item.
You could use grids to achieve this. If you name them like I did in the snippet, it is easy to alter the sequence of the columns.
.container {
display: grid;
grid-auto-rows: 200px;
grid-auto-columns: auto;
grid-template-areas:
"column1 column2 column3 column4";
border: 1px solid black;
width: 100%;
height: 100%;
}
.column {
display: flex;
}
.column1 {
grid-area: column1;
background-color: red;
}
.column2 {
grid-area: column2;
background-color: yellow;
}
.column3 {
grid-area: column3;
background-color: green;
}
.column4 {
grid-area: column4;
background-color: blue;
}
#media (max-width: 720px) {
.container {
grid-template-areas:
"column1 column2"
"column3 column4";
}
}
#media (max-width: 600px) {
.container {
grid-template-areas:
"column1"
"column2"
"column3"
"column4";
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="container">
<div class="column column1"></div>
<div class="column column2"></div>
<div class="column column3"></div>
<div class="column column4"></div>
</div>
</body>
</html>
More info about grids in CSS here
I want to place description under the photo from 768px up, but without white gap between them. Could someone help me.
I note that the HTML order cannot be changed. Eventually element's can be wrapped.
I tried flexbox and grid layout but with no success.
Below is the latest version of what I am trying to achieve.
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
* {
box-sizing: border-box;
}
#media (min-width: 768px) {
.container {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
}
.container div {
padding: 20px;
}
.container .name {
background: orange;
}
#media (min-width: 768px) {
.container .name {
flex-basis: 100%;
}
}
.container .photo {
background: yellow;
}
#media (min-width: 768px) {
.container .photo {
flex-basis: 50%;
padding: 100px 20px;
}
}
.container .price {
background: purple;
}
#media (min-width: 768px) {
.container .price {
flex-basis: 50%;
padding: 150px 20px;
}
}
.container .description {
background: blue;
flex-basis: 50%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div class="container">
<div class="name">name</div>
<div class="photo">photo</div>
<div class="price">price</div>
<div class="description">description</div>
</div>
</body>
</html>
You don't really need flexbox layout for that. A couple of good old-fashioned floats will do.
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
* {
box-sizing: border-box;
}
#media (min-width: 768px) {
.container {
position: relative;
}
}
.container div {
padding: 20px;
}
.container .name {
background: orange;
}
.container .photo {
background: yellow;
}
#media (min-width: 768px) {
.container .photo {
float: left;
width: 50%;
padding: 100px 20px;
}
}
.container .price {
background: purple;
}
#media (min-width: 768px) {
.container .price {
float: right;
width: 50%;
padding: 150px 20px;
}
}
.container .description {
background: blue;
}
#media (min-width: 768px) {
.container .description {
float: left;
clear: left;
width: 50%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div class="container">
<div class="name">name</div>
<div class="photo">photo</div>
<div class="price">price</div>
<div class="description">description</div>
</div>
</body>
</html>