CSS grid where one column shrinks to fit content, the other fills the remaning space

Andrea picture Andrea · Nov 8, 2013 · Viewed 16.1k times · Source

I need to create a horizontal layout where one block takes all available space and the other ones shrink to fit their content.

For example:

<div class="grid">
    <div class="expand">Long text label</div>
    <div class="shrink">Button</div>
</div>

A more complex example with two rows (an actual grid):

<div class="grid">
    <div class="row">
        <div class="shrink">...</div>
        <div class="expand">...</div>
        <div class="shrink">...</div>
        <div class="shrink">...</div>
    </div>
    <div class="row">
        <div class="shrink">...</div>
        <div class="expand">...</div>
        <div class="shrink">...</div>
        <div class="shrink">...</div>
    </div>
</div>

My requirements:

  1. The large block should fill all available space even if short
  2. The small blocks should fit their content
  3. The large block (usually a text label) may be a single word larger that the available space, so it should be truncated in this case
  4. The large block should not wrap if multi-word
  5. The small blocks should not wrap (though in the case of multiple buttons or icons, this can be solved by making one block per component)
  6. Support multiple rows (i.e. columns should be aligned)

I am targeting Android and iOS smartphones.

I have tried to adapt the code from this answer but I could not make it work for multiple rows. Also, the source code must be out of order, which is confusing (though not blocking for my use case). Here's a jsfiddle: http://jsfiddle.net/k3W8L/

Answer

kumarharsh picture kumarharsh · Sep 26, 2017

I bumped into this question recently while learning to use grid in my app. With the ilyaigpetrov's answer's help, I was able to get an shrink-to-fit column sizing to work. Although the answer doesn't give much explanation, so I thought I'd add this:

What you need to do is use grid-template-column and set the size of column you want to shrink-to-fit as auto, and at least one other column in the fr unit.

Example: To recreate the sidebar-content layout, where the sidebar is collapsible,

-------------------------------
| Sidebar |       Content     |
-------------------------------

you can create the grid as:

.grid {
  display: grid;
  ...
  grid-template-columns: auto minmax(0, 1fr); // see note below
  grid-template-areas: "sidebar content";
}
.sidebar {
  grid-area: sidebar;
}
.content {
  grid-area: content;
}

See the codepen here for a demo & code: https://codepen.io/khs/pen/vegPBL You can click on the navbar to see auto-sizing in action.


Note: One thing I've learnt since writing this answer is that in most cases, and especially in a fixed-height/fixed-width layout, you should use minmax(0, 1fr) instead of 1fr. The reason is that 1fr is actually a shorthand for minmax(auto, 1fr). This breaks when fixed layouts with longer content. See this question for more details: How come minmax(0, 1fr) works for long elements while 1fr doesn't? Hence I've updated my answer to reflect the fact. The minmax might be a little verbose, but it's almost always what you want for this kind of layout.