I have grid with 3 elements like this:
Now I want to replace blue elements with images (could be just dummy images).**
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: minmax(30em, auto);
justify-items: stretch;
align-items: stretch;
}
.grid-item-1 {
background: url("https://editzstock.com/wp-content/uploads/2022/04/broken-text-300x300.png");
background-size: cover;
overflow: hidden;
}
.grid-item-2 {}
.grid-item-3 {
grid-column: span 2;
grid-row: span 1;
}
.grid-item {
position: relative;
font-size: 25px;
padding: 20px;
padding-top: 50px;
background-color: #379AD6;
color: #222;
border: 1px solid white;
}
<div class="grid-container">
<div class="grid-item grid-item-1">
</div>
<div class="grid-item grid-item-2">
</div>
<div class="grid-item grid-item-3"></div>
</div>
Speaking just from experience over the past 7 years, images as grid / flex items often glitch in one way or another.
The glitch is almost always resolved by nesting the image in a container, making the container the grid / flex item.
Although images are valid as grid / flex items, until the various browsers make some more progress on this issue, I would suggest you use a container (thus keeping the images in a block formatting context).
Related
can someone please tell me why the 3rd div is looking that way instead of being right under the 1st div? And what would I need to write in my CSS file to make the 3rd div positioned right under the 1st one?
This is the HTML:
<div class="div-main">
<div class="div-1">
1
</div>
<div class="div-2">
2
</div>
<div class="div-3">
3
</div>
</div>
This is the CSS:
.div-main {
border: 5px solid yellow;
padding: 15px;
}
.div-1 {
border: 1px solid black;
padding: 15px;
width: 30%;
height: 30vh;
display: inline-block;
}
.div-2 {
border: 1px solid black;
padding: 15px;
width: 69%;
height: 50vh;
display: inline-block;
}
.div-3 {
border: 1px solid black;
padding: 15px;
width: 30%;
height: 30vh;
display: inline-block;
}
Why this is happening?
By default, the block elements, whether they are block or inline-block, will fill all the available space in the row, so if the blocks should have an overlapping situation, you can't achieve it with block approaches.
How to solve it?
With the CSS grid approach, you can make sure how each element should be positioned in your box. You can specify how your columns should be distributed by using the grid-template-columns, and how your rows should do it, with the grid-auto-rows property. You can also ensure how much of your current available space should be filled with the children by using grid-column and grid-row on each child.
The grid approach:
.div-main {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
.div-1, .div-2, .div-3 {
border: 1px solid black;
}
.div-1 {
grid-column: 1 / 2;
grid-row: 1;
}
.div-2 {
grid-column: 2 / 4;
grid-row: 1 / 3;
}
.div-3 {
grid-column: 1;
grid-row: 2 / 3;
}
<div class="div-main">
<div class="div-1">1</div>
<div class="div-2">2</div>
<div class="div-3">3</div>
</div>
How the above code works?
In this example by default,
I distributed the available space for the column into 3 even blocks (grid-template-columns: repeat(3, 1fr)).
I set the minimum of each row to be 100px and allow them to grow if other blocks in the container want them to (grid-auto-rows: minmax(100px, auto)).
At last, I set the children to fill the available space the way I wanted (grid-column: *; grid-row: *;).
NOTE1: If in any case you want to make the third child gets bigger in height in comparison to the second child you can change the second part of grid-row: 2 / 3; to a bigger number like grid-row: 2 / 4;.
.div-main {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
.div-1, .div-2, .div-3 {
border: 1px solid black;
}
.div-1 {
grid-column: 1 / 2;
grid-row: 1;
}
.div-2 {
grid-column: 2 / 4;
grid-row: 1 / 3;
}
.div-3 {
grid-column: 1;
grid-row: 2 / 4;
}
<div class="div-main">
<div class="div-1">1</div>
<div class="div-2">2</div>
<div class="div-3">3</div>
</div>
NOTE2: You can learn more about how CSS grid works in the CSS-tricks website with more examples.
Here I don't directly say why; I think others have done a great job there. Here I show how you can place items in columns in a container, and then forced some sizing to show the effect of doing that within individual blocks - and why sizing to the containing element might be more desirable at times.
I added a left/right block to illustrate the effect of creating logical groups of elements to work with by simply wrapping them in a group-left and group-right thus if you change grid-template-columns: minmax(150px, 30%) 30%; to grid-template-columns: minmax(150px, 30%) 1fr; the right group takes up whatever is remaining - a typical left/right layout where you have say links in the left group for example.
The only difference between the to major containers here is the content of each and those styles added to those contained elements.
.parent {
display: grid;
grid-template-columns: minmax(150px, 30%) 30%;
}
.group-left {
border: solid purple 3px;
background-color: #77008822;
}
.group-left>* {
margin: 1rem;
}
.group-right {
border: solid orange 3px;
}
.content-block {
/* just here to center the text in both directions */
display: grid;
place-items: center;
border: 1px solid;
}
/* below here is now just color and border styling and some forced sizing */
.div-main {
border: 5px solid yellow;
/* padding: 15px;*/
}
.div-1 {
border: 1px solid black;
/* force a height */
height: 30vh;
}
.div-2 {
border: 1px solid black;
/* force a height */
height: 50vh;
background-color: #eeffdd;
/* this can make the second block wider and potentially overlap the next column */
width: 20em;
}
.div-3 {
border: 1px solid black;
/* force a height */
height: 30vh;
}
.forced-height {
height: 30vh;
background-color: #44ddff33;
}
.img-force {
border: dashed 2px cyan;
width: 50%;
height: 30vh;
}
<div class="parent div-main">
<div class="group-left">
<div class="content-block div-1">1 is a happy one
</div>
<div class="content-block div-2">
2 here
</div>
</div>
<div class="group-right">
<div class="content-block div-3">
3 is not sad
</div>
</div>
</div>
<div class="parent">
<div class="group-left">
<div class="content-block">1 is a happy one
</div>
<div class="content-block forced-height">
2 here
</div>
</div>
<div class="group-right">
<div class="content-block">
<img class="img-force" src="" alt="no soup for you"> 3 is not sad
</div>
</div>
</div>
Inline elements can't position themselves like what you want as they're block level elements. You can use CSS grid and set div-2 to span two rows. There's a lot to grid but it's really flexible. Have a look. I've annotated the CSS so you can see how I've done it.
Some good resources on CSS tricks and here's a video by Kevin Powell that's a handy introduction.
.div-main {
border: 5px solid yellow;
padding: 15px;
/* this makes a grid layout with 2 columns and as many rows as needed. */
/* There's only 3 divs so that'll automatically give us 2 rows */
/* The grid-template-columns property is the width of each column - though there are some qualifications with this */
display: grid;
grid-template-columns: 30% 69%;
}
.div-main>div {
/* I've moved this to its own rule so you don't need to repeat yourself */
border: 1px solid black;
padding: 15px;
}
.div-1 {
/* I've kept the height of your original divs */
height: 30vh;
}
.div-2 {
height: 50vh;
/* setting grid-row: span 2 makes this div use two rows when it's being displayed */
/* this allows the third div to appear to the left */
/* in effect there's 4 cells in this grid but the last, bottom right cell is taken up by div-2 as we've told it to span 2 rows */
grid-row: span 2;
}
.div-3 {
height: 30vh;
}
<div class="div-main">
<div class="div-1">
1
</div>
<div class="div-2">
2
</div>
<div class="div-3">
3
</div>
</div>
I am trying to understand how CSS grids work. I've tried to make an example of a store item as practice, but I am at a loss.
Here's my how my CSS currently looks. Cut off at the top, weird spacing, and the right side is not coming together at all.
How's how it would ideally look
Here is my current CSS, I hope someone can help explain where I am misunderstanding the use of
CSS grids.
.store-currency {
height: 3vh;
}
.item {
display: flex;
align-items: center;
grid-row: 1 / span 2;
}
.currency {
display: flex;
align-items: center;
}
#num-bought-item0 {
display: flex;
align-items: center;
justify-content: right;
margin-right: 10px;
grid-column: 1 / span 2;
}
.store-item {
height: 15vh;
width: 100%;
display: grid;
grid-template-columns: 2fr;
grid-template-rows: 1fr 1fr;
font-size: 24px;
color: white;
border: 5px white solid;
justify-content: left;
align-items: center;
}
.store-item img {
margin: 10px;
height: 8vh;
}
.store-container {
display: flex;
height: 100%;
width: 30vw;
z-index: 0;
background-color: saddlebrown;
left: 0;
position: absolute;
text-align: center;
}
HTML:
<div class="store-container">
<div class="store-item" id="item0">
<div class ="item">
<img src="dumbell.png" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item0">
<span>Owned</span>
<span id="count-item0">0</span>
</div>
<div class="currency">
<img class="store-currency" src="coin.png" alt="">
<span>100000</span>
</div>
</div>
you did the first steps.
To get started you have to define a container element as a grid with display: grid, set the column and row sizes with grid-template-columns and grid-template-rows, and then place its child elements into the grid with grid-column and grid-row.
.store-container {
display: grid | inline-grid;
}
grid – generates a block-level grid
inline-grid – generates an inline-level grid
With grid-template-columns you can define how many columns will appear in your layout.
P.S Fr unit is a fractional unit and 1fr is for 1 part of the available space. In this example each column would take ~ 25% from the available space.
.container {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
For your task, you can use grid-template-areas feature.
The grid-template-areas CSS property specifies named grid areas,
establishing the cells in the grid and assigning them names.
For example:
.item-a {
grid-area: header;
}
.item-b {
grid-area: main;
}
.item-c {
grid-area: sidebar;
}
.item-d {
grid-area: footer;
}
.container {
display: grid;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main . sidebar"
"footer footer footer footer";
}
This will generates something like that in modern browsers:
If you need more examples, take a look here:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas
https://css-tricks.com/snippets/css/complete-guide-grid/
Some of the examples are taken from the second site.
It looks like you are mixing flex and grid properties. grid-row and grid-column are only avalaible for a grid display (2D), not a flex display (1D).
You can try to play around with flex (worse choice since it is drawing a 1D layout) , you can use grid , which is made for this kind of layout.
Here a couple example with flex and grid
/* GRID make it simple*/
.grid {display:grid;}
#num-bought-item2 {grid-row:1/3;grid-column:2;}
#num-bought-item2 {display:grid;margin:auto;text-align:center}
/* layout done */
/* some reset for the demo*/
*{box-sizing:border-box;}
.store-container {display:grid;justify-content:center;}
.store-item {border:solid;}
.store-item>div {padding:0.5em;}
img{vertical-align:middle;}
[src="https://dummyimage.com/25/ff0"]{border-radius:50%}
big{color:darkgreen;background:lightyellow;}
/* FLEX make it a mess */
.flex {display:flex}
.column {flex-flow:column wrap;height:120px;}/* here an height is to be set so it wraps*/
/* since it is not made for this, we need to mess around */
.flex #num-bought-item1{order:2}/* reorder item */
.flex .item {height:0;min-height:60%;}/* hide it, then show it */
.flex .currency {height:0;min-height:40%;}/* hide it, then show it */
.flex #num-bought-item1{display:flex;flex-direction:column;justify-content:center;text-align:center;margin:auto;}
/* and flex did not do it */
<p>Let's try via flex</p>
<div class="store-container">
<div class="store-item flex column" id="item1">
<div class="item">
<img src="https://dummyimage.com/50" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item1" >
<span>Owned</span>
<span id="count-item1">0</span>
</div>
<div class="currency">
<img class="store-currency" src="https://dummyimage.com/25/ff0" alt="">
<span>100000</span>
</div>
</div>
</div>
<p>And via <big>grid</big> </p>
<div class="store-container">
<div class="store-item grid" id="item2">
<div class="item">
<img src="https://dummyimage.com/50" alt="">
<span>Dumbbell</span>
</div>
<div id="num-bought-item2" >
<span>Owned</span>
<span id="count-item1">0</span>
</div>
<div class="currency">
<img class="store-currency" src="https://dummyimage.com/25/ff0" alt="">
<span>100000</span>
</div>
</div>
</div>
I have a container grid to center the child inline-grid element. However, I'm unable to have auto-fill/auto-fit to take as many columns as there can fit. The grid items have a specified width/height.
It is possible to have the inline-grid take as many columns if specified directly, but that is not what I want.
If it's possible doing this with flex it would be okay, even though I prefer using grid.
I want the grid to be CSS ONLY. Do NOT post answers using JavaScript.
body, html {
margin: 0;
height: 100%;
}
.container {
display: grid;
background: red;
height: 100%;
}
.grid {
background: green;
height: 100%;
display: inline-grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 100px));
margin: auto;
}
.item {
background: blue;
}
<div class="container">
<div class="grid">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
</div>
</div>
Automatic centering of grid items is not a simple matter because of the column tracks in the container. They restrict movement across the row. The problem is explained in full here:
Aligning grid items across the entire row/column (like flex items can)
Areas covered by Flexbox which are difficult or impossible to achieve with Grid
However, the layout may be possible with flex:
.grid {
display: flex;
background: green;
justify-content: center;
height: 100vh;
}
.item {
flex: 0 0 100px;
background: blue;
}
.item + .item {
margin-left: 5px;
}
body {
margin: 0;
}
<div class="grid">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
</div>
If I have a 3 column grid and I want the content to appear in the 2 column: am I understanding correctly that the content HAS to go in the 2nd column in the HTML, and I have to create an empty div in the HTML?
In the grid below I want the title to appear in the middle column so I've created an empty div before this.
There's no way of getting the title to appear in the middle one of the 3 columns whilst only using one div is there?
** Note I haven't included a div for the 3rd column because I don't need to.
Codepen: https://codepen.io/emilychews/pen/rEoKPg
Code snippet also included below.
body {
margin: 0;
padding: 0;
display: flex;
height: 100vh;
width: 100%;
justify-content: center;
align-items: center;
}
.row {
width: 50%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
.grid {
background: #f1f1f1;
padding: 1rem;
}
<div class="row">
<div class="grid grid-item-1"></div>
<div class="grid grid-item-2">The Title</div>
</div>
You don't have to create an empty div if you use grid-column-start, but you will need to specify the column number.
<div class="row">
<div class="grid grid-item-2">The Title</div>
</div>
body {
margin: 0;
padding: 0;
display: flex;
height: 100vh;
width: 100%;
justify-content: center;
align-items: center;
}
.row {
width: 50%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
.grid {
background: #f1f1f1;
padding: 1rem;
}
.grid-item-2 {
grid-column-start: 2;
}
Yes, you can. Remove the first div then add this to your css code:
.grid-item-2 {
grid-column-start: 2;
}
Check this article on CSS Tricks with a quick cheatsheet on CSS Grids: A Complete Guide to Grid | CSS Tricks
The MDN reference is very good also: CSS Grid Layout | MDN
I have a card built with CSS Grid layout. There might be an image to the left, some text to the right top and maybe a button or a link at the right bottom.
In the code below, how can I make the green area take up as much space as possible and at the same time make the blue area take up as little space as possible?
The green should push the blue area down as far as possible.
https://jsfiddle.net/9nxpvs5m/
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Adding grid-template-rows: 1fr min-content; to your .grid will get you exactly what you're after :).
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: 1fr min-content;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Jens edits: For better browser support this can be used instead: grid-template-rows: 1fr auto;, at least in this exact case.
A grid is a series of intersecting rows and columns.
You want the two items in the second column to automatically adjust their row height based on their content height.
That's not how a grid works. Such changes to the row height in the second column would also affect the first column.
If you must use CSS Grid, then what I would do is give the container, let's say, 12 rows, then have items span rows as necessary.
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: repeat(12, 15px);
}
.one {
grid-row: 1 / -1;
background: red;
}
.two {
grid-row: span 10;
background: lightgreen;
}
.three {
grid-row: span 2;
background: aqua;
}
.grid > div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
Otherwise, you can try a flexbox solution.
.grid {
display: flex;
flex-flow: column wrap;
height: 200px;
}
.one {
flex: 0 0 100%;
width: 30%;
background: red;
}
.two {
flex: 1 0 1px;
width: 70%;
background: lightgreen;
}
.three {
background: aqua;
}
.grid>div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
When using grid, and you have grid template area used, and by chance you gave a particular area a width, you are left with a space grid does automatically.
In this situation, let grid-template-columns be either min-content or max-content, so that it adjusts its position automatically.
A possible approach might be grouping two and three together, and using flexbox:
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: "one two"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.wrap {
grid-area: two;
display: flex;
flex-direction: column;
}
.two {
background: green;
flex: 1;
}
.three {
background: blue;
}
<div class="grid">
<div class="one">
One
</div>
<div class="wrap">
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
</div>
Definitely not the most elegant solution and probably not best practice, but you could always add more lines of
"one two"
before the part where you have
"one three"
so it ends up looking like
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one two"
"one two"
"one three"
}
Again, pretty sure this is just a work around and there's better solutions out there... But this does work, to be fair.
Just use width: 100% and height: 100% in the CSS class of the item you want to fill the grid. Join a max-width property and a max-height property if you don't want a grid item inside a grid container to grow more than some size.