CSS Layout Methods and Fundamentals Guide

This guide will uncover the differences, pros, cons, and make some recommendations for using floats, inline-block, display: table, and flexbox when building your responsive CSS layouts. Here are some of the techniques covered in the guide:

Preface

Before we dive into the methods, there is some CSS which will make our lives infinitely easier. Here it is:

html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }

I add this to all my CSS documents. By doing so, I can add all the padding and borders I want to an element, and it won’t effect the height and/or width dimensions I set on it.

For example, If I declare width: 50% on an element and then add padding: 20px to it, the element will remain 50% in width.


Without box-sizing: border-box, 40px would be added to the total width (20px for left and right sides), so the element would really be 50%+40px wide, which causes headaches and makes responsive CSS nearly impossible.


Throughout the examples I will be using .parent and .child as CSS classes. These classes are being used for illustrative purposes - and refer to the HTML structure of a parent and child or children HTML element(s). For example:

<div class="parent">
  <div class="child"><!-- content goes here --></div>
</div>


CodePen demos will be provided for each example. These demos will contain slightly more CSS than is necessary to achieve the desired layouts, such as borders or background colors, just to better illustrate the dimensions, positioning and spacing of elements.

Method 1: Floats

Most HTML elements (div, section, header, h1, p, ul, li etc.) have a default display property value of block.

display: block;

Block-level elements take up 100% of the width of their context by default. This makes it impossible to get two block-level elements to sit side-by-side without some additional CSS.

Floats require just one line of CSS to all block-level elements to get started.

float: left; or float: right;

Example 1

Here we have two 50% width divs sitting side-by-side.

See the Pen Layout Methods Guide #1 by Joey Augustin (@joeaugie) on CodePen.

Example 2

We can also easily create consistent spacing between two or more equal-width floated elements by using a margin along the right-hand side of each element. Also, since we only want space in between the floated elements and not around the outside, we can use the :nth-child() selector to target the last element in each row.

See the Pen Layout Methods Guide #2 by Joey Augustin (@joeaugie) on CodePen.

Now, every third item in a row will not have a right-hand margin, and you can create as many rows as you’d like and be sure of consistent spacing throughout your layouts.

Example 3

You can also position two elements on the left and right of their parent container.

See the Pen Layout Methods Guide #3 by Joey Augustin (@joeaugie) on CodePen.

Example 4

Floats are also an ideal layout technique for allowing text to flow around an image. Declaring floats removes a block-level element from the normal flow of the document, which means block-level elements (such as a paragraph) that come after them in the HTML will slide up underneath them, but the text inside those elements will flow around the floated element.

See the Pen Layout Methods Guide #4 by Joey Augustin (@joeaugie) on CodePen.

However, there is one caveat with floats. In order to use them effectively, you need to add what’s called a “clearfix hack” to any parent element which contains floated elements. Without it, you won’t be able to see the parent container’s background, and you may run into other layout issues.

Here is the clearfix hack as a CSS class you can add to any parent element which contains floated children. Just add class=“cf” to the parent of floated elements.

.cf:before, .cf:after { content: ""; display: table; }
.cf:after { clear: both; }

Pros vs Cons of using floats

Pros

Cons

Recommendations

Floats come in most handy when you want text to flow around images. The float:right and float: left combo can be utilized to keep left and right arrows below a slideshow, for example. They also work fine with rows of side-by-side elements, or in large layout containers like a header, sidebar, main content area, and footer of a website.

Method 2: Inline-Block

Inline-block is a blend of inline and block display values. You can do very similar layouts to those you can do with floats, with a few differences. In fact, many non-flexbox CSS Frameworks utilize either inline-block of floats as their main layout methods within their grid systems.

Unlike floats, you don’t have to clear the parent container because they are not removed from the flow of the document. But inline-block is not without it’s own strangeness.

For example, if you set two containers to inline-block and set their width to 50%, you may find the second container being bumped down to the next row.

Example 5

See the Pen Layout Methods Guide #5 by Joey Augustin (@joeaugie) on CodePen.

Theoretically, these two containers should sit side-by-side. However, inline-block inherits characteristics of inline elements, and when inline elements have whitespace between them in the HTML, the browser will render that whitespace.

So the extra 4 (or so) pixels of whitespace causes the second container to be pushed down to the next row.

