CSS Grid: column-gap forces parent to overflow - html

I want to achieve 12 column grid behavior similar to what Bootstrap has,
but using CSS grids.
I need to have a fixed gapsĀ in pixels
And have a 12 column grid, so I can decide how to place the children.
I'm facing the issue, that combination of grid-template-columns and column-gap doesn't shrink the columns on a smaller screens, but cause horizontal overflow on a screen.
How can I achieve expected behavior with shrinking without reducing the number of columns and keeping the gap in pixels.
DEMO:
.parent {
max-width: 300px;
height: 500px;
overflow: auto;
border: 1px solid blue;
}
.box {
grid-column: span 6 / span 6;
background: red;
height: 40px;
}
.grid {
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
gap: 40px;
}
<div class="parent">
<div class="grid">
<div class="box"></div>
<div class="box"></div>
</div>
</div>

Related

CSS Grid - Stretch dynamic number of colums to fit row width

Is it possible to use CSS grid to auto-fit the columns in a row to always take up the whole width?
I know this would be possible if you knew the number of columns, but is it possible with a dynamic number of columns?
Image for reference of what I'd like to achieve.
column example image
This is what I have so far, but you can see that the lower row item doesn't take up all the row width.
.wrapper {
display: grid;
grid-template-columns: 200px 200px;
column-gap: 20px;
}
.grid {
border: solid #FF8181 1px;
display: grid;
grid-template-rows: 40px repeat(8, minmax(0, 1fr));
width: 200px;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}
.row-item {
background: #FFC555;
border: 1px solid #835600;
width: 100%;
height: 40px;
}
.item-1, .item-1 {
grid-row: 2 / span 1;
}
.item-2 {
grid-row: 6 / span 1;
font-size: 12px;
}
<div class='wrapper'>
<div class='grid'>
<div class='row-item item-1'></div>
<div class='row-item item-1'></div>
<div class='row-item item-2'>I'm too short</div>
</div>
<div class='grid'>
<div class='row-item item-1'></div>
<div class='row-item item-1'></div>
<div class='row-item item-1'></div>
<div class='row-item item-2'>Should be the whole width</div>
</div>
</div>
you can stretch a element in a grid over the whole width by using:
grid-column: 1 / all;
or
grid-column: 1 / -1;
unfortunately does it affect the other elements in the same grid.
A solution like "span last-column" doesnt exist yet, but is already discussed: https://github.com/w3c/csswg-drafts/issues/2402
Maybe they will implement the function soon. Good luck anyways
What I need doesn't exist yet. This does indeed look like the latest update:
A solution like "span last-column" doesnt exist yet, but is already
discussed: https://github.com/w3c/csswg-drafts/issues/2402
I calculated overlapping grid items and rendered items in subgrids based on this answer:
Group multiple overlapping timeblocks that may not have a direct overlap
With js its different.
Find the grid
Get the Style of the Grid
Filter the Style of the Grid for grid-template-columns
Set the Element grid-column to the number of columns
Your code will look like this:
window.addEventListener("DOMContentLoaded", function(){
// find the elemen by the class and safe it as grid
let grid = document.querySelector(".grid")
// sage the style of the element
const gridComputedStyle = window.getComputedStyle(grid);
// get the grid-template-columns style poperty of the element and format them to a useful value
const gridColumnCount = gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length
// log for debug
console.log(gridColumnCount)
// set the column style of the element to the span of the variable
document.getElementById("item-2").style.gridColumn = "1 / span " + gridColumnCount;
// set the row style because it got overwritten by the line above
document.getElementById("item-2").style.gridRow = "6 / span " + gridColumnCount;
})
note that i have changed your html and css too:
html:
<div class='grid'>
<div class='row-item item-1'></div>
<div class='row-item item-1'></div>
<div class='row-item item-1'></div>
<div class="row-item" id="item-2">whole width</div>
</div>
Just deleted the wrapper for a better overview
CSS:
.grid {
border: solid #FF8181 1px;
display: grid;
grid-template-rows: repeat(8, minmax(0, 1fr));
width: 300px;
grid-template-columns: repeat(auto, minmax(0, 1fr));
}
.row-item {
background: #FFC555;
border: 1px solid #835600;
width: 100%;
height: 40px;
}
.item-1, .item-1 {
grid-row: 2;
}
.item-2 {
grid-row: 5;
font-size: 12px;
}
I had to change the grid-template-value of grid from auto-fit to auto. Otherwise there would be a bug when counting the columns

Can I set an image as a grid item?

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).

Grow parent to width of the child [duplicate]

This question already has answers here:
Why does the outer <div> here not completely surround the inner <div>?
(2 answers)
Closed 2 years ago.
I have a child element inside of a parent element. The child has a min-width set, which makes it (at some screen sizes) wider than the parent element. The child's width correctly is set to the min-width, but the parent's width seems to max out at the original screen width. I would like the parent to grow with the child. How can I achieve this?
.container {
display: block;
background-color: blue;
width: auto;
}
.grid {
min-width: 1000px;
display: grid;
padding: 10px;
grid-gap: 10px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, auto);
margin-left: auto;
margin-right: auto;
align-items: start;
}
.grid > div {
background-color: yellow;
}
<div class="container">
<div class="grid">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
</div>
</div>
In the example, 'container' (blue background) is narrower than the child 'grid' (the grid of yellow boxes). If you scroll right, you can see that the blue background stops at the edge of the screen, while the yellow grid continues. I would like the blue area to grow to contain the child grid.
I have tried setting width and min-width properties on the container to auto and/or 100%. I've also tried changing the display to inner-block. None of these work.
Using width: fit-content on the .container element would allow it to expand outside of the window bounds when necessary.
.container {
display: block;
background-color: blue;
width: fit-content;
}
.grid {
min-width: 1000px;
display: grid;
padding: 10px;
grid-gap: 10px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, auto);
margin-left: auto;
margin-right: auto;
align-items: start;
}
.grid > div {
background-color: yellow;
}
<div class="container">
<div class="grid">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
</div>
</div>

