CSS layout - grid or flex [closed] - html

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I'm trying to create this layout.
https://pasteboard.co/K1C5o3k.jpg
I tried to use display: grid but the spacing was strange. What would be the best solution? Use grid or flexbox? How do I achieve this spacing using grid or flexbox?
<div class="wrap">
<div class="test-grid">
<div class="card box1">some text</div>
<div class="card box2">some text</div>
<div class="card">some text</div>
<div class="card box4">some text</div>
</div>
</div>
.wrap {
max-width: 600px;
}
.test-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 1em;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
margin-top: 40px;
}
.box4 {
grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 2;
grid-row-end: 3;
}

On your grid layout, I use grid-template-row/columns to define the fraction amount and then grid-template-areas to layout the elements, for each child element you want to define the unique class as its grid-area. You can use gap to control the spacing between the elements. Once you define a height and width for the parent element, the children will fill in their respective fraction, along with any defined gap.
Then use a media query with flex for your mobile layout. You may need to tweek the CSS a bit to get it to look just as you want, but the following example should do the trick.
.test-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
gap: 20px 20px;
grid-template-areas:
". two ."
"one two four"
"one three four"
". three .";
width: 100vw;
height: 100vh;
}
.one {
grid-area: one;
background-color: tomato;
}
.two {
grid-area: two;
background-color: tomato;
}
.three {
grid-area: three;
background-color: tomato;
}
.four {
grid-area: four;
background-color: tomato;
}
.box {
display: flex;
justify-content: center;
align-items: center;
}
#media only screen and (max-width: 600px) {
.test-grid {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.box {
width: 100%;
height: 100%;
}
}
<div class="test-grid">
<div class="one box">some text</div>
<div class="two box">some text</div>
<div class="three box">some text</div>
<div class="four box">some text</div>
</div>

