How To
Now Reading
How to Build CSS-only Smart Layouts with Flexbox
0

How to Build CSS-only Smart Layouts with Flexbox

by Irina papucMay 25, 2017

Flexible box, or Flexbox in short, is a set of properties in CSS introduced in 2009 to provide a new, exceptional layout system. The Flexbox module is identified as a part of the third version of CSS (CSS3).

You are probably already using many of the new properties in CSS3, such as box-shadow, border-radius, background gradients, and so on. However, Flexbox has yet to see the widespread adoption that it deserves. This may be because of all the breaking changes it has suffered over the years, or because it is only partially supported in Internet Explorer 10, or just because Flexbox is a whole ecosystem while previous paradigms have been predominantly based on single, ready-to-go properties.

It is super powerful and offers a wide range of options to achieve layouts that, previously, could only be dreamed of.

This article will walk you through the basics of Flexbox and how you can use it to achieve some really cool layouts which would otherwise require complicated CSS hacks or even JavaScript.

Why Use Flexbox?

By default, HTML block-level elements stack, so if you want to align them in a row, you need to rely on CSS properties like float, or manipulate the display property with table-ish or inline-block settings.

If you choose to use float (left or right), you must clear the wrapper at some point to push it until the very last floated element, otherwise, they will overflow over anything coming after. However, with float, you are limited to organizing elements horizontally.

Alternatively, or in addition, you can manipulate the display property to try to achieve the layout you desire! But this often feels kludgy at best, not to mention tedious, and often results in a fairly fragile layout that won’t necessarily render consistently across browsers. This approach is particularly ineffective if you are targeting multiple devices of varying sizes—which is almost always the case nowadays.

Enter Flexbox!

With a simple rule applied to a parent element, you can easily control the layout behavior of all of its children.

With Flexbox, you can:

  • Reverse the order of the elements inside a Flexbox parent.
  • Wrap child elements in columns (number of columns can vary depending on child and parent height).
  • Specify the rate at which elements grow or shrink while the viewport size changes.
  • Control whether elements are shrinkable or not, regardless of the specified width unit type (relative or absolute).
  • Change the order of elements with CSS (combine this with media queries and you will find limitless possibilities in your flow).
  • Generate complex distributions of the elements to be equidistant with space around or just space between.
  • Generate “renegade” elements that flow differently (everyone to the left but one to the right, top/bottom… it’s your call).
  • And, most importantly, avoid the clear-fix hack for good!

I understand Flexbox can be tough in the beginning. I think it is easier to learn ten unrelated CSS properties than five with some inter-dependency. However, with your current CSS skills, and maybe a little help from this article, you will launch yourself into a new CSS universe.

The Basics of Flexbox

Display

Display

display is one of the most basic properties in CSS and is quite important in the context of Flexbox, as it is used to define a flex wrapper.

There are two possible flex wrapper values: flex and inline-flex.

The difference between the two is that a display: flex wrapper acts like a block element while a display: inline-flex wrapper acts like an inline-block. Also, inline-flex elements grow if there is not enough space to contain the children. But other than those differences, the behavior of the two would be the same.

Try the sample code below, reduce the viewport width when inline-flex is active and… scroll.

.wrapper {
    display: flex || inline-flex;
}

Flex Direction

Flex Direction

Now that you have seen the first sample, you can infer that the default behavior is to simply make a row of the elements. But there is more:

  • row (default): Arranges the elements from left to right (but if RTL is set it would be backward).
  • row-reverse: Reverses the order of elements in a row disposition
  • column: Arranges the elements from top to bottom
  • column-reverse: Reverses the orders of elements in a column disposition

Hint: The column and column-reverse values can be used to swap the axes, so the properties that would affect the horizontal axis would affect the vertical axis instead.

.wrapper {
    flex-direction: row || row-reverse || column || column-reverse;
}

Flex Wrap

If you check the first code sample, you’ll figure out that the child elements don’t stack by default within a flex wrapper. This is where flex-wrap comes into play:

  • nowrap (default): Prevents the items in a flex container from wrapping
  • wrap: Wraps items as needed into multiple rows (or columns, depending on flex-direction)
  • wrap-reverse: Just like wrap, but the number of rows (or columns) grows in the opposite direction as items are wrapped
.wrapper {
    flex-direction: nowrap || wrap || wrap-reverse;
}

You can combine flex-direction and flex-wrap properties into a single property: flex-flow.

.wrapper {
    flex-flow: {flex-direction} {flex-wrap};
}

Justify Content

Justify Content

