Laying out a tab bar in HTML/CSS: shrinking larger elements before smaller ones

Viewed 143

I'm trying to lay out a tab bar in HTML / CSS but am having trouble implementing my desired layout. It is:

  • no tab element should ever be larger than needed
  • if there is not enough space, larger elements should be shrunk before smaller elements

Essentially, I'd like it to be similar to "5 tabs? max-width: 20%" except where if one tab is very short, another could claim its space.

The closest I've gotten is with flex: 0 1 auto and setting min-width to 0. When there's more space than needed, this works fine:

Short tabs

However, when there is insufficient space, the tabs are shrunk according to their initial width ratios:

Long tabs

This is very close to what I'm trying to accomplish. However, each tab loses width according to its initial size ratio, meaning the first tab (whose contents is short) gets undesirably shortened.

How can I implement a row of elements such that width is taken from the larger elements evenly before width is taken from the smaller elements? I am hoping to accomplish this without javascript if at all possible.

For completeness, the code which drives the almost correct screenshots above is:

.nav-tabs {
    display: flex;
}
.nav-tabs li {
    flex: 0 1 auto;
    min-width: 0;
    max-width: auto;
}
.nav-tabs li a {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.nav-tabs .manage-tabs {
    min-width: auto;
    width: auto;
    flex-basis: 0;
    margin-left: auto;
}

with the following HTML, using Twitter Bootstrap 2.3.2 for basic styles:

<ul class="nav nav-tabs">
    <li>
        <a href="...">short1</a>
    </li>
    <li>
        <a href="...">This is very long wwwwwww</a>
    </li>
    <li class="active">
        <a href="...">Also very long wwwwwwwwww</a>
    </li>
    <li>
        <a href="...">wwwwwwwwwwwwwwwwwwwwwwwww</a>
    </li>
    <li>
        <a href="...">awwwwwwwwwwwwwwwwwwwwwwww</a>
    </li>
    <li>
        <a href="...">bwwwwwwwwwwwwwwwwwwwwwwww</a>
    </li>
    <li class="manage-tabs">
        <a href="...">Manage Pockets</a>
    </li>
</ul>
1 Answers

I think you may not be able to use all available space without some JS to calculate the space that the shorter ones aren't using.

The issue for me is with the max-width of 20% and where the shorter elements do not take up 20%. When you set 20% it does not take up the rest of the available space for use by the longer ones. If you are ok with leaving some room when there are smaller items than the below works. If they are all longer than 20% they will all get the text-overflow.

.nav-tabs {
  display: flex;
  padding: 0;
}

.nav-tabs li {
  list-style: none;
  display: flex;
  /* 100% minus width of "Manage Pockets" then divided by the number of remaining nav items */
  max-width: calc((100% - 125px) / 5);
}

.nav-tabs li a {
  display: block;
  width: 100%;
  padding: 8px 10px 6px;
  border-bottom: 1px solid transparent;
  border-bottom-color: currentColor;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav-tabs li.active > a {
  border: 1px solid currentColor;
  border-bottom-color: transparent;
}

.nav-tabs .manage-tabs {
  flex-shrink: 0;
  max-width: none;
  margin-left: auto;
}
<nav>
  <ul class="nav-tabs">
    <li>
      <a href="#">Mollis</a>
    </li>
    <li>
      <a href="#">Vestibulum</a>
    </li>
    <li class="active">
      <a href="#">Ligula Dapibus Purus</a>
    </li>
    <li>
      <a href="#">Cras Ridiculus Commodo Sem</a>
    </li>
    <li>
      <a href="#">Ultricies Vestibulum Tortor Adipiscing Nullam</a>
    </li>
    <li class="manage-tabs">
      <a href="#">Manage Pockets</a>
    </li>
  </ul>
</nav>

Related