Useful Flexbox Tricks and Tips
Flexbox is a CSS spec that has been around for a few years now, but it continues to be one that people seem to struggle with. There are a few things that I think trip people up, and hopefully I can provide some resources and examples that will make it easier to understand. Let's dive in!
First things first, there are a couple of resources that are worth their weight in gold for learning flexbox. The first is CSS Tricks' Complete Guide to Flexbox. I can't tell you how many times I have gone back to this post. It does an excellent job visualizing the way the different flex properties affect the layout. I honestly think that I understand flexbox so well because I basically memorized this article due to the sheer number of times I visited it.
The second resource is an interactive game called Flexbox Froggy. It's a fun way to solve increasingly more challenging puzzles using flexbox to place frogs onto their lily pads.
Lastly, if you don't mind a shameless plug, I wrote a little web app that allows you to play around with flexbox layouts. You can also view the HTML and CSS required to generate the layout you build, so it can be pretty handy if you need to troubleshoot a flex layout issue. Check it out here. Note: the app is not mobile-friendly. PR's welcome!
Another thing that seems to be a stumbling block is when to actually use flex for layouts. Especially now that the browser support for CSS Grid is pretty solid, many use cases for flex are much better suited for using Grid. The rest of this post will cover some use cases for flex.
Inline Forms and Input Addons
The first handy use case for flex is inline forms and input addons. For inline forms, you can use flexbox with the
align-items: stretch property and all items in the row will be the same height. This means you can set the height on the container and not worry about setting the height on any of the items. This can be very helpful to prevent having to deal with making sure
heights, etc. all play nicely to ensure all items in your inline forms are the same height. Here's an example:
<input type="text" class="inline-form--input" />
Everything in that
.inline-form container will be
2rem tall, no matter what. Pretty handy!
The second use case here is for input addon items. Consider an input field for currency, where you want the currency prepended to the input field. It's also typical to use a
span with a search icon appended to an input that searches the site. You want the addon to occupy as much space as it needs, and have the input fill the remaining space fluidly. That's possible with a hack using
display: table-cell and a
width property on the input, but that also has limitations. Because you might not know the exact width of what will be in your input addon, you don't want to set a fixed width (imagine some dynamic text being put in there, like someone's first name, or a month of the year). Flexbox makes this trivial. We also get the same benefit from the inline-form where the input field and the addon item will automagically be the same height.
<input type="text" class="input-addon--input" />
Now, no matter what content is in our addon item, the input will fill the remaining space in the container! Super helpful.
Check out this Codepen example of these solutions.
<!-- this content is what should fill all available space -->
In this situation, we use a
vh unit to make the body fill at minimum 100% of the height of the viewport. This way if the content doesn't cause the footer to be at the bottom, the
flex: 1 on the
main tag will force it to grow until the body fills 100%. Again, if you can use CSS Grid, that's probably a better solution, but this works really well too.
Vertically Centering Items
This one is probably the best use for flexbox. Previously, centering something vertically within its container was impossible unless you knew the height of the container and the element. Flexbox makes it dead simple. It also makes it easy to center vertically AND horizontally, if you need that too.
align-items: center; /* vertically centers item */
justify-content: center; /* horizontally centers item */
That's it! No matter what you put in the
container, it will be vertically and horizontally centered. How easy!
Independent justify-content behavior
Imagine this scenario: you have a line item where you want everything to be flexed with
justify-content: flex-start so it aligns at the beginning of the container (left side). But you just have one item (the last one) that you want pushed all the way to the right. You could create an extra layer of
divs and use
justify-content: space-between, but that's not ideal. There is a much better way:
margin: auto. It's a lesser known feature of the spec, but it is definitely intentional. What happens is that flex allocates any positive free space to the auto margins, and so if you wanted to push the last item all the way to the right, you would add
margin-left: auto to it.
<a class="right">Log Out</a>
This can be handy for things like a logout link in a nav menu, a close icon on a card header, etc. - I keep finding excellent use cases for this trick when I build apps!
Flexbox makes it pretty simple to space any number of items equally across an axis. If you have a list of tabs for navigation, and you want to implement this pattern, flexbox is a great solution. Here's the code:
flex: 1 1 0px;
The difference here between what we have been doing in other examples is that instead of using the shorthand for
flex: 1, we are explicitly defining the
flex-basis properties. The important ones here are
flex-basis. In the shorthand
flex: 1, the
flex-basis is set to
auto, which makes the item have an initial width of whatever the size of the content within it is. More than likely, your tab titles will not all be the same length, so you'd end up with unequal tab widths. By setting the initial width (
0px, and telling them all to grow equally, we ensure that each tab ends up taking up the same amount of space across the tabs container. Easy peasy!