CSS - Flexbox

Container-Adapting Tabs With "More" Button

A non-wrapping horizontal menu, with a "More" button on the end, which reveals a vertical list of menu items that overflow the limited horizontal space.

This looks like an excellent, accessible starting point for the priority navigation pattern:

Or the priority navigation pattern, or progressively collapsing navigation menu. We can name it in at least three ways.

There are multiple UX solutions for tabs and menus and each of them have their own advantages over another, you just need to pick the best for the case you are trying to solve. At design and development agency Kollegorna we were debating on the most appropriate UX technique for tabs for our client’s website…

We agreed it should be a one-liner because the amount of tab items is unknown and narrowed our options down to two: horizontal scroll and adaptive with “more” button. Firstly, the problem with the former one is that horizontal scroll as a feature is not always visually obvious for users (especially for narrow elements like tabs) whereas what else can be more obvious than a button (“more”), right? Secondly, scrolling horizontally using a mouse-controlled device isn’t a very comfortable thing to do, so we might need to make our UI more complex with additional arrow buttons. All considered, we ended up choosing the later option[.]


Is it really safe to start using CSS Grid Layout?

The really short version? Absolutely. Slightly longer version:

Grid is new! Surely it has terrible browser support?

CSS Grid Layout shipped into Chrome, Firefox, Opera and Safari in March of this year. Microsoft Edge currently have an updated Version of Grid available behind a flag in Preview builds. At the time of writing, Can I Use indicates a global availability of CSS Grid Layout of 65.64%, rising to 70.75% if you include the prefixed version in IE10, 11 and current Edge. This is a rate of adoption we’ve never seen before for such a huge feature. It isn’t surprising that people don’t realise how many visitors will have support.


And non-supporting browsers?

CSS has the solution for you. To start with, defined in the Grid and Flexbox specifications are exactly how those specifications overwrite older layout methods.

Therefore if you want to use floats, inline-block, multiple-column layout, flexbox or even display: table as a fallback for your grid layout then the spec has you covered. You can overwrite those methods in a safe and predictable way. I made a cheatsheet explaining the fallbacks. I also cover several of these in my talk which was recorded at Render Conference earlier this year.

CSS also has Feature Queries. These have really great browser support, and the nice thing about Feature Queries is that you don’t need to concern yourself with the browsers that don’t support feature queries. There is no browser supporting Grid Layout and not supporting Feature Queries.


Generally you will then have a few things in the fallback CSS that will “leak through” to the grid layout. This is often widths on items as we need to assign widths to items in legacy layout to fake something that looks like it is using a grid. Therefore we use a simple feature query, checking for support of Grid Layout, and there we perhaps set widths back to auto.


Expand last row of wrapped flex items to fill entire row

Thanks to Jonathan Snook, I’ve learnt that we don’t need quantity queries to create a balanced grid. Quantity queries are very powerful, but so is Flexbox. If we just want all the items in the last row to fill the space, regardless of how many there are, then Flexbox can take care of this. But if we want to add additional styles to the items, we still need quantity queries.

This is the grid we want to achieve:

A wrapped grid of flexbox items. The first two rows have four items each, stretching to the full width of the container. The third row only has three items, but they also stretch to the available space.

Here’s the Flexbox magic.

The container needs to have the property display: flex; and the items need to be wrapped using flex-wrap: wrap;


.list {
    display: flex;
    flex-wrap: wrap;

Now here’s the clever bit. We can set an initial width to the items (in this case flex-basis: 23%;) so that each item will always get a width of 23% unless otherwise stated in the CSS. flex-grow: 1; tells the items to grow and fill the space in the row.


.list-item {
    flex-basis: 23%;
    flex-grow: 1;

So, thanks to flex-grow, no matter how many items are in the last row, they will always fill the space. Works like magic! It’s amazing how much can be achieved with so little CSS.


The limits of @supports

@supports may be very useful, but it can only tell you so much, especially in the case of browsers that will return true, technically supporting the feature, but having a buggy implementation. This is a case where we can often assume too much about a browser based on a reductive test that isn’t guaranteed to tell us what we think it does. PPK explains:

If a mobile browser doesn’t support background-attachment: fixed in practice, what happens when you do this?


@supports(background-attachment: fixed) {
	// CSS

Does it return false because the mobile browser doesn’t support it? Or does it return true because its desktop version supports it? With my background-attachment test data in hand I could now answer this question.

All mobile browsers return true for both fixed and local. Only 3 out of 23 browsers speak the truth here. See the test case and the inevitable table for more details.


What’s clear from these tests is that @supports is only useful when you’re detecting entire CSS modules such as flexbox. So the check below makes sense.


@supports (display: flex) {
	// flexbox layout
@supports not(display: flex) {
	// float layout

This example is likely safe. If a browser decides to support flexbox, display: flex is the first item on the agenda, so detecting it makes perfect sense. (It’s theoretically possible, though, that a browser fakes display: flex support in order to end up on the right side of some support detects. But as far as I know this is not the case today.)

On the other hand, if a browser has flaky support for, I don’t know, justify-content, a more precise check like this may or may not work, depending on how the CSS parser is written:


@supports (justify-content: space-around) {
	// may or may not fire correctly in case
	// of a browser bug

So this example is unsafe. Don’t use @supports for such detailed compatibility questions.