Positioning Elements on the Web

Choosing how to position an element in CSS is sometimes really a choice about what side effects are most acceptable.

Positioning layouts in CSS was once a very daunting task, and hacks like using tables for the entire layout were quite common. Over the years, the demand for better layout tools has led to steadily better support and techniques. Today we have options, and learning to manage each of these techniques is the key to creating complex layouts that remain easy to change and flexible enough to handle multiple screen sizes.

Floats

Floats are the most commonly used layout technique in CSS, but they can be frustrating if you don’t know how they affect their neighboring elements. When you style an element with float: left, the following elements will reflow. The document flow is just the order of the content and how the elements arrange themselves around each other. If the floated element does not have a set width, it will collapse to the width of the contents. If the following element is narrower than the remaining space, it will move to the right. Keep in mind that elements set to display: block will need to be given a set width or they will remain on their own line.

You can prevent an element from reflowing by giving it a clear property in your stylesheet. Options include clear: both, clear: left (which will still allow reflowing following elements with float: right), and clear: right (which does the opposite). You can also use clear: none to override the default behavior. This is the basic idea behind grids, which we will cover in detail later, along with how to use floats responsively.

Because floated children will cause their parent elements to collapse, you will find yourself tempted to create new elements just to add clear: both and prevent this behavior. While that does work, we want to keep our markup semantic so this should be done just using CSS if possible. By using an ::after pseudo-element, you can create a clearfix:

  .container::after {
    clear: both;
    content: "";
    display: table;
  }

Using a preprocessor like Bourbon makes it easy to add this as a Sass mixin:

  .container {
    @include clearfix;
  }

Floats work best for large containers, but may not work so well for text elements since it will be difficult to align. You may find that using display: inline-block is better for these situations.

Position CSS Property

Positioning gives us a completely different layout method. The default value is static, and makes the element behave normally.

Using position: relative lets you specify an offset with top, bottom, left, and right.

.logo {
  position: relative;
  left: 1em;
  top: 1em;
}

This can be useful to do a simple offset without using something like margin, but it becomes really powerful when containing a child with position: absolute. Absolute positioning bases the elements position relative to the nearest parent element that has position: relative set. If it can’t find one, it will be relative to the document.

.hero {
  position: relative;
}

.hero-icon {
  position: absolute;
  left: 20px;
  top: 10%;
}

Absolute positioning should not be used to layout columns of content. Because the elements are removed form the document flow, that means every time you add content to one section, you may have to adjust the sizes of other sections by hand, and it makes responsive design much more of a hassle than it needs to be. Reserve absolute positioning for getting those small design elements exactly where you want them to be. As a general rule, if an element can be simply positioned using floats or a change to the display styles, it is probably best to avoid absolute positioning.

Something that can be very useful but stumps a lot of beginners is centering elements with absolute positioning. If your element has a set size, it’s just a matter of offsetting using margins. Let’s take the last example but center the icon both horizontally and vertically. To center an element using absolute positioning, just follow these steps:

  1. Add left: 50% to the element that you want to center. You will notice that this aligns the left edge of the child element with the 50% line of the parent.
  2. Add a negative left margin that is equal to half the width of the element. This moves us back onto the halfway mark.
  3. Next, we’ll do a similar process for the vertical axis. Add top: 50% to the child
  4. And then add a negative top margin equal to half its height.

This means that even though the container may change sizes, the centered element will stay right where we want it. The resulting CSS should look something like this:

.container {
  position: relative;
}

.centered-element {
  height: 100px;
  width: 100px;
  position: absolute;
  left: 50%;
  margin-left: -50px;
  top: 50%;
  margin-top: -50px;
}

Fixed positioning works like absolute, but is always relative to the viewport rather than the document and will remain in place when the user scrolls. This can make your app feel more like a native application, with a fixed header or side navigation, or for any element you want to keep in easy reach. Like absolute positioning, fixed elements will be removed from the document flow, so you may need to add padding on an element beneath them to make sure your other content will still be visible.

Sticky positioning is the newest of the group, and doesn’t have good enough browser support to suggest using it. There are some great articles on how to go about using it, as well as javascript alternatives. This shouldn’t be confused with the ever-popular sticky footer technique, which also deserves a special mention.

The position property gives us the advantage of being able to specify the z-index of our elements. If we go back to our metaphor of seeing elements as pieces of paper, setting the z-index property allows us to specify whether our paper is above or below the other pieces. A higher number will appear above, and a higher number will appear below. You can also use a negative number, which may make the element appear behind the parent (or even behind the document entirely!). This can lead to a sort of arms race with higher and higher numbers to ensure an element always sits on top. This can get pretty unmanageable and it is better to use positioning and z-indexes conservatively.

