Positioning in CSS can be a nightmare, especially when you want to make all your pages responsive and look pretty on phones, tablets, laptops, and bigger screens. If we wanted to create layouts for an entire page, one option is to use a grid like Bootstrap. But what if we wanted to create layouts for something smaller, like items in a component?

As part of the WebDev team, I worked on several components that were used by editors in our CMS to create content for the Hootsuite website. This meant I was given a design of a component that was to be used, and it was my job to create it, considering responsiveness, translations, and content variability at all times. I was fairly comfortable with using the basics of CSS, and the transition to using SCSS at Hootsuite didn’t turn out to be a huge challenge either. What I struggled with the most was positioning – even tasks that seemed to be easy didn’t end up being as easy as they appeared.

Pre-Flexbox: Absolute Positioning

Let’s take a simple situation as an example: vertically centering something. Besides the horrendous idea of hard-coding the pixel values, a neat trick that would do the job would be to use absolute positioning:

See the Pen Vertical Centering – Absolute Positioning by Jieun Lee (@jieun-lee) on CodePen.

This isn’t a terrible idea, since it accomplishes the task with a few lines of code and is also fairly responsive, as the object would be centered at different screen sizes as well. However, it’s not the best solution, as it makes code overly complicated when we get to more complex situations, such as when using nested components and handling varying designs for different screen sizes. I kept thinking that there had to be a better way to approach these problems, and it turned out the solution I was looking for was flexbox.

The Transition to Using Flexbox

During a code review, one of my teammates suggested using flexbox to refactor my component. At first, it seemed like a lot of work because I would have to rewrite a lot of CSS after I spent a lot of time getting all the images and content to align nicely using absolute positioning. However, after a quick reading of flexbox from some articles I found online, it didn’t seem so bad. In fact, it seemed to make the tasks that should have been easy actually easy.

After some thought, I decided to start fresh with a blank CSS file – I literally scrapped all the CSS I had and re-wrote everything using flexbox. It was amazing to see how quickly I was able to re-create the component, and my file went from 150 lines to 100 lines. Refactoring was definitely worth it – of course, it did take a bit more time to redo the component, but it took much less time to implement and my code was shorter, cleaner, and easier to read and manage.

So let’s go back to that vertical centering problem. This is the same scenario created using flexbox:

See the Pen Vertical Centering – Flexbox by Jieun Lee (@jieun-lee) on CodePen.

All we had to do was apply display: flex; then set the vertical margin to auto. This was a much easier and more flexible solution.

Flexbox Layouts with an Example

There are many resources out there that explains the fundamentals of flexbox and its basic properties, so instead of being repetitive I will show you a sample layout built with flexbox and break it down into parts of how it was created. Let’s say we’re trying to make something like this:

See the Pen Flexbox Example – Final by Jieun Lee (@jieun-lee) on CodePen.

It’s a basic usage example, but it contains several usages of flexbox:

  • Overall Layout: the sidebar and main section are in a wrapper div, and the wrapper and header are in a page div
  • Header: the box that contains the title is flexible and fills the space that isn’t filled up by the circular buttons on the right
  • Sidebar: the menu items are spaced apart evenly from one another (this might look ugly on mobile, normally we wouldn’t keep the menu as a sidebar on smaller screens)
  • Main: contains three streams, evenly spaced, with each stream containing multiple text boxes with varying lengths (two streams on smaller screen sizes; this would normally be styled nicer on real components)

NOTE: If you’re not familiar with SCSS, part of the syntax may be confusing, so here’s a short guide to the SCSS syntax that you’ll encounter in my code:

  • Using variables, named using the dollar sign
  • (ex) $menu-color: #333;

  • Using nesting with ampersands (the ‘&’ replaces the parent in this case)
  • (ex) .header { &__main { //css }} would compile out to .header__main { //css }

Making the Menu Items Space Evenly on the Sidebar

Making items space evenly is easy with flexbox; simply use flexbox by adding display: flex; to the flex container and set margin: auto; to the flex items. This is the same technique we used to center a single item. Try changing the height to verify that it is flexible and evenly spaced at various height settings.

See the Pen Flexbox Example – Sidebar by Jieun Lee (@jieun-lee) on CodePen.

Splitting the Main Section into Streams

This is actually pretty simple, since all three streams (two, if you’re on mobile) have the same width, height, and flex properties. We will be able to see the desired behavior as soon as we add display: flex; and flex-direction: row;. However, the underlying property that makes this all work is set on the flex items (the streams).

In the code below, I have explicitly included flex: 0 1 auto; which is the default value in most modern browsers. The values represent flex-grow, flex-shrink, and flex-basis, respectively. None of the streams will grow larger than the specified width (flex-grow: 0;), but all of them have the equal ability to shrink (flex-shrink: 1;). They also have a flex-basis: auto; which is used to set the default size of the stream. This method is better than specifying widths in percentages, as it will be easier to make changes if we ever have to add or remove streams but still want to fill the entire space.

See the Pen Flexbox Example – Main Section by Jieun Lee (@jieun-lee) on CodePen.

Filling Remaining Space in the Top Header

The header is composed of three circular buttons with fixed sizes on the right and a titlebar on the left that fills the space that isn’t taken up by the buttons. When the width is adjusted, the titlebar shrinks or grows accordingly, and the title text inside centers itself automatically (just another use of flexbox with auto margin).

The only actual work we have to do is set header__menu to have flex-shrink: 0; instead of the default value of 1. This means these menu items cannot shrink, so the titlebar with an initial width of 100% shrinks instead, as it still has flex-shrink: 1;.

See the Pen Flexbox Example – Header by Jieun Lee (@jieun-lee) on CodePen.

Combining the Sections

Basically, the “page” div holds the header and the wrapper, and the “wrapper” holds the sidebar and the main section. Of course, I used display: flex; on both the page and the wrapper. This example uses minimal content (no menus, only one stream, etc.) to illustrate the layout.

As mentioned previously, the page div holds the header and the wrapper (with a flex-direction: column;). We want the header to be a fixed height, which we specify. We also add flex-shrink: 0; so that the heading section will never get squished. This means the wrapper div (below the header) has a flex-shrink: 1; so it will adjust its height as needed.

The wrapper works in a similar way; it has a flex-direction: row; and a sidebar with a fixed size. For the sidebar we set width: 20%; and flex-shrink: 0; and have the main section have a width: 100% so it can shrink the width as needed.

See the Pen Flexbox Example – Layout by Jieun Lee (@jieun-lee) on CodePen.

Put these four steps together to get the final product that was illustrated at the top of this section. If all of this seems easy to you, try and create this exact scenario without using flexbox – in addition to looking correct, it has to be scalable to content changes and different screen sizes. You’ll quickly realize how much flexbox simplifies the whole process.

One final note about flexbox is that there are some older browsers that have limited or no support for flexbox. For example, Internet Explorer 10 has a different default value for flex, and some properties such as flex-shrink are not supported. However, most newer browsers do have full support for flexbox, but we may have to add prefixes (ex. display: -webkit-flex;) to make sure it is compatible. You may be able to find an automated way to do this, or use something like SCSS mixins to add flex properties all at once.

There’s a lot of neat things you can do with flexbox, also by using the properties I didn’t have in my examples. Either way, I encourage you to try it out – you’ll be amazed by how easily you can create interesting layouts with just a few short lines of code.

About the Author

Jieun Lee is a Software Developer Co-op on the WebDev Team. Jieun studies Computer Science and Mathematics at UBC, and likes to play piano in her spare time. Connect with her on LinkedIn.