Prevent Content from Expanding Grid Items

Prevent content from expanding grid items

By default, a grid item cannot be smaller than the size of its content.

Grid items have an initial size of min-width: auto and min-height: auto.

You can override this behavior by setting grid items to min-width: 0, min-height: 0 or overflow with any value other than visible.

From the spec:

6.6. Automatic Minimum Size of Grid
Items

To provide a more reasonable default minimum size for grid items, this
specification defines that the auto value of min-width / min-height also applies an automatic minimum size in the specified axis to grid items whose overflow is visible. (The effect is analogous to the automatic minimum size imposed on flex items.)

Here's a more detailed explanation covering flex items, but it applies to grid items, as well:

  • Why don't flex items shrink past content size?

This post also covers potential problems with nested containers and known rendering differences among major browsers.


To fix your layout, make these adjustments to your code:

.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
background: #fff;
grid-gap: 2px;
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}

.day-item {
padding: 10px;
background: #DFE7E7;
overflow: hidden; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}

jsFiddle demo



1fr vs minmax(0, 1fr)

The solution above operates at the grid item level. For a container level solution, see this post:

  • Who does minmax(0, 1fr) work for long elements while 1fr doesn't?

Prevent grid items from expanding when content is added

You're setting the column and row sizes to auto. This means they will be sized based on their content. Instead, use fr units, which use the free space in the container.

#content {  display: grid;  grid-template-rows: 20px auto 20px;  grid-template-columns: 20px auto 20px;  height: 100vh;  background-color: #880022;}
#grid { grid-row-start: 2; grid-column-start: 2; display: grid; grid-template-rows: 1fr 1fr; /* adjustment */ grid-template-columns: 1fr 1fr; /* adjustment */ grid-gap: 2px;}
.tile { display: flex; align-items: center; justify-content: center; background-color: rgba(255, 255, 255, 0.2);}
.tile:hover { background-color: rgba(255, 255, 255, 0.3);}
.tile span { font-size: 2em;}
body { margin: 0;}
<div id="content">  <div id="grid">    <div class="tile"><span>test</span></div>    <div class="tile"></div>    <div class="tile"></div>    <div class="tile"></div>  </div></div>

How can I prevent an item in a CSS grid layout from growing to accommodate its content?

The solution was to add position: relative; to the container that I didn't want to grow (#output_container) and position: absolute; width: 100%; to its child (#output), whose content was causing the growth of the parent container.

function showSize(selector) {
const a = document.querySelector(selector);
const p = a.querySelector('p');
p.textContent = `${getComputedStyle(a).width} x ${getComputedStyle(a).height}`;
}

function showSizes() {
showSize('#left');
showSize('#right1');
showSize('#right2');
window.setTimeout(showSizes, 100);
}

function writeOutput(lines) {
const output = document.querySelector('#output');
let text = '';
for (let i = 0; i < lines; i++) {
for (let j = 65; j < 91; j++) {
text += String.fromCharCode(j);
}
text += "\n";
}
output.textContent = text;
output.scrollTop = output.scrollHeight;
}

document.querySelector('#small').addEventListener('click', () => writeOutput(5));
document.querySelector('#large').addEventListener('click', () => writeOutput(50));
writeOutput(5);
showSizes();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

#output_container {
/* Setting the height to 100% makes it the right size, unless its child div forces it to grow.
I want to prevent this type of growth, because the child content is scrollable.
*/
height: 100%;
/* Setting the height to a fixed size works, but I don't know in advance what the size should be in order for the Output panel to be be size that it would have been if this content were not there. */
/* height: 170px; */
background: lightseagreen;
position: relative;
}

#output {
position: absolute;
width: 100%;
background-color: hsl(0, 0%, 83%);
min-height: 50px;
max-height: 100%;
padding: 0.5em;
overflow: auto;
}

.pre {
white-space: pre;
font-family: monospace;
}

.pre:after {
/* Allows user to see a trailing line break. */
content: '';
}

#grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
"left right1"
"left right2";
}

#left {
grid-area: left;
background: lightskyblue;
display: flex;
flex-direction: column;
// min-height: 800px;
}

#grid > div {
padding: 10px;
overflow: hidden;
}

#right1 {
grid-area: right1;
background: seagreen;
min-height: 300px;
display: grid;
grid-template-rows: auto auto 1fr;
}

#right2 {
grid-area: right2;
background: lightsalmon;
min-height: 300px;
}

