Flex Items

In the last drip, we looked at flexbox and the flexbox container rules. Today we are going to look at the properties you can use on the children of a flex container, known as flex items. These properties allow you to set order and override group settings.

We'll start by using the same basic page we were using yesterday. It's just a list of divs in a main container. I've brought the individual classes over that we use to target each item specifically. For styles, I'll also keep with what we created before, and there is nothing unexpected there.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Flexbox</title>
    <link rel="stylesheet" href="normalize.css" type="text/css">
    <link rel="stylesheet" href="typebase.css" type="text/css">
    <link rel="stylesheet" href="style.css" type="text/css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <header>
      <h1>Flexbox</h1>
    </header>
    <main>
      <div class="one">1</div>
      <div class="two">2</div>
      <div class="three">3</div>
      <div class="four">4</div>
      <div class="five">5</div>
      <div class="six">6</div>
      <div class="seven">7</div>
      <div class="eight">8</div>
      <div class="nine">9</div>
      <div class="ten">10</div>
    </main>
  </body>
</html>
header {
  text-align: center;
  margin: 1rem;
}

main {
  background: lightblue;
  margin: 1rem;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-around;
  align-items: center;
  height: 20em;
}

main > div {
  width: 5rem;
  text-align: center;
  margin: .1rem;
}

div {
  background: yellow;
}

order

The order property lets you set what order each block is rendered in. This is great, because it means you can do things like render a menu later, but have it appear first in the code. This makes accessibility tasks much easier to tackle, and source order really matters for people using screen readers. There are a handful of things to know about order:

Let's look at a rebellious example where we make our first item last and our last item first. Just by adding an order value of -1 to ten and 1 to one, we've got them rendering that way. Easy right? Flexbox is pretty sweet.

div.ten {
  order: -1;
}

div.one {
  order: 1;
}

align-self

I use align-self constantly. It's a great way to get items positioned in just the right place without having to mess with nested position absolute/relative type approaches. Also this directive overwrites any settings from the flex container, so you can set a default for the group while having certain items be exceptions. aligns-self accepts all the same parameters as align-items, so I won't go through them again. For a quick example, lets override our current setting of center for a single item, and move div five to flex-end.

div.five {
  align-self: flex-end;
}

This puts five at the bottom of the current row (flex-end in this case) thus overwriting the group setting of center.

flex-grow

So what if you want some items take up more space than others, but stretch and maintain roughly that ratio as the screen size changes? This happens a lot with multi column layouts, and inside of components with large buttons or inputs. flex-grow is the easy way to accomplish this. Flex items have a default flex grow of zero, meaning they won't grow by default. Giving an item a 1 value lets it take up the rest of the available space.

div.two, div.nine {
  background: lightyellow;
  flex-grow: 1;
}

Checkout how divs two and nine stretch and work with the flex wrap setting. To get your ratios dialed in, remember that you can set flex-grow to any positive float, not just whole-numbered integers. We'll look more into how this is calculated in a moment.

flex-shrink

If you have a fixed width box, and need some items to shrink, then flex-shrink is a great option. I'll need to remove the flex-wrap before showing this one, otherwise they'll just go to the next line and not shrink.

main {
  /* snip */
  /*flex-wrap: wrap;*/
}

div.two, div.nine {
  /* snip */
  flex-shrink: 2;
}

You can see boxes two and nine shrinking, while the rest remain their proper size. If you ever need to stop a component from shrinking, setting its flex-shrink to zero will do just that. Let's revert this before moving on.

flex-basis

To set the initial size of a flex item use flex-basis. Width is actually a fall back for for this setting, so its best to just use flex-basis. Min and max width will still be respected when set, however. Note that flex basis just sets the initial width. Flex will change the size of the item unless you lock it in with both flex-shrink and flex-grow.

There are a lot of options you can pass as a value to flex-basis. The main one that is actively used is a width measurement (so any px, rem etc will work). There are other values, including content, max-content, min-content, fit-content, and stretch. These use the intrinsic value of the existing content, and support can be spotty on these. I suggest avoiding these entirely. If you do need them, MDN has docs and be sure to check the browser support.

main > div {
  /* snip */
  /* width: 5rem; removing this! */
  flex-basis: 5rem;
}
div.one {
  /* snip */
  flex-basis: 50%;
}

You can see we have replaced our width with the flex-basis property, and as we scale the page the width is recalculated to match the given row.

How flex-shrink and flex-grow use flex-basis

Now that we have an understanding of flex-shrink, flex-grow, and flex-basis, we can talk about how the underlying calculations are done. A simplified version of this is that the browser takes the total linear length availible, subtracts all the flex items' flex-basis (along with their margins, etc) and gets a remaining space. If this number is positive, it's passed to flex grow, and the total flex-grow number is summed from all flex items, the remaining space is divided by that sum, then portioned out to each item by multiplying by its flex-grow value. The same type of process is used if the remaining space is negative, only the flex item size is reduced by the result of that multiple.

This is why setting an item's grow and shrink values to zero locks in its size: the multiplied adjustment will always be zero.

Shorthand

I am often not a fan of CSS shorthand, as I think it does a poor job of communicating intent to future developers. Flexbox is in a slightly different situation. The spec actually recomends you use the shorthand, as it sets some reasonable defaults for you.

flex-flow

The first shorthand is for the flex contianer: flex-flow. You can pass two options to it. The first option is row, column, or the reverse version of either. The second option is the flex-wrap setting of either wrap or nowrap.

main {
  /* snip */
  /* flex-direction: row; remove this */
  /* flex-wrap: wrap; remove this */
  flex-flow: row wrap;
}

You can see when I replace my current CSS with the shorthand, we don't have any changes. This is exactly as exspected, yay!

flex

The second shorthand option in flexbox is for flex items, and it combines flex-grow, flex-shrink and flex-basis all into a single command of flex.

If you just send a single value to flex it's rendered as the flex-basis. Two values are flex-grow and flex-shrink, while three values are flex-grow flex-shrink and flex-basis. I think think this is quite confusing to parse, So I typically just send either one or three values when I call flex.

main > div {
  /* snip */
  flex: 5rem;
}

Vertical Centering

One more thing today: vertical centering. This used to be a giant pain, but flexbox has made it really easy. Let's take the simplest possible example:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Flexbox</title>
    <link rel="stylesheet" href="normalize.css" type="text/css">
    <link rel="stylesheet" href="style.css" type="text/css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <main>
      <h1>Flexbox</h1>
    </main>
  </body>
</html>
main {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

The height is 100% of the viewport height vh, then we use both align-items and justify-content as centered. Vertical centering is that easy, and it responsively works on any screen size without any math or further intervention.

Summary

In this drip, we looked into the rules around flex items, and saw how easy it is to center content with flexbox. We examined how to manage size of flex items and how to override placement of individual items. We also looked into shorthand and an easy way to use flexbox to center content. Tomorrow we'll be examining real world usages of flexbox. See you then!

Resources

Adam Dill

Adam has over 19 years of software development experience, and has spent a good part of that educating new developers. He was previously CTO at inside.com and Development Director at Maxmedia . When Adam isn't coding, he is off hiking in Colorado mountains, or practicing some pretty fly martial arts. He thinks swords are cool.

You May Also Like