Grid and flexbox min-width

| permalink | css

Sometimes you want a specific content block to be able to scroll horizontally when the content grows wider than its container.

The most common use case is for a code block.

<!-- HTML -->
<pre>
  <code>*some very long lines of code*</code>
</pre>
/* CSS */
pre code {
  display:block;
  overflow-x:auto;
}

However, sometimes it refuses to do so, for example inside a Grid or Flex container, when flex-direction: row.

The reason this happens is due to the min-width.

The initial value is min-width: auto. auto maps to 0 for all CSS2 elements because the initial value used to be min-width: 0 for CSS2.

However both Grid and Flexbox are added later and have their own rules governing minimum sizing.

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

Logic

For minimum size, the "content-based minimum size" is used if the element is a flex item, or in case of grid item if all of the following are true (paraphrased):

  1. overflow: visible;
  2. at least one of the columns/rows it span need to have min-width: auto, either set by default, or via minmax(auto, #);
  3. if it spans more than one track in that axis, none of those tracks are flexible (fr).

Otherwise, minimum size is 0.

The "content-based minimum size" is in turn derived from, in order of precedence (paraphrased):

  1. the width or height value, if defined;
  2. the calculated size from aspect-ratio and the opposite height or width values, if defined;
  3. the min-content size in the relevant axis, clamped, if it has a preferred aspect ratio, by any definite opposite-axis minimum and maximum sizes converted through the aspect ratio.

Ok, I've got to admit that #3 hurts my brain.

I'm just going to assume that it simply means min-content is the fallback value if #1 and #2 does not apply, because this is the last stop.

Effect

When a flex/grid item is set to min-width: min-content, it will expand to the full width of its content, thereby never triggering the overflow-x property on the <code> element.

The solution

Based on the logic, you can solve it by giving the flex or grid item min-width: 0.

For grid items, you can additionally solve it by:

  1. give item a value other than overflow: visible such as overflow: auto;
  2. provide a minimum width via grid-template-columns: minmax(0, 1fr);
  3. create two columns grid-template-columns: 1fr 1fr, and span across both grid-column: span 2.

Nested Flexbox

It appears that for nested Flexbox, you must apply this fix to all flex items.

Will do more testing later and update this post.