I will teach you how to use flexbox in practice --- code included.
Here's a screenshot of the final product we are going to build, step-by-step.
This was developed in Chrome without browser prefixes, so check your browser support at Caniuse.com. Unless you need to support IE<11 or Safari<8, you'll need no browser prefixes at all. If you need support for older browsers, use autoprefixers in your workflow and make workarounds for bugs listed at Flexbugs. You can also use @supports media query for achieving fallbacks for Firefox, Chrome, and Opera. Also, it's possible to use Modernizr to detect when you need a fallback with flexbox.
Flexbox is a W3C Candidate Recommendation from 26th of May 2016.
The basic DOM structure for all flexbox cases is as follows:
<section class="parent"> <section class="item"></section> <section class="item"></section> <section class="item"></section> </section>
We have a parent element, which holds all the items, which will be flexed. Flexbox only affects the direct children of parent.
When you need vertically aligned items, use
flex-direction: column --- for horizontal layouts, use
It all starts with...
What this does is align the items of the parent in a row. I've attached JSBin's about the progress.
Okay, so now we have block-level elements side-by-side. Now this is pretty bare-bones, so let's add some more challenging content to the DOM.
Wrapping the products row
Let's make the elements flow on next row by adding the rule
flex-wrap: wrap to the parent. Hooray! We have a responsive (ish) design.
The layout isn't exactly optimal yet, so let's make the items fill the width on screen in a more sane way: Always fill 100% of the width, and use equal sizes for the items.
Filling whole screen area
flex-grow: 1 to let the items fill the width equally.
text-align: center to center all content inside each product. I also added some basic styling, including my favourite font: Titillium Web.
Let's vary the content lengths a bit, since these are usually edited in administration by our customers. Wow, what the hell is going on here? How can we keep the items equal size?
Making elements equal size
flex-basis: 0 to the flexbox in order to prevent the extra space around content. Let's use the shorthand version, just type:
flex: 1 1 0 (this is shorthand for flex-grow, flex-shrink and flex-basis combined).
So we have now written a responsive grid in just 4 CSS rules... Amazing!
The long h1's are causing the images to misalign horizontally. There isn't exactly one way to solve this --- it's partly an editorial issue. All we can do is to optimize our layout for specific content lengths. Let's make our lives a bit easier by moving the product images as first element of each item.
Let's complicate the DOM a bit:
- Add to cart button with icon
- List of specs
Also, let's add basic styling for those elements.
Adding complexity to the layout
In order to use the flexbox-magic for each product, let's tell them to
display: flex as well. But this time we want to keep them on top of each other, so let's add
flex-direction: column to them as well. Add
align-items: center to make each direct DOM children of a product to align themselves on center.
Let's set the product spec (ul) to display as flex as well (surprise!). In order to justify the two li's at the and the beginning of the row, let's add
margin-top: auto to aside element to magically keep the buttons and specs at the bottom.
Now we have a pretty neat layout --- Check it out! I added some responsiveness to the image sizes with media queries.
Handling last items
The last items seem to behave erroneously (or at least we're not used to this on layouts). Let's add
max-width: 400px to flex items --- now this is the same as the width of the image. I've also added a media query to change the max-width to 250px on below 1600px wide screens, but this is just a responsiveness trickery due to image resizing. I chose to add max-width instead of width so my boxes' size (paddings and margins) will remain fixed.
Because of the max-width, we need to define a
justify-content for the parent .flex. The value depends on your personal opinion. I chose to center the parent's items as it seems like a logical way. Be sure to try out
space-around for this!
I couldn't help myself to improve the colors and typography. I also added a flexbox navbar!
The Source Code
Here's all the code for the flexbox-related stuff (everything else was just candy sprinkled on top of them).
and the HTML:
In no means this is a complete solution, there's still some flexbox quirks you need to fix / make workarounds for. For example, what should we do with the last items? ...Anyways I've fallen in love with flexbox. Especially
align-items which solve common problems, such as aligning grouped header items: brand, navigation and search with
justify-content: space-between. The syntax is pretty awesome too, and you can avoid the float bloat and position inquisition. One neat tip is to use a media query for screen widths and convert flex-rows to cols to make the site responsive really easily. This goes especially with React.js --- you can use componentized flexbox and ensure browser support with autoprefixers.
The easiest way to get started with flexbox is probably
Bennett Feely's Flexplorer.
- For more practical flexbox solutions, I suggest to check out Zoe Mickley Gillenwater's Enhancing Responsiveness /w Flexbox.
- If you're more reading, check out this book: Hardboiled Web Design.
I haven't used flexbox extensively, but I've noticed a pattern where your UI has rows and cols alternating --- This happened to the product page as well.
Flexbox isn't meant for whole page layouts --- There's an upcoming standard called CSS Grid. A W3C Candidate Recommendation was released on 29th of September, 2016.
CSS is evolving all the time --- So let us evolve on how we solve common UI design patterns.