1

I am making a navigation bar for my app. There are currently 3 main items on my navigation bar (Menu, Search and Cart indicator). And they are nicely evenly spread using flexbox and space-between. My app needs to support multiple languages and the problem is that when the translation for "Cart" changes then there is a huge content shifting happening and it looks like my app is broken.

Is there some way I can prevent this content shifting and still have my navigation items evenly spread out and centered? I have thought about adding fixed widths to my flex items but then I can't get my items to be centered (what space-between does).

Any help would be much appreciated.

Here is a working fiddle demo: https://jsfiddle.net/queeeeenz/mf6jak05/15/

Here you can see how my whole navigation bar jumps around when I change the language. enter image description here

Here is my code (I am using tailwind for styling):

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.tailwindcss.com"></script>
  </head>

  <body>
    <div class="flex justify-between items-center bg-gray-50 p-2 border border-gray-200">
      <div class="bg-gray-200 p-2 rounded">Menu</div>
      <div class="bg-gray-200 p-2 rounded w-[150px] text-center">Search</div>
      <div class="bg-gray-200 p-2 rounded" id="cart">Cart (2)</div>
    </div>
      
    <button class="bg-teal-100 mt-2 py-2 px-4 rounded-lg border border-teal-300" id="changeLanguage">
      Change Language
    </button>

    <script>
      document.querySelector('#changeLanguage').addEventListener('click', () => {
        if (document.querySelector('#cart').innerText === 'Cart (2)') {
          document.querySelector('#cart').innerText = 'Kariton Ti Panaggatang (2)'
        } else {
          document.querySelector('#cart').innerText = 'Cart (2)'
        }
      })
    </script>
  </body>
</html>
Gerard
  • 15,418
  • 5
  • 30
  • 52
Martin Zeltin
  • 2,496
  • 3
  • 18
  • 36
  • _"and still have my navigation items evenly spread out and centered?"_ - you can't really have both. The elements _are_ evenly spread out in that scenario your gif shows, even with the longer cart item text. And _because_ they are, the Search item is not centered in regard to the screen. – CBroe Jan 31 '23 at 07:15
  • @CBroe I guess more importantly I would like to prevent content jumping / shifting. – Martin Zeltin Jan 31 '23 at 07:16
  • I'd maybe try and position the cart item absolute here; and compensate for the width of the "Menu" item by a padding-right. Even without the translation, you'd have a similar issue already when the number of my cart items goes from 1 to 2 digits, so that might be the most robust solution, I think. The width of the Menu item you should be able to "guess" close enough, when you express it in a font-size relative unit. – CBroe Jan 31 '23 at 07:19

1 Answers1

3

If you want to make the Search to be at the absolute center of the container (unless there are no enough room), I would suggest you to use grid layout.

With columns look like this:

grid-template-columns: 1fr max-content 1fr;

It makes sure the left side and the right side take equal space. Then by giving the first item justify-self: flex-start and the last item justify-self: flex-end, they could stick to the both ends of the edge. So search could be centered and also avoiding overlapped with them.

let lang = 'en';

document.querySelector('button').addEventListener('click', () => {
  lang = lang === 'en' ? 'de' : 'en';
  document.querySelector('.item:last-child').innerText = lang === 'de' ? 'Kariton Ti Panaggatang (2)' : 'Cart (2)';
});
/* important */
.nav {
  display: grid;
  grid-template-columns: 1fr max-content 1fr;
}

.nav .item {
  white-space: nowrap;
}

.nav .item:first-child {
  justify-self: flex-start;
}

.nav .item:last-child {
  justify-self: flex-end;
}

/* decorative */
.nav {
  overflow: hidden;
  resize: horizontal;
  background-color: salmon;
}

.nav .item {
  background-color: gray;
  padding: 4px 20px;
  color: white;
}

.nav .item:nth-child(2) {
  margin: 0 4px;
}

footer {
  margin-top: 20px;
  display: flex;
  justify-content: space-between;
}
<nav class="nav">
  <div class="item">Menu</div>
  <div class="item">Search</div>
  <div class="item">Cart (2)</div>
</nav>

<footer>
  <button>Change Language</button>
  <span>You may adjust the width with this ↑</span>
</footer>
Hao Wu
  • 17,573
  • 6
  • 28
  • 60