Expanding to fill remaining space in a CSS Grid layout

I want to use CSS grid and the following is a mock-up of the aim:
I'm building an interface that should expand rightward to fill the browser screen; my current code causes column 2 of the outer grid to be as wide as the browser in addition to column 1; or maybe one of it's children is causing this and it's just expanding to accommodate. Either way, it's spilling off the page horizontally
So the code:
#main {
width: 100%;
display: grid;
grid-template-columns: 250px 100%;
grid-template-rows: 100px 100%;
}
#col-2-outer {
display: grid;
grid-template-columns: 250px auto;
grid-template-rows: 100%;
}
#row-1-inner {
grid-column: span 2;
}
#col-2-inner table {
width: 100%;
}
<div id="main">
<div id="col-1-outer"></div>
<div id="col-2-outer">
<div id="row-1-inner"></div>
<div id="row-2-inner">
<div id="col-1-inner"></div>
<div id="col-2-inner">
<table></table>
</div>
</div>
</div>
</div>
FYI, for the time being I've forgone template areas until I get a handle on the basics (unless this somehow solves my problem but I gather this is strictly a code organization feature?).
I'd suggest to change your markup with a 3x2 grid like below:
Remove the hierarchical structure like you have in your code and add one element for each section in the grid.
Note that in the rule grid-template-columns: 250px 150px auto, 250px is the width of your col-1-outer and 150px is the width of the col-1-inner.
Span the first column over the two rows by using grid-row: span 2
Span the first row in the second column by using grid-column: span 2.
Extend the table over the last grid item by using 100% width and height.
See demo below:
* {
border: 1px solid; /* For illustration */
}
#main {
width: 100%;
display: grid;
grid-template-columns: 250px 150px auto;
grid-template-rows: 100px auto;
}
#col-1-outer {
grid-row: span 2;
}
#row-1-inner {
grid-column: span 2;
}
#col-2-inner table {
width: 100%;
height: 100%;
}
<div id="main">
<div id="col-1-outer">col-1-outer</div>
<div id="row-1-inner">col2-row-1-inner</div>
<div id="col-1-inner">col2-row2-inner</div>
<div id="col-2-inner">
<table><tr><td>table</td></tr></table>
</div>
</div>
The 100% for the 2nd column in your grid-template-columns is based on the width of the container - rather than occupying the space outstanding within the container, it will push out to the right because the 2nd column is trying to match the width of the container.
Try changing this to auto and this should rectify the issue, as it will only take up the space up to the end of the container and no further.
Source: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns

Why does grid-gap not work on mobile?

I've been playing around with CSS Grid recently and have noticed something that I can't see to find the answer to. Let's say I split my page out to have 2 columns, and then a row below it, with another column (which spans both columns). On mobile, I'd like them to stack one on top of the other and then go back to layout described above after a certain breakpoint. Here is the markup:
HTML
<div class="grid">
<div class="upper">
<div class="a">A</div>
<div class="b">B</div>
</div>
<div class="lower">
<div class="c">C</div>
</div>
</div>
SCSS
.upper, .lower {
display: grid;
}
.upper {
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
background-color:grey;
grid-gap:10px;
#media only screen and (max-width:800px) {
grid-template-columns: 1fr;
grid-template-rows: auto;
}
}
.lower {
grid-template-columns: 1fr;
grid-template-rows:auto;
background-color: green;
grid-gap:10px;
}
I've noticed that on mobile, even though I've defined grid-gap for both of my grid sections, on mobile when the columns stack, the grid-gap is not maintained. So in the fiddle below, when you make the window smaller, you can see that when the columns, stack one on top of the other, the gap between B and C is non existent. Here is the fiddle:
Fiddle
Hope I'm making sense!
EDIT: Bear in mind I'm only testing this in Firefox and Chrome (which support grid).
The grid-gap rule doesn't work between B and C because it doesn't apply.
This rule creates gutters between rows and columns inside a grid container.
But you are declaring grid-gap on .upper and .lower, two siblings in a block container. Their parent (.grid) is not a grid container because it doesn't have display: grid or inline-grid.
Therefore, grid-gap: 10px on .upper is creating a 10px gutter between A and B...
and grid-gap: 10px on .lower is creating a 10px gutter between.... nothing (.lower has only one grid item. grid-gap creates gutters between multiple grid items).
fiddle demo 1
For grid-gap to work among the .upper and .lower siblings you need to apply it to their parent, which must be a grid container.
fiddle demo 2
.grid {
display: grid; /* NEW */
grid-gap: 25px; /* NEW */
}
.upper, .lower {
display: grid;
}
.upper {
grid-template-columns: 1fr 1fr;
grid-gap: 25px;
}
.lower {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-gap: 10px; /* does nothing unless there are multiple grid items */
}
#media ( max-width:800px ) {
.upper {
grid-template-columns: 1fr;
grid-template-rows: auto;
}
}
.upper > * { border: 1px dashed red; }
.lower > * { border: 1px dashed blue; }
<div class="grid">
<div class="upper">
<div class="a">A</div>
<div class="b">B</div>
</div>
<div class="lower">
<div class="c">C</div>
</div>
</div>