The remedy? Remove the whitespace between the closing and opening tags of inline-block elements in your HTML. There are a few other ways to deal with it - and you can read in detail about them over at David Walsh's blog.

PureCSS (purecss.io), a lightweight responsive framework, removes the space by using negative letter or word spacing (depending on the browser).

It works, but there are some other rules you need to follow because of that choice, so be sure to read the documentation if you decide to give it a try.

Example 6

One convenience of inline-block is the ease of horizontal centering. Because of their inline characteristics, you can use text-align: center on the parent element for centering.

See the Pen Layout Methods Guide #6 by Joey Augustin (@joeaugie) on CodePen.

However, notice I had to reset the text-align on the container if I want the text inside of those containers to be left-aligned. Not ideal, but it works.

Example 7

Another perk of inline-block is being able to utilize vertical-align along with either top, middle, or bottom values.

See the Pen Layout Methods Guide #6 by Joey Augustin (@joeaugie) on CodePen.

These items are vertically centering in relation to each other, not in relation to the parent container. However, as long as you have only one row of items, they will technically be vertically centered inside the parent container if you are using equal padding on the top and bottom of the parent container.

Pros vs Cons of using inline-block

Pros

Cons

Recommendations

Overall, inline-block is a nice solution for things like navigation items, grids of video thumbnails, slideshow pagination indicators, and really any items that need to be lined up side-by-side, with the option to vertically and horizontally center them.

Method 3: Table

HTML tables used to be used as structure layouts, but CSS caught on when developers began to realize if we want a usable, searchable web, we need to make sure our HTML is properly defining our information. So HTML tables as a layout technique faded away.

However, there were a few nice things about using tables as a layout tool. So, display: table was introduced to allow for some of the table layout techniques without having to destroy the HTML semantic structure.

When using display: table, one things must be kept in mind - you are using this declaration on the parent element - along with other table declarations, such as display: table-cell or display: table-row on the child elements, depending on how you want them laid out.

Example 8

See the Pen Layout Methods Guide #6 by Joey Augustin (@joeaugie) on CodePen.

Wait? What’s going on here? Why are both containers 50% in width?

Well, table cells will grow to take up the remaining space of a table. It’s exactly how a cell in an actual HTML table would respond. Essentially, table cells don’t respond well to percentage widths. However, one thing you can do with display: table-cell is have one fixed-pixel width element adjacent to another element that takes up the remaining space.

Example 9

See the Pen Layout Methods Guide #9 by Joey Augustin (@joeaugie) on CodePen.

This is something that neither floats nor inline-block layouts can easily accomplish without issues arising.

Another thing side-by-side floated and inline-block elements can’t do by default is be of equal height. You will notice in the last two examples, each container is the same height (the height of the tallest container). This is exactly how table cells work in order to keep each new row of cells starting on the same line, which in turn makes tabular data easier to read.

Pros vs Cons of using display: table

Pros

Cons

Recommendations

Overall, display: table does it’s best work for larger layout containers. For example, a static width sidebar next to an flexible content container. It’s also nice to use when you are looking for equal height row items. However, it’s inability to play nicely with percentage widths presents limitations.

Method 4: Flexbox

Flexbox combines all of the pros of each of the previous methods into one incredibly robust layout system.

It all starts with declaring display: flex on the parent container. From there, you have lots of values and properties to choose from to add to both the parent and child containers to achieve the types of layouts you are looking for.

Example 10

See the Pen Layout Methods Guide #10 by Joey Augustin (@joeaugie) on CodePen.

We are declaring display: flex on the parent, along with the justify-content: space-between in order to designate the extra space in-between the two, which effectively pushes each child to opposite sides of the parent.

Also, notice that instead of declaring a width, we are using the flex: 0 1 25% on the child elements.

The flex property, which is declared on children (or flex) items, can contain three different values. These three values are flex-grow, flex shrink, and flex-basis.

The default values for any flex item is as follows:

flex: 0 1 auto;

So by default, the browser is saying “If there is any extra space, don’t grow (flex-grow: 0), and if there isn’t enough space, shrink at a rate of 1 unit (flex-shrink: 1). Also, I want your initial width to be automatic (flex-basis: auto).”

We could declare all three values separately, but declaring them all within one flex declaration keeps things nice and tidy.

So, when you declare display: flex on a parent container, all the child elements will lineup side-by-side and take up an equal width within the parent. And, since the default flex-basis value is auto, all the available space will be consumed.

