Flexible Overflow

Gif animation showing this article's effect in action

A lot of peo­ple love re­spon­sive sites, and we used to make them with the help of Me­dia Queries. To­day, in the era of com­po­nents, we can't rely just on the width of our view­port any­more. Our com­po­nents need to be in­de­pen­dent and work in any con­di­tions.

One of the so­lu­tions every­one is wait­ing for is Con­tainer Queries (for­merly known as El­e­ment Queries). But their fu­ture is not cer­tain, and while there are poly­fills that al­low us to use some of their pos­si­ble fea­tures, the need to poly­fill every­thing can be daunting.

But should we rely on JS or look at our news feeds in an­tic­i­pa­tion of Con­tainer Queries all the time? What if CSS is al­ready pow­er­ful enough to solve some of the po­ten­tial Con­tainer Queries use cases right now? What if CSS could even solve some of the re­spon­sive cases that even Con­tainer Queries prob­a­bly couldn't solve (Very of­ten we don't know the di­men­sions we could rely on, even on per-com­po­nent ba­sis, so queries not al­ways could help us, and we need to learn how to use more com­plex CSS to achieve what we want.)?

To­day I'll pre­sent you with one of those cases.

Long Line of Text Becomes Shorter

When­ever we have a very long string that won't fit our avail­able space, the most ob­vi­ous so­lu­tion is text-over­flow: el­lip­sis. But very of­ten we don't want to just trun­cate our long text strings: we could want to sub­sti­tute it with some other text in­stead, re­move some parts, or re­place it with just an icon. That's what you could see hap­pen­ing in the gif at the start of this ar­ti­cle, and here is a much sim­pler live ex­am­ple (try to re­size the wrap­per or tog­gle the tog­gler to see how it would be­have):

Some long text that could become shorter.

The code be­yond this ex­am­ple is just some HTML & CSS which uses (With fall­back to just text-over­flow: el­lip­sis when there is no sup­port for flex-wrap.) flexbox, and is made to be ac­ces­si­ble to screen-read­ers which would read only the longest part, ig­nor­ing the shorter one. Ah, and also when­ever you see the shorter line, the longer part would be also ac­ces­si­ble as an HTML title.

The Implementation

I'll go straight to the code and would ex­plain some parts of it later. Here is the CSS I've writ­ten for the above ex­ample:

.overflower {
  display: inline-block;
  overflow: hidden;

  box-sizing: border-box;
  max-width: 100%;
  height: 1.5em;
  line-height: 1.5em;

  white-space: nowrap;
  text-overflow: ellipsis;
}

.overflower-long {
  display: inline;
}

.overflower-short {
  display: none;
}

@supports (flex-wrap: wrap) {
  .overflower {
    display: inline-flex;
    flex-wrap: wrap;
  }

  .overflower-short {
    display: block;
    overflow: hidden;

    flex-grow: 1;
    width: 0;

    text-overflow: ellipsis;
  }

  .overflower-long {
    flex-basis: 100%;
  }
}

Here is how the markup looks for it:

<span class="overflower">
  <span
    class="overflower-short"
    aria-hidden="true"
    title="Some long text that could become shorter"
  >
    Short text here is.
  </span>
  <span class="overflower-long">
    Some long text that could become shorter.
  </span>
</span>

The best part here is that you can nest this con­struc­tion, thus gain­ing more than two pos­si­ble length vari­a­tions:

Very long text that would become shorter if you'd resize it.

And two more ex­am­ples: header and a menu, as the more com­mon use cases for some­thing like this:

Really Long Header Becomes so Much Shorter.

Flex

So, how and why does this work? Let's look at CSS:

  1. The first thing you can no­tice is that most of the styles are be­yond the @sup­ports (We miss IE11 here, and maybe with some hacks, we could make it work as well, but I don't think it would worth the ef­fort. You can try though if you want.): that is be­cause every­thing works only when we can have flex-wrap, so we would need to have some fall­back in case there won't be any (UC Browser for An­droid, hello).
  2. The next thing is that we need to make the height of our block fixed (and equal to line-height (That would be an ideal case for the lh unit, can we have it al­ready, please?) for sim­plic­ity), so we could trim every­thing that would be wrapped later (rather a com­mon trick I'd say).
  3. Now, the most in­ter­est­ing part: we need to make the shorter part to dis­ap­pear when there is enough space for our long part, but then to ap­pear when there won't be. We do this by mak­ing the short part to take all the re­main­ing space of the flex flow and then mak­ing the long part to take all 100%.

    When there is enough space for the long part it would al­ways take this space. But when its par­ent would be­come shorter than the con­tents of the long part, the magic part would hap­pen: it would jump to the new line as there was an­other item be­fore it, and that shorter item, that had ba­si­cally 0 width be­fore, would grow to take all the sud­denly va­cant space.

In the end, the CSS for this ef­fect is rather short. We just uti­lize mul­ti­ple as­pects of flexbox to­gether: wrap­ping, grow­ing and shrinking.

Accessibility

While there are some mi­nor caveats that are hard to over­come (when the shorter vari­ant is shown, you could se­lect & copy it along­side the longer vari­ant (It is pos­si­ble to work around that by not hav­ing the shorter vari­ants as HTML con­tent, but in­sert­ing it as pseudo-el­e­ments by us­ing at­trib­utes, see the ex­am­ple with Header above.)), most of the a11y stuff is fix­able in HTML:

  • For screen read­ers we need only the longest part, so we can hide every­thing else us­ing aria-hid­den='true'.
  • We can en­hance the ex­pe­ri­ence for users who can use a pointer de­vice and can see the ti­tle at­tribute's tooltip by adding it for the short part only. This way, when the text would be dis­played at full, we won't have this tooltip. And when at least some­thing is hid­den we'd get the tooltip on hover.
  • If we would use this method by nest­ing it, we'd need just one aria-hid­den and ti­tle, both on the top­most short vari­ant.
  • As the cru­cial part of this method is based on flex-wrap, for those who don't sup­port it we make a fall­back to just text-over­flow: el­lip­sis, so things won't break in older browsers.

Play With Flex, CSS & Everything

This was just one of the pos­si­ble ef­fects you can achieve us­ing pow­er­ful mod­ern CSS. And as flexbox is al­ready re­ally wide sup­ported, and fall­backs for it are easy, noth­ing should stop you from us­ing it. I'll con­tinue my ex­per­i­ments with flexbox, and later with grids, so stay tuned for more re­spon­sive, query­less so­lu­tions from me. Ah, and there is also some space for good old floats, they're still cool and can some­times achieve stuff that is re­ally hard to do oth­erwise.

Things were in­ter­est­ing in CSS, they are now, and they'll al­ways be.