css grid grows over 100% width with fr but not with minmax

Here's the solution to the second grid.

.grid-minmax {
   display: grid;
   grid-template-columns: minmax(120px, 1fr);
 }

This is how the browsers calculate the track size:

(200px container) - (120px nonflexible track size) + (1fr leftover space) = 200px

Using the guidance provided in the specification (see below), the behavior above is relatively simple and straightforward.

But why does the content in the first container overflow?

That's a tricky scenario and, at this point, I can see two potential paths to the answer.

  1. There is an issue / problem / bug in the workings between:

    .break-long-text {
        word-wrap: break-word;
        overflow-wrap: break-word;
     }
    

    and

    grid-template-columns: 1fr;
    

    I say this because when the string is broken up, the problem in the question doesn't exist. In other words, both grid containers behave the same (demo).

OR

  1. I'm not finding the answer in the specification. I've reviewed the following sections.

    • § 7.2.3. Flexible Lengths: the fr unit
    • § 11.7. Expand Flexible Tracks
    • § 11.7.1. Find the Size of an fr

Here's how the fr unit works, in detail:

From the spec:

§ 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 leftover space in the grid container.

Tracks sized with fr units are called flexible tracks as they flex in response to leftover space similar to how flex items fill space in a flex container.

Okay. So far, so good. The fr unit in grid layout functions similarly to flex-grow in flex layout.

Moving on with the spec...

The distribution of leftover space occurs after all non-flexible track sizing functions have reached their maximum.

The total size of such rows or columns is subtracted from the available space, yielding the leftover space, which is then divided among the flex-sized rows and columns in proportion to their flex factor.

(emphasis mine)

In other words all non-flexible track sizes (such as those based on pixels or ems) are first subtracted from the available space (200px, in this case). Whatever space remains is considered leftover space, which then gets targeted by the fr unit.

Also, what exactly is a "track sizing function"?

Each track sizing function can be specified as a length, a percentage of the grid container’s size, a measurement of the contents occupying the column or row, or a fraction of the free space in the grid.

It can also be specified as a range using the minmax() notation, which can combine any of the previously mentioned mechanisms to specify separate min and max track sizing functions for the column or row.

https://www.w3.org/TR/css3-grid-layout/#grid-template-rows-track-sizing-function

This explains the workings for the second grid container (with minmax()) but not the first (with 1fr).


So should I always use minmax if I don't want one cell to be larger than its parent?

It seems pretty clear to me that the grid fr units are not playing well with the word-wrap , overflow-wrap and hyphens properties.

That being the case, I would recommend using the minmax() function as a workaround when you have reason to believe that the inner text will have long words.

Note: Since we are attempting to simulate the results of fr units - it would make sense to use 0 as the minimum length in the minmax() function. eg: grid-template-columns: minmax(0, 1fr);

The demo below compares fr units and minmax() with long text - the results seem to look the same!

.medium-container { 
  width: 50vw;
  border: 1px solid green;
  padding: 20px; 
}
.border { box-shadow: 0 0 2px 2px black; }

.break-long-text {
    width: 100%;
    word-wrap: break-word;
    overflow-wrap: break-word;
}


.grid-fr {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 20px;
}

.grid-minmax {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-gap: 20px;
}

.break-long {
    width: 100%;
    word-wrap: break-word;
    overflow-wrap: break-word;
}
<h2>Using 'fr' units:</h2>
<div class="medium-container">
  <div class="grid-fr">
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,  when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
      </div>
</div>
<hr>
<h2>Using 'minmax' workaround (contains long text):</h2>
<div class="medium-container">
  <div class="grid-minmax">
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
    <div class="break-long-text border"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG when an unknown printer took a galley of type and scrambled
      it to make a type specimen book. 
    </div>
      </div>
</div>

Codepen demo (Resize to see effect)


Another workaround: word-break: break-word;

'fr' units do play well with the word-break property.

.break-long-text {
    word-break: break-word; /* word-break workaround */
}

In particular, blink-based browsers are ok with the break-word value, while firefox requires the break-all value.

.small-container { width: 200px; }
.small-container > div { margin: 16px; }
.border { box-shadow: 0 0 2px 2px black; }

.break-long-text {
    word-break: break-word;
}
/* firefox only CSS */
@-moz-document url-prefix() {
  .break-long-text {
    word-break: break-all;
  }
}

.grid-fr {
    display: grid;
    grid-template-columns: 1fr;
}

.grid-minmax {
    display: grid;
    grid-template-columns: minmax(120px, 1fr);
}
<div class="small-container">
  <div class="grid-fr">
    <div class="break-long-text border">
      LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG
    </div>
  </div>
  <div class="grid-minmax">
    <div class="break-long-text border">
      LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG
    </div>
  </div>
</div>

The problem with this workaround is that browsers which require the break-all value - such as firefox - break works in the middle - usually not a desired result.

.small-container { width: 200px; }
.small-container > div { margin: 16px; }
.border { box-shadow: 0 0 2px 2px black; }

.break-long-text {
    word-break: break-all;
}

.grid-fr {
    display: grid;
    grid-template-columns: 1fr;
}

.grid-minmax {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}
<div class="small-container">
  <div class="grid-fr">
    <div class="break-long-text border">
      Lorem Ipsum is simply dummy text of the printing and typesetting industry. LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG when an unknown printer took a galley of type and scrambled
    </div>
  </div>
  <div class="grid-minmax">
    <div class="break-long-text border">
      Lorem Ipsum is simply dummy text of the printing and typesetting industry. LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG when an unknown printer took a galley of type and scrambled
    </div>
  </div>
</div>

Solution:

Setting min-width:0 of .break-long-text container will do the trick.

.small-container { width: 200px; }
.small-container > div { margin: 16px; }
.border { box-shadow: 0 0 2px 2px black; }

.min-width-0{
    min-width: 0;
}
.break-long-text {
    width: 100%;
    word-wrap: break-word;
    overflow-wrap: break-word;
}

.grid-fr {
    display: grid;
    grid-template-columns: 1fr;
}

.grid-minmax {
    display: grid;
    grid-template-columns: minmax(120px, 1fr);
}
<div class="small-container">
  <div class="grid-fr">
    <div class="break-long-text border min-width-0">
      LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG
    </div>
  </div>
  <div class="grid-fr">
    <div class="break-long-text border">
      LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG
    </div>
  </div>
  <div class="grid-minmax">
    <div class="break-long-text border">
      LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG
    </div>
  </div>
</div>

Explanation:

From css-tricks:

The minimum width of a grid column is auto. (The same is true for flex items, by the way.)

And since auto is entirely based on content, we can say it is “indefinitely” sized, its dimensions flex. If we were to put an explicit width on the column, like 50% or 400px, then we would say it is “definitely” sized.

To apply our fix, we need to make sure that there is the column has a definite minimum width instead of auto.

Tags:

Html

Css

Css Grid