In example 7, we declared 25% for flex-basis, and since flex-grow is set to 0, the child elements will not grow beyond the flex-basis (or initial width) value.

Example 11

Both flex-grow and flex-shrink can have either percentage values, or non-descriptive proportional values. Let me explain with an example:

See the Pen Layout Methods Guide #11 by Joey Augustin (@joeaugie) on CodePen.

Here, both children have a flex:basis value of 25%, so that’s the width they will take up by default. However, because there are only two children, there is still 50% space remaining in the parent container.

Since we declared a flex-grow value of 1 on .child-1 and 2 on .child-2, .child-2 will claim twice as much of the remaining space as .child-1 will until all the extra available space is claimed.

The flex property can be the most confusing part of flexbox. Keep in mind that flex-basis is the starting width, flex-grow is how much each child is allowed to grow, and flex-shrink is how much they will shrink if there is inadequate space available.

Example 12

Let’s take a look at centering two flex items:

See the Pen Layout Methods Guide #12 by Joey Augustin (@joeaugie) on CodePen.

By default, all flex items will stretch vertically and become as tall as the tallest flex item, just like when using display: table in example 6.

This is because the flex parent container has align-items: stretch declared by default.

We can switch it up by declaring any of the following values for align-items, and in each case, their heights will be determined by the amount of content they contain, rather than stretching:

Example 13

So, if we want two 25% width children both vertically and horizontally centered, we could do it like so:

See the Pen Layout Methods Guide #13 by Joey Augustin (@joeaugie) on CodePen.

Example 14

How about vertically centered, but on opposite sides of the parent container?

See the Pen Layout Methods Guide #14 by Joey Augustin (@joeaugie) on CodePen.

Example 15

How about with equal space around them, and aligned to the bottom of the parent container?

See the Pen Layout Methods Guide #15 by Joey Augustin (@joeaugie) on CodePen.

As you can see, just switching up the justify-content and align-items properties on the parent container gives us lots of layout options.

Example 16

You can even switch up the source order with flexbox in a few different ways. The first would be to change the flex-direction property.
By default, the flex-direction property has a value of row. But we could declare flex-direction: row-reverse, which would make the last item in the HTML source appear first in the row, and the first item appear last.

See the Pen Layout Methods Guide #16 by Joey Augustin (@joeaugie) on CodePen.

Example 17

You can also explicitly place any flex item of a row in any order you wish, by declaring order on each item itself.

See the Pen Layout Methods Guide #17 by Joey Augustin (@joeaugie) on CodePen.

Example 18

With multiple rows of items the align-content property comes into play.

Let’s say you have a parent flex container that is 100% height of the viewport, along with two rows of 25% width children. How do you vertically center these two rows at the same time? Like so:

See the Pen Layout Methods Guide #18 by Joey Augustin (@joeaugie) on CodePen.

Here we are setting the height of the container to the height of the viewport. Then we declare flex-wrap: wrap to force flex items into a new row if there is inadequate space for them on the current row.

Then, we use align-items: flex-start to make sure the flex items’ height don’t stretch, and use align-content: center to center both rows at once.

This example is somewhat complex, but it really only starts to scratch the surface of what flexbox can do.

In fact, you can do everything we have done so far, only in a vertical orientation simply by declaring flex-direction: column on the parent container. When you do so, all justify-content declarations will be about separating items vertically.

This change in flex-direction is considered changing the primary axis. Therefore justify-content properties are related to the primary axis and align-items and align-content deal with the secondary axis, by default.

Pros vs Cons of using flexbox

Pros

Cons

Recommendations

First, be sure you understand what browsers you need to support and check with caniuse.com for flexbox support within those browsers.
Thankfully, you can add flexbox to an existing float or inline-block layout without any complications. For example, older browsers will utilize the display:inline-block, width and margin values while newer browsers will utilize the display:flex, flex and justify-content values.

Lastly, I recommend tools like Sass mixins, PostCSS, or CodeKit so you don’t have to mess around with all the browser prefixing associated with certain flexbox properties and values.

Conclusion

The possibilities of layout combinations in CSS really are endless, but utilizing the fundamentals listed in this guide will get you well on track to CSS layout mastery. We covered a lot of the basic scenarios you are likely to run into when doing responsive layout, such as centering items both vertically and horizontally, placing fixed-width items next to flexible ones, and different ways to create and space out rows of items and push them to opposite sides of a container.