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:
- All items have an order of zero by default
- You can set any integer as the order; this includes negative numbers
- Lower numbers are rendered first
- In cases of a tie, then items are rendered in source 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!
Comments for Flex Items