10

So I have this:

.menu {
  display: flex;
  align-items: center;
  justify-content: center;
  /* flex-wrap: wrap; → I want this only when the children reach their min-width, to avoid horizontal scrolling */
}

.menu-title {
  flex-shrink: 0;
}

.menu-item {
  flex: 0 1 auto;
  min-width: 10rem;
}

.menu-link {
  padding: 0 1rem;
}


/* Demo purpose */

html,
body {
  margin: 0;
  padding: 0;
}

.menu {
  margin: 2rem;
}

.menu-title {
  margin-right: 1rem;
}

.menu-link {
  display: flex;
  position: relative;
  text-decoration: none;
  align-items: center;
}

.menu-icon {
  display: block;
  width: 2em;
  height: 2em;
  flex-shrink: 0;
  margin-right: 0.5em;
  background-color: #eee;
}
<div class="menu">
  <div class="menu-title">Menu:</div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A menu entry</span></a></div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A very very very very long menu entry that is should be on two lines</span></a></div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A quite long menu entry</span></a></div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A menu entry that is a bit longer</span></a></div>
</div>

<div class="menu">
  <div class="menu-title">Menu:</div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A two items menu entry</span></a></div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">I should have put some lerem ispum at a moment right?</span></a></div>
</div>

<div class="menu">
  <div class="menu-title">Menu:</div>
  <div class="menu-item"><a class="menu-link" href=""><span class="menu-icon"></span><span class="menu-text">A menu entry, but yeah you got it</span></a></div>
</div>

I want flex items to be exactly how they behave right now: only one line, shrink when they need, so the text goes on 2 lines, and grow when they can till their normal 'inline' width.

But they have a min-width, which create an horizontal scrolling at a point. And at this point, I'd like the last one to go on a new line: I want the wrap behavior, but not before they reach their min-width because I want them to shrink before.

The only way I managed to make it work, is by adding a wrap on .menu and allow items to grow, but when there's only one item, the render is not right (I still want the max width to be content width). https://jsfiddle.net/joanva/9zgn3hcm/30/ (initial: https://jsfiddle.net/joanva/9zgn3hcm/)

Joan
  • 659
  • 2
  • 7
  • 20
  • 1
    Flex-wrap is either ON or OFF....there's no conditional options available. I suspect that what you want is not possible given the nature of inline-boxes. - https://stackoverflow.com/questions/37406353/make-container-shrink-to-fit-child-elements-as-they-wrap – Paulie_D Aug 12 '19 at 10:42
  • @Paulie_D Thanks for edit and this. There's actualy something close to what I try to achieve, but it breaks the width (added to the post). – Joan Aug 12 '19 at 10:56

2 Answers2

10

Gotcha!

Setting .menu to wrap, and allowing items to grow + adding max-width: fit-content; makes it.
Intrinsic size is kinda cutting edge but graceful degradation ftw.

https://jsfiddle.net/joanva/9zgn3hcm/33/

Joan
  • 659
  • 2
  • 7
  • 20
4

What you're describing is a perfect use-case for grid.

The css would look something like this:

.menu {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  grid-gap: 1rem;
}

This sets up your grid so that it will attempt to 'auto-fit' the columns, stretching them between evenly spaced (1fr) and your minimum column width (10rem). If it can't fit the content on one row because they would go below the min-width, it will instead move the excess onto a new row.

Here is a jsfiddle example. You can try manually adding a few extra menu-items and see what happens: https://jsfiddle.net/547hq0Lb/4/

  • – thanks for the suggestion! But does grid really helps here? columns do not adapt to text width, and columns of each row (when on a new line) shouldn't have the same width as the col above… https://jsfiddle.net/joanva/78rbneka/ – Joan Aug 12 '19 at 11:11
  • 1
    I modified your fiddle to use grid: https://jsfiddle.net/yL98s41v/ Can't get around the issue of the new row obeying the column width though. You might not be able to do what you want with pure css. (edit: still needs to tidy up the alignment issues of the inner content) – Ollie Carson Aug 12 '19 at 11:24