h1 {
margin: 0.5rem 0;
}

button {
margin: 0.25rem;
}
<div id="grid">
<div id="left">
<p></p>
<button id="small">Small amount of output</button>
<button id="large">Large amount of output</button>
</div>
<div id="right1">
<p></p>
<h1>Output</h1>
<div id="output_container">
<div id="output" class="pre"></div>
</div>
</div>
<div id="right2">
<p></p>
</div>
</div>

Prevent CSS grid from causing overflow

A few things to consider:

missing height reference

Using a percentage value to set the height of the img is problematic because there is no defined height on the container. Generally speaking, percentage heights should have a height reference on the parent for reliable rendering. Your declarations may or may not be ignored / misinterpreted.

See: Working with the CSS height property and percentage values


height: 100%

Setting the #results element to height: 100% is problematic, if you want to prevent a vertical overflow, because it doesn't factor in the height of the sibling (the h1).

height: 100% + height of h1 title > height of container (resulting in an overflow)

use a flexible height instead

Instead of using a percentage height, set a more flexible height, such as flex-grow. This tells the container to simply consume remaining space.


override the minimum height default

Grid and flex items are set by default to stop shrinking at the size of their content. Override that setting with min-height: 0.

See: Why don't flex items shrink past content size?


cross browser compatibility

Chrome can do the layout with less code (than posted below). It makes more assumptions about an author's intentions. Firefox, Edge and Safari assume less, so require more rules.

#container {  display: grid;  grid-template-columns: 1fr 5fr;  height: 100vh;}
#left { background: lightblue;}
#right { display: flex; flex-direction: column; height: 100vh;}
#results { flex-grow: 1; min-height: 0; display: grid; grid-template-rows: repeat(5, 1fr);}
.result { min-height: 0;}
img { max-width: 100%; max-height: 100%;}
body { margin: 0;}
<div id="container">  <div id="left">    <p>Some stuff on the left....</p>  </div>  <div id="right">    <h1>Title</h1>    <div id="results">      <div class="result">        <img src="https://upload.wikimedia.org/wikipedia/commons/6/62/Paracas_National_Reserve%2C_Ica%2C_Peru-3April2011.jpg" />      </div>      <div class="result">Result 2</div>      <div class="result">Result 3</div>    </div>  </div></div>

How to prevent item height expansion from expanding other item in the same row - CSS grid/flex?

So after some more searching I figured that the actually layout style that I needed aligns with the Masonry/Mosaic pattern. Since I now know the name I could do more specific Googling and found a blog post written by Tobias Ahlin with a solution.

https://tobiasahlin.com/blog/masonry-with-css/

The gist is that you need to have the flow direction be columns while being wrapped and then place orderings on the elements using :nth-child.


/* Render items as columns */
.container {
display: flex;
flex-flow: column wrap;
}

/* Re-order items into rows */
.item:nth-child(3n+1) { order: 1; }
.item:nth-child(3n+2) { order: 2; }
.item:nth-child(3n) { order: 3; }

/* Force new columns */
.container::before,
.container::after {
content: "";
flex-basis: 100%;
width: 0;
order: 2;
}

If I'm honest, I'm not really sure why this works. It will also behave unexpectedly depending on the heights of the container and the items.

Hope this helps anyone else who's having issues with this deceptively simple design layout!

How to prevent CSS grid from taking up full width?

Because you're using block level grid which is always takes up the full width available. Use inline-grid instead.

.layout-grid {
margin: 0 auto;

background-color: lime;

display: inline-grid;
grid-template-columns: 200px 100px;
grid-template-rows: auto;
grid-gap: 1rem;
grid-template-areas:
"company company"
"form billing";
}
<div class="layout-grid">
<div style="grid-area: company">company</div>
<div style="grid-area: form">form</div>
<div style="grid-area: billing">billing</div>
</div>

prevent content from increasing size of CSS grid column

Shubh Sheth's answer is correct but probably another way of writing that is:

grid-template-columns: repeat(3, 1fr); 

Comes in handy when you have numerous columns to layout.

Having said this, your error is that you are not specifying the columns but only the areas.

 grid-template-areas: 
'header header header'
'col1 col2 col3'
;

Grid areas are used in conjunction with grid-template-columns, not as a replacement.

So your layout code should look something like this:

display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
'header header header'
'col1 col2 col3';

In this case, you could very well remove the template-areas code because you are not changing any positions.



Related Topics



Leave a reply



Submit