skip to Main Content

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.

2

Answers


  1. with 3 different container behaviors, you need to change the characteristics for the cards.

    "small container cards" need a max-width with overflow: hidden and text-overflow: ellipsis.

    "medium container cards" need a min-width and the default flex-shrink disabled.

    "large container cards" need to preset the width to have all the equal width:

    .container {
      display: flex;
      width: 100%;
    }
    
    .container>* {
      box-shadow: inset 0 0 0 0.5em rgba(0, 200, 0, 0.6);
      border: 1px dashed red;
      padding: 0.5em;
      text-align: center;
      white-space: nowrap;
    }
    
    @media only screen 
      and (min-width: 320px) 
      and (max-width: 524px) {
        .container > * {
          max-width: 5em;
          overflow: hidden;
          text-overflow: ellipsis;
        }
    }
    
    @media only screen 
      and (min-width: 525px) 
      and (max-width: 719px) {
        .container > * {
          min-width: 3em;
          flex-shrink: 0;
        }
    }
    
    @media only screen
      and (min-width: 720px) {
        .container {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
        }
    }
    <div class="container">
      <div>Title</div>
      <div>Long Title</div>
      <div>Even longer Title</div>
      <div>Title</div>
    </div>

    The grid for larger screens does not care for the amount of child elements but will also not break by default. But without JS I don’t see a solution that could do that.

    Login or Signup to reply.
  2. 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;
    }
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search