Both Grid and flex will do the work, it just based on your preferences.
Snippet below will do the trick and when the screen became small (less than 500px). The grid will show as a list.
.wrap {
max-width: 600px;
}
.test-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 1em;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
grid-column: 1/span 1;
grid-row: 2/span 2;
}
.box2 {
grid-column: 2/span 2;
grid-row: 1/span 1;
}
.box3 {
grid-column: 3/span 2;
grid-row: 2/span 2;
}
.box4 {
grid-column: 2/span 2;
grid-row: 3/span 3;
}
#media (max-width: 500px) {
.test-grid {
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
<div class="wrap">
<div class="container">
<div class="test-grid">
<div class="card box1">box1</div>
<div class="card box2">box2</div>
<div class="card box3">box3</div>
<div class="card box4">box4</div>
</div>
</div>

Here's an option using only grid. In this example we create many small grid rows (10px each) which then allows you to start each element at a specific row and adjust the boxes by 10 pixel increments.
.test-grid {
display: grid;
grid-template-columns: repeat(3, 160px);
grid-template-rows: repeat(45, 10px);
column-gap: 10px;
}
.card {
background-color: tomato;
width: 160px;
min-height: 220px;
}
.box1 {
grid-row-start: 10;
}
.box2 {
grid-row-start: 0;
grid-column-start: 2;
}
.box3 {
grid-row-start: 24;
grid-column-start: 2;
}
.box4 {
grid-row-start: 8;
grid-column-start: 3;
}
<div class="wrap">
<div class="test-grid">
<div class="card box1">some text</div>
<div class="card box2">some text</div>
<div class="card box3">some text</div>
<div class="card box4">some text</div>
</div>
</div>

Related

How to use CSS Grid to make layout where one column has a maximum size

I'm trying to make a layout with a "page".
I would have 3 columns, 1st and 3th would use only 10% of the space, and the middle 80%. Until there no problem. But I would like that as soon as the middle part reach 64rem, it's only the first and last column that grow.
Currently I've tried this:
.container {
display: grid;
grid-template-columns: 10% minmax(80%, 64rem) 10%;
grid-template-rows: min-content auto;
min-height: 100vh;
background-color: red;
}
.header {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
background-color: blue;
}
.content {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 3;
background-color: yellow;
}
<div class="container">
<div class="header">
header
</div>
<div class="content">
content
</div>
</div>
But it doesn't stops at 64rem. Any idea how to adress this issue?
Replace the 10% with 1fr and consider min() instead of minmax(). I used 32rem instead of 64rem to easily demonstrate the trick
.container {
display: grid;
grid-template-columns: 1fr min(80%, 32rem) 1fr;
grid-template-rows: min-content auto;
min-height: 100vh;
background-color: red;
}
.header {
grid-column: 2;
background-color: blue;
}
.content {
grid-column: 2;
background-color: yellow;
}
<div class="container">
<div class="header">
header
</div>
<div class="content">
content
</div>
</div>
You can also use padding and simplify the code like below:
.container {
display: grid;
padding-inline: max(10%,(100% - 32rem)/2);
grid-template-rows: min-content 1fr;
min-height: 100vh;
background-color: red;
}
.header {
background-color: blue;
}
.content {
background-color: yellow;
}
<div class="container">
<div class="header">
header
</div>
<div class="content">
content
</div>
</div>
You need to think otherwise and set width and max-width on the container itself. your template becomes then : 1fr auto 1fr , wher both sides will grow as much as the middle column will allow them to.
Example below
.container {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-rows: min-content auto;
min-height: 100vh;
background-color: red;
}
.header {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
background-color: blue;
}
.content {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 3;
background-color: yellow;
width:80vw;/* where the parent container fills the whole screen's width */
max-width:64rem;
}
<div class="container">
<div class="header">
header
</div>
<div class="content">
content
</div>
</div>

Need assist with CSS grid layout of cards

I have this grid over here:
and i want the first big card to take the whole height of the wrapper and remain the same width, while the bottom two cards go to the right, somehow like this:
here's my css/html code where item-1 is the bigger card on the top-left:
.cards-wrapper {
background-color: #43cbff;
width: 1240px;
height: 380px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-gap: 20px;
#media (min-width: 30em) {
grid-template-columns: 1fr 1fr;
}
#media (min-width: 60em) {
grid-template-columns: repeat(4, 1fr);
}
}
.cards {
display: flex;
flex-direction: column;
min-height: 100%;
position: relative;
top: 0;
background-color: aquamarine;
border: 1px solid lightgrey;
border-radius: 8px;
}
.item-1 {
#media (min-width: 60em) {
grid-column: 1 / span 2;
h1 {
font-size: 24px;
}
}
}
You can keep the grid layout and use grid-template-areas to make that first item take up the full height whilst retaining its existing width.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-auto-columns: 1fr;
grid-auto-rows: 1fr;
gap: 8px 8px;
grid-auto-flow: row;
grid-template-areas:
"one one two three"
"one one four five";
}
.container * {
background: orange;
}
.one { grid-area: one; }
.two { grid-area: two; }
.three { grid-area: three; }
.four { grid-area: four; }
.five { grid-area: five; }
<div class="container">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>
</div>
Flex version
I dont know you entire structure and your requirement. But by using only flexbox you can archive this also quite easy.:
.cards-wrapper {
background: gray;
}
.flex {
display: flex;
gap:5px;
}
.left, .right {
width: 50%;
}
.right {
flex-wrap: wrap;
justify-content: center;
}
.right > div {
width: 49,2%;
background-color: lightgreen;
height:100px;
}
.big {
background-color: green;
width: 100%;
}
<div class="cards-wrapper flex">
<div class="left flex">
<div class="big">BIG</div>
</div>
<div class="right flex">
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
</div>

CSS media query not responding in GRID

