https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/
JoshWComeau
* Latest
* Posts
* Snippets
* Goodies
HomeTutorialsCSS
An Interactive Guide to Flexbox
Table of Contents
Introduction to FlexboxFlex directionAlignmentContent vs. items
Hypothetical sizeGrowing and shrinkingflex-basisflex-growflex-shrink
Preventing shrinkingThe minimum size gotchaGapsAuto marginsWrapping
You made it!Bonus: Unpacking the demo
Introduction
Flexbox is a remarkably powerful layout mode. When we truly
understand how it works, we can build dynamic layouts that respond
automatically, rearranging themselves as-needed.
For example, check this out:
Name:[ ]Email:[ ]Submit
Container width:600
[600 ]
Drag me!
This demo is heavily inspired by Adam Argyle's incredible "4 layouts
for the price of 1" codepen. It uses no media/container queries.
Instead of setting arbitrary breakpoints, it uses fluid principles to
create a layout that flows seamlessly.
Here's the relevant CSS:
css
I remember running into demos like this and being completely baffled.
I knew the basics of Flexbox, but this seemed like absolute wizardry!
In this blog post, I want to refine your mental model for Flexbox.
We'll build an intuition for how the Flexbox algorithm works, by
learning about each of these properties. Whether you're a CSS
beginner, or you've been using Flexbox for years, I bet you'll learn
quite a bit!
Let's do this!
Content warning
I make a food-related metaphor later in this tutorial.
Way better on desktop!
This tutorial features a ton of interactive demos, and some of these
demos just really don't work super great on smaller devices.
I've done my best to make them mobile-friendly, but for the best
experience, I recommend going through this tutorial on a desktop,
laptop, or tablet.
Link to this heading
Introduction to Flexbox
CSS is comprised of many different layout algorithms, known
officially as "layout modes". Each layout mode is its own little
sub-language within CSS. The default layout mode is Flow layout, but
we can opt in to Flexbox by changing the display property on the
parent container:
Hello
to
the
world!
Primary Axis
Primary Axis
display:
(*)block( )flex
When we flip display to flex, we create a "flex formatting context".
This means that, by default, all children will be positioned
according to the Flexbox layout algorithm.
Clippy, the helpful paperclip assistant from Microsoft WordEach
layout algorithm is designed to solve a specific problem. The default
"Flow" layout is meant to create digital documents; it's essentially
the Microsoft Word layout algorithm. Headings and paragraphs stack
vertically as blocks, while things like text, links, and images sit
inconspicuously within these blocks.
So, what problem does Flexbox solve? Flexbox is all about arranging a
group of items in a row or column, and giving us a ridiculous amount
of control over the distribution and alignment of those items. As the
name suggests, Flexbox is all about flexibility. We can control
whether items grow or shrink, how the extra space is distributed, and
more.
Is it still relevant?
You might be wondering: now that CSS Grid is well-supported in modern
browsers, isn't Flexbox obsolete?
CSS Grid is a wonderful layout mode, but it solves different problems
than Flexbox. We should learn both layout modes, and use the right
tool for the job.
Flexbox still reigns supreme when it comes to dynamic, fluid UIs that
arrange items in a vertical or horizontal list. We'll see an example
in this guide, the deconstructed pancake, that can't easily be
accomplished with CSS Grid.
Honestly, as someone comfortable with both CSS Grid and Flexbox, I
still find myself reaching for Flexbox quite often!
Link to this heading
Flex direction
As mentioned, Flexbox is all about controlling the distribution of
elements in a row or column. By default, items will stack
side-by-side in a row, but we can flip to a column with the
flex-direction property:
Show Primary Axis
Hello
to
the
world
Primary Axis
Primary Axis
flex-direction:
(*)row( )column
With flex-direction: row, the primary axis runs horizontally, from
left to right. When we flip to flex-direction: column, the primary
axis runs vertically, from top to bottom.
In Flexbox, everything is based on the primary axis. The algorithm
doesn't care about vertical/horizontal, or even rows/columns. All of
the rules are structured around this primary axis, and the cross axis
that runs perpendicularly.
This is pretty cool. When we learn the rules of Flexbox, we can
switch seamlessly from horizontal layouts to vertical ones. All of
the rules adapt automatically. This feature is unique to the Flexbox
layout mode.
The children will be positioned by default according to the following
2 rules:
1. Primary axis: Children will be bunched up at the start of the
container.
2. Cross axis: Children will stretch out to fill the entire
container.
Here's a quick visualization of these rules:
[flex-row][flex-colum]
In Flexbox, we decide whether the primary axis runs horizontally or
vertically. This is the root that all Flexbox calculations are pegged
to.
Link to this heading
Alignment
We can change how children are distributed along the primary axis
using the justify-content property:
Show Primary Axis
Hello
to
the
World
Primary Axis
Primary Axis
flex-direction:
[row ]
row
justify-content:
[flex-start ]
flex-start
When it comes to the primary axis, we don't generally think in terms
of aligning a single child. Instead, it's all about the distribution
of the group.
We can bunch all the items up in a particular spot (with flex-start,
center, and flex-end), or we can spread them apart (with
space-between, space-around, and space-evenly).
For the cross axis, things are a bit different. We use the
align-items property:
Show Primary Axis
Hello
to
the
World
Primary Axis
Primary Axis
flex-direction:
[row ]
row
justify-content:
[flex-start ]
flex-start
align-items:^New
[stretch ]
stretch
It's interesting... With align-items, we have some of the same options
as justify-content, but there isn't a perfect overlap.
justify-content
align-items
space-between
space-around
space-evenly
stretch
baseline
flex-start
center
flex-end
Why don't they share the same options? We'll unravel this mystery
shortly, but first, I need to share one more alignment property:
align-self.
Unlike justify-content and align-items, align-self is applied to the
child element, not the container. It allows us to change the
alignment of a specific child along the cross axis:
Show Primary Axis
Hello
to
the
world
Primary Axis
Primary Axis
flex-direction:
[row ]
row
align-self:
[stretch ]
stretch
align-self has all the same values as align-items. In fact, they
change the exact same thing. align-items is syntactic sugar, a
convenient shorthand that automatically sets the alignment on all the
children at once.
There is no justify-self*. To understand why not, we need to dig
deeper into the Flexbox algorithm.
Link to this heading
Content vs. items
So, based on what we've learned so far, Flexbox might seem pretty
arbitrary. Why is it justify-content and align-items, and not
justify-items, or align-content?
For that matter, why is there an align-self, but not a justify-self??
These questions get at one of the most important and misunderstood
things about Flexbox. To help me explain, I'd like to use a metaphor.
In Flexbox, items are distributed along the primary axis. By default,
they're nicely lined up, side-by-side. I can draw a straight
horizontal line that skewers all of the children, like a kebab?:
[][yH5BAEAAAA][]
The cross axis is different, though. A straight vertical line will
only ever intersect one of the children.
It's less like a kebab, and more like a group of cocktail wieners?:
[][yH5BAEAAAA][]
There's a significant difference here. With the cocktail wieners,
each item can move along its stick without interfering with any of
the other items:
[purple-too][purple-wie][purple-too][purple-wie]
[arrow]Drag me!
[green-toot][green-wien][green-toot][green-wien]
[red-toothp][red-wiener][red-toothp][red-wiener]
By contrast, with our primary axis skewering each sibling, a single
item can't move along its stick without bumping into its siblings!
Try dragging the middle piece side to side:
[souvlaki-s][souvlaki-1][souvlaki-1][souvlaki-2][souvlaki-2]
[souvlaki-3][souvlaki-3][souvlaki-s]
This is the fundamental difference between the primary/cross axis.
When we're talking about alignment in the cross axis, each item can
do whatever it wants. In the primary axis, though, we can only think
about how to distribute the group.
That's why there's no justify-self. What would it mean for that
middle piece to set justify-self: flex-start? There's already another
piece there!
With all of this context in mind, let's give a proper definition to
all 4 terms we've been talking about:
* justify -- to position something along the primary axis.
* align -- to position something along the cross axis.
* content -- a group of "stuff" that can be distributed.
* items -- single items that can be positioned individually.
And so: we have justify-content to control the distribution of the
group along the primary axis, and we have align-items to position
each item individually along the cross axis. These are the two main
properties we use to manage layout with Flexbox.
There's no justify-items for the same reason that there's no
justify-self; when it comes to the primary axis, we have to think of
the items as a group, as content that can be distributed.
What about align-content? Actually, this does exist within Flexbox!
We'll cover it a little later on, when we talk about the flex-wrap
property.
Link to this heading
Hypothetical size
Let's talk about one of the most eye-opening realizations I've had
about Flexbox.
Suppose I have the following CSS:
css
A reasonable person might look at this and say: "alright, so we'll
get an item that is 2000 pixels wide". But will that always be true?
Let's test it:
Code Playground
Format code using Prettier
Reset code
HTMLCSS
[
Result
Refresh results pane
[ ]
Enable 'tab' key
This is interesting, isn't it?
Both items have the exact same CSS applied. They each have width:
2000px. And yet, the first item is much wider than the second!
The difference is the layout mode. The first item is being rendered
using Flow layout, and in Flow layout, width is a hard constraint.
When we set width: 2000px, we'll get a 2000-pixel wide element, even
if it has to burst through the side of the viewport like the Kool-Aid
guy.
In Flexbox, however, the width property is implemented differently.
It's more of a suggestion than a hard constraint.
The specification has a name for this: the hypothetical size. It's
the size an element would be, in a perfect utopian world, with
nothing getting in the way.
Alas, things are rarely so simple. In this case, the limiting factor
is that the parent doesn't have room for a 2000px-wide child. And so,
the child's size is reduced so that it fits.
This is a core part of the Flexbox philosophy. Things are fluid and
flexible and can adjust to the constraints of the world.
Inputs for the algorithms
We tend to think of the CSS language as a collection of properties,
but I think that's the wrong mental model. As we've seen, the width
property behaves differently depending on the layout mode used!
Instead, I like to think of CSS as a collection of layout modes. Each
layout mode is an algorithm that can implement or redefine each CSS
property. We provide an algorithm with our CSS declarations (key/
value pairs), and the algorithm decides how to use them.
In other words, the CSS we write is an input for these algorithms,
like arguments passed to a function. If we want to truly feel
comfortable with CSS, it's not enough to learn the properties; we
have to learn how the algorithms use these properties.
This is the central philosophy taken by my course, CSS for JavaScript
Developers. Rather than have you memorize a bunch of inscrutable CSS
snippets, we pop the hood on the language and learn how all of the
layout modes work.
(Oh, and it's currently 50% off for Black Friday! )
Link to this heading
Growing and shrinking
So, we've seen that the Flexbox algorithm has some built-in
flexibility, with hypothetical sizes. But to really see how fluid
Flexbox can be, we need to talk about 3 properties: flex-grow,
flex-shrink, and flex-basis.
Let's look at each property.
Link to this heading
flex-basis
I admit it: for a long time, I didn't really understand what the deal
was with flex-basis.
To put it simply: In a Flex row, flex-basis does the same thing as
width. In a Flex column, flex-basis does the same thing as height.
As we've learned, everything in Flexbox is pegged to the primary/
cross axis. For example, justify-content will distribute the children
along the primary axis, and it works exactly the same way whether the
primary axis runs horizontally or vertically.
width and height don't follow this rule, though! width will always
affect the horizontal size. It doesn't suddenly become height when we
flip flex-direction from row to column.
And so, the Flexbox authors created a generic "size" property called
flex-basis. It's like width or height, but pegged to the primary axis
, like everything else. It allows us to set the hypothetical size of
an element in the primary-axis direction, regardless of whether
that's horizontal or vertical.
Give it a shot here. All 4 children have been given flex-basis: 50px,
but you can tweak the first child:
Show Primary Axis
Primary Axis
Primary Axis
flex-direction:
(*)row( )column
flex-basis:50
[50 ]
Like we saw with width, flex-basis is more of a suggestion than a
hard constraint. At a certain point, there just isn't enough space
for all of the elements to sit at their assigned size, and so they
have to compromise, in order to avoid an overflow.
Not exactly the same
In general, we can use width and flex-basis interchangeably in a Flex
row, but there are some exceptions. For example, the width property
affects replaced elements like images differently than flex-basis.
Also, width can reduce an item below its minimum size, while
flex-basis can't.
It's well outside the scope of this blog post, but I wanted to
mention it, because you may occasionally run into edge-cases where
the two properties have different effects.
Link to this heading
flex-grow
By default, elements in a Flex context will shrink down to their
minimum comfortable size along the primary axis. This often creates
extra space.
We can specify how that space should be consumed with the flex-grow
property:
0
Primary Axis
Primary Axis
flex-direction:
(*)row( )column
flex-grow:
(*)0 (default)( )1
The default value for flex-grow is 0, which means that growing is
opt-in. If we want a child to gobble up any extra space in the
container, we need to explicitly tell it so.
What if multiple children set flex-grow? In this case, the extra
space is divvied up between children, proportionally based on their
flex-grow value.
I think it'll be easier to explain visually. Try incrementing/
decrementing each child:
flex-grow:
1
2
Decrement
Increment
flex-grow:
1
2
Decrement
Increment
Primary Axis
Primary Axis
The first child wants 1 unit of extra space, while the second child
wants 1 unit. That means the total # of units is 2 (1 + 1). Each
child gets a proportional share of that extra space.
---------------------------------------------------------------------
Link to this heading
flex-shrink
In most of the examples we've seen so far, we've had extra space to
work with. But what if our children are too big for their container?
Let's test it. Try shrinking the container to see what happens:
flex-basis
300px
Reduced by:
0%
flex-basis
150px
Reduced by:
0%
Primary Axis
Primary Axis
Container width:600
[600 ]
Interesting, right? Both items shrink, but they shrink
proportionally. The first child is always 2x the width of the second
child.*
As a friendly reminder, flex-basis serves the same purpose as width.
We'll use flex-basis because it's conventional, but we'd get the
exact same result if we used width!
flex-basis and width set the elements' hypothetical size. The Flexbox
algorithm might shrink elements below this desired size, but by
default, they'll always scale together, preserving the ratio between
both elements.
Now, what if we don't want our elements to scale down proportionally?
That's where the flex-shrink property comes in.
Take a couple of minutes and poke at this demo. See if you can figure
out what's going on here. We'll explore below.
flex-basis
250px
flex-shrink
1
Reduced by:
0%
flex-basis
250px
flex-shrink
1
Reduced by:
0%
Primary Axis
Primary Axis
flex-shrink:1
[1 ]
Container width:600
[600 ]
---------------------------------------------------------------------
Alright, so: we have two children, each with a hypothetical size of
250px. The container needs to be at least 500px wide to contain these
children at their hypothetical size.
Let's suppose we shrink the container to 400px. Well, we can't stuff
500px worth of content into a 400px bag! We have a deficit of 100px.
Our elements will need to give up 100px total, in order for them to
fit.
The flex-shrink property lets us decide how that balance is paid.
Like flex-grow, it's a ratio. By default, both children have
flex-shrink: 1, and so each child pays 1/2 of the balance. They each
forfeit 50px, their actual size shrinking from 250px to 200px.
Now, let's suppose we crank that first child up to flex-shrink: 3:
[]Screenshot showing the demo above, locked at 400px wide, with the
first child having a flex-shrink of 3Screenshot showing the demo
above, locked at 400px wide, with the first child having a
flex-shrink of 3
We have a total deficit of 100px. Normally, each child would pay 1/2,
but because we've tinkered with flex-shrink, the first element winds
up paying 3/4 (75px), and the second element pays 1/4 (25px).
Note that the absolute values don't matter, it's all about the ratio.
If both children have flex-shrink: 1, each child will pay 1/2 of the
total deficit. If both children are cranked up to flex-shrink: 1000,
each child will pay 1000/2000 of the total deficit. Either way, it
works out to the same thing.
---------------------------------------------------------------------
I had an epiphany a while back about flex-shrink: we can think of it
as the "inverse" of flex-grow. They're two sides of the same coin:
* flex-grow controls how the extra space is distributed when the
items are smaller than their container.
* flex-shrink controls how space is removed when the items are
bigger than their container.
This means that only one of these properties can be active at once.
If there's extra space, flex-shrink has no effect, since the items
don't need to shrink. And if the children are too big for their
container, flex-grow has no effect, because there's no extra space to
divvy up.
I like to think of it as two separate realms. You're either on Earth,
or in the Upside Down?. Each world has its own rules.
Link to this heading
Preventing shrinking
Sometimes, we don't want some of our Flex children to shrink.
I notice this all the time with SVG icons and shapes. Let's look at a
simplified example:
When the container gets narrow, our two circles get squashed into
gross ovals. What if we want them to stay circular?
We can do this by setting flex-shrink: 0:
When we set flex-shrink to 0, we essentially "opt out" of the
shrinking process altogether. The Flexbox algorithm will treat
flex-basis (or width) as a hard minimum limit.
Here's the full code for this demo, if you're curious:
Flex Shrink ball demo
Format code using Prettier
Reset code
HTMLCSS
[
Result
Refresh results pane
[ ]
Enable 'tab' key
A simpler approach?
So, I teach this concept in my course, and every now and then,
someone will wonder why we're going through all the trouble of using
flex-shrink when there's a simpler approach available:
css
A few years ago, I would have agreed. If we set a minimum width, the
item won't be able to shrink below that point! We're adding a hard
constraint, instead of the soft constraint of width / flex-basis.
I think this is one of those situations where it's easy to confuse
"familiar" with "simple". You're probably much more comfortable with
min-width than flex-shrink, but that doesn't mean flex-shrink is more
complicated!
After a few years of practice, I actually feel like setting
flex-shrink: 0 is the more straightforward / direct solution to this
particular problem. Though, min-width still has an important role to
play in the Flexbox algorithm! We'll talk about that next.
Link to this heading
The minimum size gotcha
There's one more thing we need to talk about here, and it's super
important. It may be the single most helpful thing in this entire
article!
Let's suppose we're building a fluid search form for an e-commerce
store:
When the container shrinks below a certain point, the content
overflows!
But why?? flex-shrink has a default value of 1, and we haven't
removed it, so the search input should be able to shrink as much as
it needs to! Why is it refusing to shrink?
Here's the deal: In addition to the hypothetical size, there's
another important size that the Flexbox algorithm cares about: the
minimum size.
The Flexbox algorithm refuses to shrink a child below its minimum
size. The content will overflow rather than shrink further, no matter
how high we crank flex-shrink!
Text inputs have a default minimum size of 170px-200px (it varies
between browsers). That's the limitation we're running into above.
In other cases, the limiting factor might be the element's content.
For example, try resizing this container:
For an element containing text, the minimum width is the length of
the longest unbreakable string of characters.
Here's the good news: We can redefine the minimum size with the
min-width property.
By setting min-width: 0px directly on the Flex child, we tell the
Flexbox algorithm to overwrite the "built-in" minimum width. Because
we've set it to 0px, the element can shrink as much as necessary.
This same trick can work in Flex columns with the min-height property
(although the problem doesn't seem to come up as often).
Proceed with caution
It's worth noting that the built-in minimum size does serve a
purpose. It's meant to act as a guardrail, to prevent something even
worse from happening.
For example: when we apply min-width: 0px to our text-containing Flex
children, things break in an even worse way:
With great power comes great responsibility, and min-width is a
particularly powerful property when it comes to Flexbox. It's gotten
me out of a jam more than once, but I'm always careful to make sure
I'm not making things worse!
Link to this heading
Gaps
Property not supported
This section talks about the gap property. Unfortunately, the browser
you're using doesn't support this property. As a result, the demos in
this section won't display correctly.
One of the biggest Flexbox quality-of-life improvements in recent
years has been the gap property:
Primary Axis
Primary Axis
flex-direction:
(*)row( )column
gap:4px
[4 ]
gap allows us to create space in-between each Flex child, along the
primary axis. This is great for things like navigation headers:
HomeShopContact
Primary Axis
Primary Axis
justify-content:
( )flex-start(*)center( )flex-end
gap:16px
[16 ]
gap is a relatively new addition to the Flexbox language, but it's
been implemented across all modern browsers since early 2021.
Link to this heading
Auto margins
There's one other spacing-related trick I want to share. It's been
around since the early days of Flexbox, but it's relatively obscure,
and it blew my mind when I first discovered it.
The margin property is used to add space around a specific element.
In some layout modes, like Flow and Positioned, it can even be used
to center an element, with margin: auto.
Auto margins are much more interesting in Flexbox:
Primary Axis
Primary Axis
margin-left:
(*)0 (default)( )auto
margin-right:
(*)0 (default)( )auto
Earlier, we saw how the flex-grow property can gobble up any extra
space, applying it to a child.
Auto margins will gobble up the extra space, and apply it to the
element's margin. It gives us precise control over where to
distribute the extra space.
A common header layout features the logo on one side, and some
navigation links on the other side. Here's how we can build this
layout using auto margins:
Code Playground
Format code using Prettier
Reset code
HTMLCSS
[
Result
Refresh results pane
[ ]
Enable 'tab' key
The Corpatech logo is the first list item in the list. By giving it
margin-right: auto, we gather up all of the extra space, and force it
between the 1st and 2nd item.
We can see what's going on here using the browser devtools:
[]Screenshot showing the above playground with an orange rectangle
representing margin between the first item and the othersScreenshot
showing the above playground with an orange rectangle representing
margin between the first item and the others
There are lots of other ways we could have solved this problem: we
could have grouped the navigation links in their own Flex container,
or we could have grown the first list item with flex-grow. But
personally, I love the auto-margins solution. We're treating the
extra space as a resource, and deciding exactly where it should go.
Link to this heading
Wrapping
Phew! We've covered a lot of stuff so far. There's just one more big
takeaway I want to share.
So far, all of our items have sat side-by-side, in a single row/
column. The flex-wrap property allows us to change that.
Check it out:
flex-basis
180px
flex-basis
180px
flex-basis
180px
Primary Axis
Primary Axis
flex-wrap:
(*)nowrap (default)( )wrap
Container width:600
[600 ]
Most of the time when we work in two dimensions, we'll want to use
CSS Grid, but Flexbox + flex-wrap definitely has its uses! This
particular example showcases the "deconstructed pancake" layout,
where 3 items stack into an inverted pyramid on mid-sized screens.
When we set flex-wrap: wrap, items won't shrink below their
hypothetical size. At least, not when wrapping onto the next row/
column is an option!
But wait! What about our kebab / cocktail weenie metaphor??
With flex-wrap: wrap, we no longer have a single primary axis line
that can skewer each item. Effectively, each row acts as its own mini
flex container. Instead of 1 big skewer, each row gets its own
skewer:
[][yH5BAEAAAA][]
All of the rules we've learned so far continue to apply, within this
reduced scope. justify-content, for example, will distribute the two
pieces on each stick.
But hmm... How does align-items work, now that we have multiple rows?
The cross axis could intersect multiple items now!
Take a moment to consider. What do you think will happen when we
change this property? Once you have your answer (or at least an
idea), see if it's right:
Primary Axis
Primary Axis
align-items:
(*)flex-start( )center( )flex-end( )stretch
Each row is its own mini Flexbox environment. align-items will move
each item up or down within the invisible box that wraps around each
row.
But what if we want to align the rows themselves? We can do that with
the align-content property:
Primary Axis
Primary Axis
align-items:
[flex-start]
flex-start
align-content:
[flex-start ]
flex-start
To summarize what's happening here:
* flex-wrap: wrap gives us two rows of stuff.
* Within each row, align-items lets us slide each individual child
up or down
* Zooming out, however, we have these two rows within a single Flex
context! The cross axis will now intersect two rows, not one. And
so, we can't move the rows individually, we need to distribute
them as a group.
* Using our definitions from above, we're dealing with content, not
items. But we're also still talking about the cross axis! And so
the property we want is align-content.
Link to this heading
You made it!
So I want to acknowledge something: this has been a dense tutorial.
We've gone way down the rabbit hole, and unless you're already a
Flexbox pro, I expect your head is spinning a bit.
Like so much in CSS, Flexbox might seem simple when you first get
started, but the complexity ramps up quickly when you get beyond the
basics.
As a result, so many of us hit an early plateau with CSS. We know
enough to get things done, but it's a constant struggle. The language
feels rickety and unpredictable, like an ancient rope bridge that
could give out at any second. When it snaps, we hurl random
StackOverflow snippets at the problem, hoping something will help.
It's no fun. And that sucks, since CSS is a pretty big part of most
front-end dev jobs!
The thing is, CSS is actually a deeply robust and consistent
language. The problem is that most of our mental models are
incomplete and inaccurate. When we take the time to build a proper
intuition for the language, things start to click, and CSS becomes an
absolute joy to use.
Last year, I released a comprehensive course called CSS for
JavaScript Developers.
[css-for-js]
The course is "multi-modality", meaning that it uses lots of
different forms of media. I built my own course platform from
scratch, so that it supports:
* Interactive articles (like this blog post!)
* Videos (170+ short videos)
* Exercises
* Real-world-inspired projects
* Mini-games
If you found this blog post helpful, you'll love the course. It
follows a similar approach, but for the entire CSS language, and with
exercises and projects to make sure you're actually developing new
skills.
It's specifically built for folks who use a JS framework like React/
Angular/Vue. 80% of the course focuses on CSS fundamentals, but we
also see how to integrate those fundamentals into a modern JS
application, how to structure our CSS, stuff like that.
And right now, the course is a whopping 50% off for Black Friday!
CSS for JavaScript Developers
This is the first time the course has gone on sale since it launched
back in September 2021! I don't know when it'll go on sale next, but
it won't be anytime soon.
If you struggle with CSS, I hope you'll check it out. Gaining
confidence with CSS is game-changing, especially if you're already
comfortable with HTML and JS. When you complete the holy trinity, it
becomes so much easier to stay in flow, to truly enjoy developing web
applications.
Link to this heading
Bonus: Unpacking the demo
At the start of this tutorial, we saw the following "4 layouts for
the price of 1" demo:
Name:[ ]Email:[ ]Submit
Container width:600
[600 ]
Drag me!
Now that we've learned all about the Flexbox algorithm, can you
figure out how this works? Feel free to experiment with the code
here:
Code Playground
Format code using Prettier
Reset code
HTMLCSS
[
Result
Refresh results pane
[ ]
Enable 'tab' key
Let's walk through how this works:
Thanks so much for reading! This blog post was a ton of work, and I'm
thrilled to have it out in the world! I hope you found it useful.
---------------------------------------------------------------------
Last Updated
November 22nd, 2022
Hits
A front-end web development newsletter that sparks joy
My goal with this blog is to create helpful content for front-end web
devs, and my newsletter is no different! I'll let you know when I
publish new content, and I'll even share exclusive newsletter-only
content now and then.
No spam, unsubscribe at any time.
First Name
[ ]
Email
[ ]
Do you agree to the terms?
If you're a human, please ignore this field.
[ ]
Subscribe
JoshWComeau
Thanks for reading!
(c) 2020-present Joshua Comeau. All Rights Reserved.
Tutorials
ReactAnimationCSSCareerGatsbyNext.jsPerformanceJavaScript
Links
TwitterContactTerms of UsePrivacy Policy
(c) 2020-present Joshua Comeau. All Rights Reserved.