This property is used to control the horizontal alignment of the child elements:

  • flex-start (default): Elements are aligned to the left (similar to inline elements with text-align: left)
  • flex-end: Elements are aligned to the right (similar to inline elements with text-align: right)
  • center: Elements are centered (similar to inline elements with text-align: center)
  • space-around (where the magic begins): Every element will be rendered with the same amount of space around each item. Note that the space between two sequential child elements will be double the space between the outermost elements and the sides of the wrapper.
  • space-between: Just like space-around, except the elements will be separated by the same distance and there will be no space near either edge of the wrapper.

Note: Remember flex-direction, when set to column or column-reverse, swaps the axis. If one of these is set, justify-content will affect vertical alignment, not horizontal.

Align Items

Align Items

This property is similar to justify-content but the context of its effects is the rows instead of the wrapper itself:

  • flex-start: Elements are vertically aligned to the top of the wrapper.
  • flex-end: Elements are vertically aligned to the bottom of the wrapper.
  • center: Elements are centered vertically within the wrapper (at last, a safe practice to achieve this).
  • stretch (default): Forces the elements to occupy the full height (when applied to a row) and the full width (when applied to a column) of the wrapper.
  • baseline: Vertically aligns the elements to their actual baselines.

Align Content

Align Content

This property is similar to justify-content and align-items but it works in the vertical axis and the context is the entire wrapper (not the row like the previous example). To see its effects, you will need more than one row:

  • flex-start: Rows are vertically aligned to the top (i.e., stacked from the top of the wrapper).
  • flex-end: Rows are vertically aligned to the bottom (i.e., stacked from the bottom of the wrapper).
  • center: Rows are centered in the wrapper vertically.
  • stretch (default): In general, this property stretches the elements to utilize the entire vertical height of the wrapper. However, if you have set some specific height of the elements, that height will be honored and the remaining vertical space (in that row, below that element) will be empty.
  • space-around: Every row will be rendered with the same amount of space around itself vertically (i.e., below and above itself). Note that the space between two rows will, therefore, be double the space between the top and bottom rows and the edges of the wrapper.
  • space-between: Just like space-around, except the elements will be separated by the same distance and there will be no space on the top and bottom edges of the wrapper.

Flex Grow

Flex Grow

This property sets the relative proportion of the available space that the element should be using. The value should be an integer, where 0 is the default.

Let’s say you have two different elements into the same flex wrapper. If both have a flex-grow value of 1, they will grow equally to share the available space. But if one a flex-grow value of 1 and the other a flex-grow value of 2, as shown in the example below, this one with a flex-grow value of 2 will grow to take twice as much space as the first.

.wrapper .elements {
    flex-grow: 1; /* Default 0 */
}
.wrapper .elements:first-child {
    flex-grow: 2;
}

Flex Shrink

Similar to flex-grow, this property sets whether the element is “shrinkable” or not with an integer value. Similar to flex-grow, flex-shrink specifies the shrink factor of a flex item.

.wrapper .element {
    flex-shrink: 1; /* Default 0 */
}

Flex Basis

This property is used to define the initial size of an element before available space is distributed and elements are adjusted accordingly.

Hint: flex-basis does not support calc() and box-sizing: border-box in every browser, so I recommend using width if you need to use one of these (note that you will also need to set flex-basis: auto;).

.wrapper .element {
    flex-basis: size || auto; /* Default auto */
}

Flex Flow

You can combine flex-grow, flex-shrink, and flex-basis properties into a single property: flex-flow as follows:

.wrapper {
    flex-flow: {flex-grow} {flex-shrink} {flex-basis};
}

Hint: If you plan to use flex-flow, make sure to define every single value (even if you want to use default values) because some browsers might not recognize them (a common bug is related to not having defined the flex-grow value).

Align Self

Align Self

This property is similar to align-items but the effect is applied individually to each element. The possible values are:

  • flex-start: Vertically aligns the element to the top of the wrapper.
  • flex-end: Vertically aligns the element to the bottom of the wrapper.
  • center: Vertically centers the element within the wrapper (at last a simple way to achieve this!).
  • stretch (default): Stretches the element to occupy the full height of the wrapper (when applied to a row) or the full width of the wrapper (when applied to a column).
  • baseline: Aligns the elements according to their actual baselines.

Order

Order

One of the best things included in Flexbox is the ability to reorder elements (using the order property) without needing to modify the DOM or use JavaScript. The way the order property works is super simple. In much the same way that z-index controls the order in which items are rendered, order controls the order in which elements are positioned within the wrapper; that is, elements with a lower order value (which can even be negative, by the way) are positioned before those with a higher order value.