index.html
This is the index file with a hero image and hero content(title and subtitle)
<section class= 'container main-section grid'>
<div class="hero-content">
<div class="title">
<h1>Hi, I'm Megha</h1>
</div>
<div class="subtitle">
<p>I’m a software engineer, where I like spending my day with programming and a bit of designing in general.</p>
</div>
</div>
<div class='image-wrapper'>
<div class='girl-image'></div>
</div>
styles.css
Code for overlapping hero content and hero image using CSS grid.
.grid {
display: grid;
grid-template-columns: 2fr 2fr 1fr 1fr;
grid-template-rows: 1fr 2fr;
margin-top: 80px;
gap: 20px;
}
.hero-content {
grid-column: 1 / span 2;
grid-row: 2 / span 2;
z-index: 1;
margin-top: -50px;
align-content: center;
max-width: 80vh;
}
.hero-content .title {
font-family: blackjack;
font-size: 24px;
color: #16161D;
}
.hero-content .subtitle {
font-family: futurapt;
font-size: 22px;
color: #363636
}
.image-wrapper {
grid-column: 2/span 3;
grid-row: 1/span 2;
}
index.css
Code for changing responsive layout with hero content on top and image on the bottom.
#media only screen and (max-width: 1249px) {
header, .hero-content, .social-icons, .image-wrapper {
margin: 0 20px;
}
}
#media only screen and (max-width: 535px) {
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 2fr 2fr 2fr;
}
.hero-content {
grid-column: 1;
grid-row: 1 / span 2;
}
.image-wrapper {
grid-column: 1;
grid-row: 3 / span 4;
}
}
The code does not work for responsive design for max-width 535px. I've been looking for a long while. Any help would be much appreciated.
Basically I want to change layout for mobile with a single column and 4 rows. This doesn't work. Why??
I've added a bit of CSS to your girl-image class so we could visualize where it currently lands in your grid. Your hero content DOES overlap your hero image at higher viewport widths. But on mobile, the hero image is under your hero content.
.girl-image {
background-color: cornflowerblue;
height: 100%;
width: 100%;
}
This is what your mobile layout looks like right now:
If you go above 535px, you get the image below:
.grid {
display: grid;
grid-template-columns: 2fr 2fr 1fr 1fr;
grid-template-rows: 1fr 2fr;
margin-top: 80px;
gap: 20px;
}
.hero-content {
grid-column: 1 / span 2;
grid-row: 2 / span 2;
z-index: 1;
margin-top: -50px;
align-content: center;
max-width: 80vh;
}
.hero-content .title {
font-family: blackjack;
font-size: 24px;
color: #16161d;
}
.hero-content .subtitle {
font-family: futurapt;
font-size: 22px;
color: #363636;
}
.image-wrapper {
grid-column: 2 / span 3;
grid-row: 1 / span 2;
}
.girl-image {
background-color: cornflowerblue;
height: 100%;
width: 100%;
}
#media only screen and (max-width: 1249px) {
header,
.hero-content,
.social-icons,
.image-wrapper {
margin: 0 20px;
}
}
#media only screen and (max-width: 535px) {
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 2fr 2fr 2fr;
}
.hero-content {
grid-column: 1;
grid-row: 1 / span 2;
}
.image-wrapper {
grid-column: 1;
grid-row: 3 / span 4;
}
}
<section class='container main-section grid'>
<div class="hero-content">
<div class="title">
<h1>Hi, I'm Megha</h1>
</div>
<div class="subtitle">
<p>I’m a software engineer, where I like spending my day with programming and a bit of designing in general.</p>
</div>
</div>
<div class='image-wrapper'>
<div class='girl-image'></div>
</div>
</section>

Flexbox/Float anchor items to top [duplicate]