Flexbox

A good way to handle elements of variable sizes is to use the new flexbox properties introduced in CSS3.1. This gives us a lot more options to control layout and has solved some of the long-standing problems in CSS. Browser support is good, and with a polyfill or fallback to get Internet Explorer up to speed, it’s ready for production usage.

I said that we weren’t going to talk about how CSS works, but flexbox is still new and unfortunately the syntax is very confusing. Flexbox is such a powerful tool and replaces so many other hacky solutions, so it is worth taking the time to understand how to use it.

Let’s jump in. Here is how to set up an element to use flexbox.

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
.container {
  display: flex;
  flex-direction: row;
}

Setting the container to display: flex simply lets the browser know that we intend the children to use flexbox for their layout. Then we add flex-direction: row to the children to align them horizontally, and by default they will be the same width unless they have a width set.


Flex-direction allows you to specify whether your elements should be arranged vertically or horizontally. By default, the value will be row, which simply arranges you items horizontally. You can also use column to switch to a vertical orientation.

.container {
  display: flex;
  flex-direction: row;
}

Keep in mind that using column may affect how the other flexbox properties look on your items, and for simplicity we will mostly be talking about horizontal items because that is by far the most common use-case, but keep in mind that this other direction option does exist.


Flex-wrap defines whether elements should be forced to fit in a single line (no-wrap, the default behavior) or allowed to maintain their normal size with wrap. Most of the time you will want the default behavior, but overriding this property will let you use flexbox’s other properties without affecting the widths.

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

When set to no-wrap, elements will still be sized proportional to each other. For instance, imagine items in a list are set to be 100px wide, except for the last one which is 200px. The items will resize to fit the container, but the last item will still be twice as wide as the others.


Justify-content determines how to space your content in your row or column. The default value is flex-start, which will left align your items. Naturally, we also have flex-end to right align the items and center to center them. Things get more interesting with space-between, which give equal spacing between items but not on the ends, while space-around gives equal spacing to the ends as well.

.container {
  display: flex;
  justify-content: center;
}

This is best used when the items have set widths (or have reached their maximum widths).

This can be really helpful when lining up your flexbox items to your grid, without relying on things like floats.


Align-content is similar to justify-content, but controls where the items are on the cross axis. I say “other” because when you are using flex-direction: row, then align-items is controlling the vertical alignment, but when you are using flex-direction: column, it’s the other way around.

You can align the items to the baseline of the text within each item by using baseline. There is also an option to make each item span from one end of the axis to the other with stretch.

.container {
  display: flex;
  align-items: center;
}

We can use align-items: stretch to solve the “equal height columns” problem that has plagued CSS layouts since the beginning. You can also set both justify-content and align-items to center to center your items in the middle of your container, which is really helpful for things like hero areas and splash pages.

There are several more properties that are used less often but that you might find useful.


Align-items affects lines of content and where they should be within their container. You can see below that the items in each line maintain their normal heights (unless you are using stretch).

.container {
  display: flex;
  align-content: stretch;
}


There are also a number of flexbox properties for the items in the container. These are quite a bit easier to understand than the parent properties and luckily, there is a useful shorthand that we can use to make this easier.

.list-item {
  flex: <flex-grow> <flex-shrink> <flex-basis>;
}
  • flex-grow: <integer> : This provides another way to give your flex items different widths. If you set all of your child elements to flex-grow: 1, but set the last child to flex-grow: 2, it will be twice as wide as its siblings.
  • flex-shrink: <number> : Determines how the element will shrink when the container is not wide enough for the items to maintain their natural width. If the last element is set to flex-shrink: 2 while its siblings are set to flex-shrink: 1, it will shrink twice as much as its siblings.
  • flex-basis: <size> : What we should consider to the be natural size of the item. This can be thought of as the “breakpoint” at which the grow and shink properties are triggered.

Order controls the order in which the item appears in the container. Negative numbers are accepted and will appear before what would normally be the first element.

Align-self has all of the same options as align-items, but lets you control how individual elements are aligned. For instance, the siblings may be set to flex-start, but you can chose an item to set to flex-end.

You probably won’t be using all of these together, but such a monstrosity would look like this:

.container {
  align-items: flex-start;
  display: flex;
  height: 40em;
}

.item {
  flex: 1 1 2em;
}

.item:nth-child(3) {
  align-self: flex-end;
  flex: 2 10 5em;
  order: -1;
}

Flexbox can be a hard thing to wrap your head around, especially if you are used to the quirks of traditional CSS layouts. Site like Codepen are a good way to learn is just to experiment and see what you can come up with.

If you aren’t sure how you would use flexbox in a real-world application, Solved by Flexbox is a great resource put together by Mozilla that features a lot of great practical ideas.