Search code examples
cssflexboxcss-grid

CSS grid/flex shrink based on content but grow evenly


I am building a Navbar for my app. I would like to have my items shrink based on their content but grow based on the average size.

All I want is:

  • if there is enough space for all items to be max-content-size, I want the size to be even of all items.
  • if there is enough space for all items min-content, I want the items to shrink based on their content.
  • if there is not enough space for all items min-content, I want them to further shrink based on their content, so that the biggest item starts to shrink first, until it is as big as the secont biggest item, then both of them start to shrink Expected behavior

I could do this using grid or flex. Unfortunately, I cannot get it the expected behavior as either they grow based on their content (and not based on the average size) or they shrink based on their average size and not based on their content. I included a snippet with two sample implementations.

body {
  margin: 0;
  font-family: Verdana;
}

.small {
  width: 400px;
}

.medium {
  width: 800px;
}

.large {
  width: 1200px;
}

.container-flex {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100%;
  border: 1px solid black;
}

.item-flex {
  display: flex;
  flex-direction: column;
  flex-basis: auto;
  flex-shrink: 1;
  flex-grow: 1;
  overflow: hidden;
  padding: 20px;
  background-color: green;
  border: 1px solid red;
  min-width: 0;
}

.title {
  background-color: white;
  flex-grow:0;
  text-align: center;
  vertical-align: middle;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
}

.container-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 1fr);
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
  border: 1px solid black;
}

.item-grid {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 20px;
  background-color: green;
  border: 1px solid red;
  min-width: 0;
}
<div class="small">
<h2>Small</h2>
<h4>Flex</h4>
<div class="container-flex">
<div class="item-flex">
<div class="title">Title</div>
</div>
<div class="item-flex">
<div class="title">Long Title</div>
</div>
<div class="item-flex">
<div class="title">Even longer Title</div>
</div>
<div class="item-flex">
<div class="title">Title</div>
</div>
</div>
<h4>Grid</h4>
<div class="container-grid">
<div class="item-grid">
<div class="title">Title</div>
</div>
<div class="item-grid">
<div class="title">Long Title</div>
</div>
<div class="item-grid">
<div class="title">Even longer Title</div>
</div>
<div class="item-grid">
<div class="title">Title</div>
</div>
</div>
</div>
<div class="medium">
<h2>Medium</h2>
<h4>Flex</h4>
<div class="container-flex">
<div class="item-flex">
<div class="title">Title</div>
</div>
<div class="item-flex">
<div class="title">Long Title</div>
</div>
<div class="item-flex">
<div class="title">Even longer Title</div>
</div>
<div class="item-flex">
<div class="title">Title</div>
</div>
</div>
<h4>Grid</h4>
<div class="container-grid">
<div class="item-grid">
<div class="title">Title</div>
</div>
<div class="item-grid">
<div class="title">Long Title</div>
</div>
<div class="item-grid">
<div class="title">Even longer Title</div>
</div>
<div class="item-grid">
<div class="title">Title</div>
</div>
</div>
</div>
<div class="large">
<h2>Large</h2>
<h4>Flex</h4>
<div class="container-flex">
<div class="item-flex">
<div class="title">Title</div>
</div>
<div class="item-flex">
<div class="title">Long Title</div>
</div>
<div class="item-flex">
<div class="title">Even longer Title</div>
</div>
<div class="item-flex">
<div class="title">Title</div>
</div>
</div>
<h4>Grid</h4>
<div class="container-grid">
<div class="item-grid">
<div class="title">Title</div>
</div>
<div class="item-grid">
<div class="title">Long Title</div>
</div>
<div class="item-grid">
<div class="title">Even longer Title</div>
</div>
<div class="item-grid">
<div class="title">Title</div>
</div>
</div>
</div>

The different sizes are just for testing, I am asking for a responsive solution working with different contents and different number of items.


Solution

  • I solved it in codepen, here's the link to the Codepen

    Here is the HTML

    <div class="navbar">
      <a href="" class="navbarLink">
        <div class="text">
          Title
        </div>
      </a>
      <a href="" class="navbarLink">
        <div class="text">
          Long Title
        </div>
      </a>
      <a href="" class="navbarLink">
        <div class="text">
          Even longer Title
        </div>
      </a>
      <a href="" class="navbarLink">
        <div class="text">
          Title
        </div>
      </a>
    </div>
    

    CSS

    body {
      margin: 0;
    }
    
    .navbar {
      display: grid;
      grid-template-columns: auto auto auto auto;
      
      padding 10px
    }
    
    .navbar > a {
      text-align: center;
      color: black;
      text-decoration: none;
      
      padding: 10px;
      border: 5px solid green;
    
      font-size: 30px;
    }
    
    .navbar > a > .text {
      overflow: hidden;
      display: -webkit-box;
      -webkit-line-clamp: 1; /*Number of lines before an ellipsis... pops up */
      -webkit-box-orient: vertical;
    }