This question already has answers here:
Create a Masonry grid with flexbox (or other CSS)
(3 answers)
Closed 5 years ago.
Consider this example:
Notice that that 4th item is pushed to top instead of aligning with the 3rd item. I can't achieve this using flexbox's align-items: flex-end, neither with floats.
I am aware of achieving this by using masonry/isotope, but I would like to avoid using javascript just for this layout.
Is it possible to achieve using only CSS?
Yes, it's possible via CSS Grid Layout:
.grid {
display: grid;
grid-gap: 10px 30px;
grid-template-rows: auto 1fr auto;
}
/* styles just for demo */
.grid__item {
background-color: #e0e0e0;
font-size: 30px;
padding: 10px;
}
.b, .d {
align-self: flex-start;
}
.a {
grid-row: 1 / span 2;
/* setting height just for demo */
height: 200px;
}
.b {
grid-column: 2;
}
.c {
grid-row: 3;
}
.d {
grid-column: 2;
}
<div class="grid">
<div class="grid__item a">1</div>
<div class="grid__item b">2</div>
<div class="grid__item c">3</div>
<div class="grid__item d">4</div>
</div>
If you need IE\Edge support you should use old grid syntax. You can fake grid-gap using additional grid columns and rows. Demo:
.grid {
display: -ms-grid;
display: grid;
-ms-grid-columns: 1fr 30px 1fr;
grid-template-columns: 1fr 30px 1fr;
-ms-grid-rows: auto 10px 1fr 10px auto;
grid-template-rows: auto 10px 1fr 10px auto;
}
/* styles just for demo */
.grid__item {
background-color: #e0e0e0;
font-size: 30px;
padding: 10px;
}
.b, .d {
-ms-grid-row-align: start;
align-self: flex-start;
}
.a {
-ms-grid-row-span: 3;
grid-row: 1 / span 3;
/* setting height just for demo */
height: 200px;
}
.b {
-ms-grid-column: 3;
grid-column: 3;
}
.c {
-ms-grid-row: 5;
grid-row: 5;
}
.d {
-ms-grid-column: 3;
grid-column: 3;
-ms-grid-row: 3;
grid-row: 3;
}
<div class="grid">
<div class="grid__item a">1</div>
<div class="grid__item b">2</div>
<div class="grid__item c">3</div>
<div class="grid__item d">4</div>
</div>

Does the order of elements define their place in a CSS grid?

The following code works as expected: the cells are filled with colors between defined lines
#grid {
display: grid;
height: 100px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 2/4;
}
#item3 {
background-color: blue;
grid-column: 4/7;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
I then tried to swap the last two elements (yellow and blue), by swapping the grid-column entries:
#grid {
display: grid;
height: 100px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 4/7;
}
#item3 {
background-color: blue;
grid-column: 2/4;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
item3 is not correctly displayed. I suppose that this is because item2 has been rendered further in the grid and the earlier element cannot be rendered anymore (wild guessing).
I am lost at how the order of the elements in the HTML is influenced by the placement of elements in the CSS, as explained in the documentation? Shouldn't the order in the HTML be insignificant?
The items are inserted one by one into the grid in the order of appearance in the html and according to their specified placement. The placement algorithm does not try to fill any previous gaps.
Note: By default, the auto-placement algorithm looks linearly through the grid without backtracking; if it has to skip some empty spaces to place a larger item, it will not return to fill those spaces. To change this behavior, specify the dense keyword in grid-auto-flow.
#grid {
display: grid;
height: 300px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 4/7;
}
#item3 {
background-color: blue;
grid-column: 2/4;
}
#item4 {
background-color: grey;
grid-column: 5/6;
}
#item5 {
background-color: orange;
grid-column: 1/7;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
<div id="item4"></div>
<div id="item5"></div>
</div>
In your example you could either make use of the grid-auto-flow property and set it to dense as suggested by the documentation:
#grid {
display: grid;
height: 100px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
grid-auto-flow: dense;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 4/7;
}
#item3 {
background-color: blue;
grid-column: 2/4;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
or you could make use of the order property to get the wished result:
#grid {
display: grid;
height: 100px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 4/7;
order: 3;
}
#item3 {
background-color: blue;
grid-column: 2/4;
order: 2;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
or, as suggested by GCyrillus, force the third item to be placed in the first row by using the grid-row property:
#grid {
display: grid;
height: 100px;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 100px;
}
#item1 {
background-color: lime;
}
#item2 {
background-color: yellow;
grid-column: 4/7;
}
#item3 {
background-color: blue;
grid-column: 2/4;
grid-row: 1;
}
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>