.wrapper .elements {
    order: 1;   /* this one will be positioned second */
}
.wrapper .elements:last-child {
    order: -1;   /* this one will be positioned first */
}

Pulling it All Together: Example Uses of Flexbox

When it comes to designing layouts, Flexbox unleashes a world of possibilities. Below, you can find some example uses of Flexbox properties.

Vertical Alignment Component

With Flexbox, you can align anything vertically, including multiple elements at once. Without Flexbox, you needed to use positioning or table-ish techniques that required us to create one child to contain multiple elements. But with Flexbox, you can leave these tedious and fragile techniques behind, and simply define a few properties in the wrapper and that’s it, regardless of how many times the content inside the container changes or the type of change!

.wrapper {
    display: flex; /* always present for Flexbox practices */
    flex-direction: column; /* elements stack */
    justify-content: center; /* now that flex-direction is a column, the axis are swapped so this centers the content vertically */
    min-height: 100vh /* make sure wrapper is taller enough */
}

Half/half Layout

A “half/half” layout is a full height layout with two columns, each with its content centered vertically. It is usually implemented “above the fold” (i.e., before users have scrolled down after page loads).

Using more traditional techniques, you could create this layout with floated elements (of width 50% each), clearing the floats into the wrapper (“clearfix” :before and :after, overflow: hidden, or a whacky <div> with clear: both; in the end). Yet it is a lot of work and the result is not as stable as what Flexbox provides.

In the following code snippet, you will see how easy it is to set the layout and also how the children become also Flexbox wrappers since everything is vertically aligned as well.

Outer wrapper:

.wrapper {
    display: flex;
    flex-direction: column; /* only for mobile */
}

Inner wrappers:

.inner-wrapper {
    flex-grow: 1; /* Allow the element to grow if there is available space */
    flex-shrink:  1; /* Elements shrink at the same rate */
    flex-basis:  100%; /* Elements will cover the same amount, if is possible the 100% of the width */
}

Full-width Navbar Buttons

A full-width navbar distributes the space equally in the same row of navbar items regardless of the number of elements.

In the sample below, there are also are some iconic buttons without this behavior, demonstrating that you can combine the two in any way you want. Without Flexbox, achieving these sorts of layouts would have required JavaScript code to calculate the available space and then distribute it programmatically depending on which buttons span and which don’t.

Flexbox makes this much simpler.

Wrapper properties:

.navbar {
    display: flex;
}

Spanning child properties:

.navbar-item {
    flex-grow: 1; /* They will grow */
}

Non-spanning child properties:

.navbar-other {
    flex-grow: 0; // They won’t grow
}

Blurbs

How many times did you have to implement a set of information boxes with icons and text in different projects?

This distribution of elements is mostly useful in digital marketing but can have some other uses in software development. With the power of Flexbox, you can set a sort of grid and also align elements regardless of how many there are.

Wrapper properties:

.wrapper {
    display: flex;
    flex-wrap: wrap;
}

Child properties:

.blurb {
    flex-grow: 0; /* elements don’t grow */
    flex-shrink: 0; /* elements don’t shrink in a flexible way */
    flex-basis: auto; /* the width of the elements will be set by proportions in `width` due to flex-basis not support workaround */
    width: calc(33.33% - 60px); /* calculate proportional width without space taken by padding (workaround for IE 11) */
}

For tablet and mobile viewports, the width varies between 50% and 100%.

Enhancing Cross-browser Compatibility

The syntax for Flexbox has changed numerous times across different browser versions. This can be an issue when implementing a layout with Flexbox and trying to support older web browsers, especially older versions of Internet Explorer.

Fortunately, many techniques and workarounds for getting your code to work across the widest range of web browsers are listed in Flexbugs, which is a great resource. If you follow the information on that site, you will have better, consistent results across different web browsers.

Prefix tasks are particularly useful in this regard. To automate prefixing of CSS rules, you can pick one of the following tools:

Ruby:

Node.js:

Start Building Smart Layouts

Flexbox is a great tool to speed, polish, and scale our work. The limit is only in the imagination of the developer.

If you need some visual aid to plan your next layout you can try this neat playground:

Open it in a new window.

With increasing adoption of modern web browsers by a majority of users, using Flexbox will allow you to create amazing layouts easily without the need to delve into messy JavaScript code or craft kludgy CSS.

This article is originally posted in Toptal.

What's your reaction?
Love It
0%
Interested
0%
Meh...
0%
What?
0%
Hate It
0%
Sad
0%
About The Author
Irina papuc