CSS wrapping break points where I want between multiple text elements

Viewed 32

Okay, I've got 3 variables, StringA, StringB, StringC. StringA and StringB combine to link to an external page.

By default, all 3 elements are on the same line:

StringA StringB StringC

When one of them is too long for the space, they need to wrap in a way that leaves StringA on the first line:

StringA
StringB StringC

When more wrapping is needed, then:

StringA
StringB
StringC

My current code looks something like this (with flex happening at a higher level):

<span class="container">
    <a class="link">
        <span class="string-a">{{stringA}} </span>
        <span class="string-b">{{stringB}}</span>
    </a>

    <span class="string-c">{{stringC}}</span>
</span>

And the CSS:

.container {
    .string-b {
        white-space: nowrap;
    }

    .string-c {
        white-space: nowrap;
    }
}

This gets me most of the way there, but it makes a "smart" choice on whether to wrap between A and B or between B and C, and I need it to always wrap between A and B as the first choice and only wrap between B and C if A and B are already wrapped.

Presumably, there's a way to use flexbox to solve this, but I've tried a whole bunch of things and keep failing. Having to restore to JS to do it would be pretty ugly.

2 Answers

Your description is a little tough to follow, but I think this might put you on the right track.

Here's the SCSS (looks like that's what you're using):

.container {
  display: flex;
  flex-flow: row wrap;

  .link {
    display: flex;
    flex-flow: row wrap;
  }

  .string-b {
    white-space: nowrap;
    order: 2;
  }
}

...but I put compiled CSS in the snippet below.

.container {
  display: flex;
  flex-flow: row wrap;
}
.container .link {
  display: flex;
  flex-flow: row wrap;
}
.container .string-b {
  white-space: nowrap;
  order: 2;
}
<div class="container">
  <a class="link">
    <span class="string-a">{{stringA}}</span>
    <span class="string-b">{{stringB}}</span>
  </a>

  <span class="string-c">{{stringC}}</span>
</div>

If we can determine in advance at which screen width all 3 don't fit any longer, we can use a media query to wrap the link's children and keep string-c on the row.

With the current text, it appears that the full width, for all 3 to fit, is 255px. So I'll set the media query to max-width: 254px. Obviously, you'll need to adjust this according to the actual strings in your project.

.container {
  display: flex;
  flex-wrap: wrap;
}

@media screen and (max-width: 254px) {
  .container {
    align-items: end;
}
  .link {
    display: flex;
    flex-direction: column;
  }
}
<span class="container">
    <a class="link">
        <span class="string-a">{{stringA}} </span>
        <span class="string-b">{{stringB}}</span>
    </a>

    <span class="string-c">{{stringC}}</span>
</span>

Tip: for an easy way to test this, run the code snippet, then right click in the result area to inspect the elements. Find the iframe element and set its width. Start with 255px, where all 3 should still be displayed in a row, then reduce to 254px, where you should see string-a on one line and srting-b and string-c on the second line. Now reduce the frame width to <172 to see how all 3 are in one column.

Related