Why Percentage Value Within Grid-Gap Create Overflow in CSS Grid

Why percentage value within grid-gap create overflow in CSS grid?

Initially, we cannot resolve the percentage of the grid-gap since it depends on the height so we ignore it (we consider it as auto). The browser is first calculating the height considering content like this:

console.log(document.querySelector('.grid').offsetHeight)
.grid {  display: grid;  background-color: blue;}
.grid-1 { background-color: red; opacity:0.5;}
<div class="grid">  <div class="grid-1">    test  </div>  <div class="grid-1">    test  </div>  <div class="grid-1">    test  </div></div>

CSS Grid: Grid-gap causing items to overflow?

Update the code like below (related question to understand the first code adjustment: Why does minmax(0, 1fr) work for long elements while 1fr doesn't?)

* {
margin: 0;
}

.container {
display: flex;
justify-content: center;
background-color: firebrick;
}

.form {
display: flex;
flex-direction: column;
padding: 2rem;
margin: 2rem;
width: 25rem;
background-color: white;
}
.content {
border: 1px solid red;
display: grid;
grid-template-columns: repeat(2, minmax(0,1fr)); /* here */
grid-gap: 4rem;
}

/* here */
input {
max-width: 100%;
box-sizing: border-box;
}
<div class="container">
<form class="form">
<div class="content">
<div class="field">
<label for="title" class="label">Title</label>
<input type="text" placeholder="Job Title" id="title" class="input">
<i class="icon icon--success"></i>
<i class="icon icon--fail">
</i>
<small class="error-msg"></small>
</div>
<div class="field">
<label for="company" class="label">Company</label>
<select name="company" id="company" class="input">
<!-- options added in js -->
</select>
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="location" class="label">Location</label>
<select name="location" id="location" class="input">
<!-- options added in js -->
</select>
<i class="icon"></i>
<i class="icon"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="wage" class="label">Wage</label>
<input type="text" placeholder="Wage" id="wage" class="input">
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="type" class="new-job__label">Type</label>
<select name="type" id="type" class="input">
<!-- options added in js -->
</select>
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="position" class="label">Position</label>
<select name="position" id="position" class="input">
<!-- options added in js -->
</select>
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="pqe" class="label">PQE</label>
<select name="pqe" id="pqe" class="input">
<!-- options added in js -->
</select>
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>

<div class="field">
<label for="featured" class="label">Featured</label>
<select name="featured" id="featured" class="input">
<!-- options added in js -->
</select>
<i class="icon icon--success"></i>
<i class="icon icon--fail"></i>
<small class="error-msg"></small>
</div>
</div>
<button class="new-job__submit">Submit</button>

</form>
</div>

Percentages in minmax CSS grid causing overflow

Setting the max-width to a percentage negates the auto-fit declaration in a sense. While fr deals with free space, percentages are an actual width in the browser's eyes. So when you set the max to 30%, the browser will honor that without wrapping, because it can always split whatever width it has into chunks of 30%. This of course, is down to your 200px minimum that you set.

Since you don't want to use fr in your desktop rendering, I would recommend inserting a media query at the breakpoint which your content begins to not work, and reduce to one column that takes up all the free space. Example:

@media only screen and (max-width: 640px) {
.wrapper-percent {
grid-template-columns: 1fr;
}
}

Why does grid-gap cause an overflow without percent?

This is because a Grid item(i.e. .container) cannot be smaller than it's contents(all .item combined). Let's consider your case here.

container width = 500px

grid-template-columns is repeating 16 times with gap of 35px each. If we do the math here that would be 560px(16*35) which will be greater than your container width(500px).

To fix this either you increase the container width to 560px or make in percentages i.e. 100%

.container {
width: 100%; /*560px*/
border: 1px solid #000;
margin: 0 auto;
}
.box {
display: grid;
grid-template-columns: repeat(16, 1fr);
background: #00f;
gap: 35px;
}
.item {
height: 50px;
background: #0f0;
text-align: center;
line-height: 40px;
vertical-align: middle;
}
.span4 {
grid-column: span 4;
}
<div class="container">
<div class="box">
<div class="item span4">A</div>
<div class="item span4">B</div>
<div class="item span4">C</div>
<div class="item span4">D</div>
<div>
</div>

Why does grid-gap cause an overflow?

Short Answer

Because the width of the columns plus the width of the gaps is greater than 100%.



Explanation

You have a 3-column grid container (.body):

grid-template-columns: 25% 50% 25%

The total width of those columns is 100%.

You're then adding gutters between the columns (and rows):

grid-gap: 10px

which is shorthand for:

grid-column-gap: 10px;
grid-row-gap: 10px;

So this becomes the width calculation:

25% + 50% + 25% + 10px + 10px

Hence,

100% + 20px > 100%, which results in an overflow condition

Note that the grid-*-gap properties apply only between grid items – never between items and the container. That's why we calculate two grid gaps, not four.

As a solution, instead of percentage units, try using fr units, which apply only to free space. This means that fr lengths are calculated after any grid-gap lengths are applied.

grid-template-columns: 1fr 2fr 1fr

div:not(.header):not(.body):not(.row) {
border: 1px solid grey;
}

.header {
margin-top: 20px;
display: grid;
grid-gap: 10px;
grid-template-areas: "header-left header-right-up" "header-left header-right-down";
grid-template-rows: 40px 40px;
grid-template-columns: minmax(50px, 200px) auto;
}

.header-left {
grid-area: header-left;
}

.header-right-up {
grid-area: header-right-up;
}

.header-right-down {
grid-area: header-right-down;
}

.body {
margin-top: 20px;
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* ADJUSTMENT */
grid-auto-rows: 80px;
grid-gap: 10px;
}

.row-left {}

.row-center {}

.row-right {}
<div class="header">
<div class="header-left">image</div>
<div class="header-right-up">content</div>
<div class="header-right-down">long content</div>
</div>

<div class="body">
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>

<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>

<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
</div>

Variable grid-gap makes padding of grid-parent invade grid-elements

Here's my guess, based on my knowledge of the cascade, percentage lengths and the grid sizing algorithm. I haven't found anything official that specifically addresses this issue so, again, this is an extrapolation.

For a percentage height to work, when there is no explicit height defined on the parent container, the browser first needs to render all other lengths. This way it arrives at the actual size of the container and can answer the question: "10% of what?".

Hence, the browser first renders the items and the padding-bottom: 100px.

Now it can calculate grid-gap: 10% or, more specifically, the row-gap: 10% component (a percentage height).

Because all other sizes are already in place, this additional 10% height forces the lower item to intrude into the fixed padding space.

In support of this theory, if we set a height on the container, which now provides a clear reference point for the percentage row height, the rule can be rendered in sequence with the others (i.e., there's no need for the percentage height to be rendered at the end), and the overlap is eliminated in most cases. (There will still be an overlap in shorter screens because the padding has a fixed height of 100px.)

* {  box-sizing: border-box;  margin: 0;  padding: 0;}
#grid { padding-bottom: 100px; display: grid; grid-gap: 10%; grid-template-columns: 100px; height: 100vh; /* new */}
.grid-item img { width: 100%;}
<div id="grid">  <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">    <h3>Stack Overflow</h3>  </div>  <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">    <h3>Stack Overflow</h3>  </div></div>

How to use a CSS grid with percentages and an unknown amount of columns?

Since you don't know the number of columns, you don't use the grid-template-columns property. This property defines an explicit grid, meaning the tracks are explicitly defined.

You may be looking for grid-auto-columns. This property defines the width of columns that are automatically created (this would be the implicit grid).

Try this:

grid-auto-columns: 1fr

With the fr unit, only the free space is distributed. This would be the space left after the gutters are factored in.

7.2.3. Flexible Lengths: the fr unit

A flexible length or <flex> is a dimension with the fr unit, which represents a fraction of the free space in the grid container.

free space

Equal to the available grid space minus the sum of the base sizes of
all the grid tracks (including gutters), floored at zero. If available
grid space is indefinite, the free space is indefinite as well.

Also – when you do have a defined number of columns – since we're dealing with proportions, you could match the fr values to your desired percentages. Something like this:

grid-template-columns: 42fr 33fr 25fr (instead of 42% 33% 25%).

One advantage of using fr here is that the gutter size is automatically deducted (to establish the free space, which is the only space fr uses). With percentages, you need to use calc().

CSS Grid is larger than it's container div in height

This is being caused by the grid-gap. You're using grid-gap: 2%; which applies a % gap between both columns and rows. This works perfectly for the grid itself as we can see, and the grid is including the 2% gap between rows in it's total height.

However using percentages for height is problematic when the container doesn't have a defined height. What's happening here is that the container isn't recognising the % gap height and is not including it in it's total height.

You can easily fix it by using a defined value for height, e.g.

grid-column-gap: 2%;    // you can still use % for the column gap
grid-row-gap: 20px; // fixed height for row gap

Working Example:

.column {
margin-top: 3%;
margin-left: 20%;
margin-right: 20%;
background-color: rgba(200, 0, 0, 0.1);
}

.grid {
display: grid;
grid-template-columns: repeat( auto-fit, minmax(300px, 1fr));
grid-auto-rows: (0px, 1fr);
grid-column-gap: 2%;
grid-row-gap: 20px;
}

.plum {
/* background-color: plum; */
}

.card {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
border-radius: 10px;
background-color: rgba(0, 0, 0, 0.1);
}

.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}

.container {
padding: 2px 16px;
}

.container p {
word-wrap: break-word;
}

.centered {
text-align: center;
}
<body class="plum">
<br>
<div class="column">
<div class=" grid">
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I like memes</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I like memes again</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: this is a post</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: This is the first post from the website</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I have added this</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: I'm joe</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: Okay</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: I like memes too</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: Caps test</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: OKAYYYYYYYYYYYYYYYYYYYYYYYY</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: sssssssssssssssssss</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: SSSSSSSSSSSSSSSSSS</p>
</div>
</div>
</div>
</div>
<p class="centered"><a href="submitform.php">Add new</a></p>


Related Topics



Leave a reply



Submit