The Art of Centering
Tags: codenewbie, tutorial, webdev, css
Published: 2020-08-03 16:52:09

Like any good Wes Anderson flick, sometimes it's important for elements on our page to utilise the art of symmetry and draw our users' eyes to the center of the page.

There are a few different methods to achieve this so here I'm going to try and explain the most simple and most useful methods that exist, and also *why* they do what they do!

Here's a quick codepen to show the methods I'll be discussing below:
{% codepen https://codepen.io/cjcon90/pen/vYGBmJB %}

## Auto margins

We'll start with the very common `margin: 0 auto`.

This is used to quickly and easily **horizontally center block-level elements**; which are elements on a page that always start on a new line and take up the full width available within their container.

This is a super useful method as many HTML elements are block-level by default, including:

* `<div>`
* `<h1>` - `<h6>`
* `<p>`
* `<form>`
* `<header>`
* `<footer>`
* `<section>`

To explain `margin: 0 auto`:

**0** refers to the top and bottom margins
**auto** refers to the left and right margins.

As block level elements take up the full width of their container, auto will give an equal margin to both the left and right of an element - thus, centering it!

*Note: unless you need a specific margin on the top and bottom of your element then you can just as easily write `margin: auto`, which will apply an automatic margin to all sides of an element and generally achieve the same result!*

## Text align

*"Wait, wait - I \*think\* I know how to center text already!"*, I hear you say. Well did you know that `text-align: center;` can be used for much more than that?

There are many important HTML elements that are set as **inline** display by default for which the above auto margin trick will not work. These include:

* `<textarea>`
* `<img>`
* `<input>`
* `<select>`
* `<button>`

Besides that, you may often want to have an element such as a `<div>` display as an **inline-block** for various styling or layout purposes, usually if you want to display other elements on the same line within that container.

When that time comes, all you need to do is use `text-align: center;` on the parent element, and it will horizontally center the child element, no matter what it is, the same way that it would text!

*Note: Compared to `display: inline`, the major difference is that `inline-block` allows to set a width and height on the element and it respects margin and padding. Try changing the display to inline in the CodePen to see the difference between the two!*

## Flexbox

Flexbox is a fantastic tool to center or position elements in most situations, however it can be confusing for people as to which flex properties are used when centering an element either vertically, horizontally or both!

The reason being: this will depend on the what you have set as `flex-direction`. To explain:

If you have a container set as `flex-direction: row` (the default setting) then your **main axis** is the horizontal x-axis, and your **cross-axis** is the vertical y-axis.

If you change this setting to `flex-direction: column`, then the vertical y-axis becomes your **main axis** and the horizontal x-axis is your **cross axis**

This is important for the two main centering properties:

* `justify-content:` which positions an element across its *main axis*
* `align-items:` which positions an element across its *cross axis*

Generally, setting both these two properties to `center` will always center an element within a flex container, however it's important to remember the key differences between these two properties for perfect positioning!

If the container is a row and you want to center the element(s) inside horizontally, go with `justify-content`! if it's a column and you need to center horizontally, then reach for `align-items`. Hopefully now you have a full understanding of the reason why!



## Grid

With grid, things can get a little trickier when looking at your page as a whole, depending on how many columns and rows you may set, and many people will reach for flexbox *within* a grid container to center elements, however I would like to share one very quick and powerful trick for perfectly centering an element within a grid container.

In addition to giving the container a property of `display: grid`, simply add the property of `place-items: center`, which will keep any child element perfectly centered.

A great option for both vertically and horizontally centering an element in any situation!



## Absolute Centering

I saved my personal favourite for last, due to the flexibility and power in this option. First I'll present the code which I'll explain afterwards:

```css
.container {
    position: relative;
}
.child {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%)
}
```

So what's going on here?

Well firstly we need to remember that whenever we want to use `absolute` positioning, it's important that the parent element is set to `position: relative`. Otherwise the child element will likely position itself in relation to the whole document body.

Then we use `top: 50%` & `left: 50%` to position the child element  at the exact mid-way point of its parent, however that means the element will only *begin* at that point (so basically the top left corner of a div).

To fix this, we use `transform: translate(-50%, -50%)` to bring it half-way back on both it's x-axis and y-axis so it is *perfectly* centered within it's parent element.

Two reasons why I love this:

One, it's flexible - If we wanted to center en element horizontally, then we just use `left: 50%`  and use `translateX(-50%)` - vice-versa for vertical centering.

Two, it's *perfect* for creating useful mixins with Sass/SCSS. For example I have the following go-to mixins on any project I'm working on for quick and easy centering when I need it:

```scss
@mixin xCenter {
    position: absolute;
    left: 50%;
    transform: translateX(-50%)
}

@mixin yCenter {
    position: absolute;
    top: 50%;
    transform: translateY(-50%)
}

@mixin absCenter {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%)
}
```

then any time we need to center an element perfectly, we can simply just use `@include absCenter` and hey presto! 

I really hope that was helpful and message if there's any other useful tips, tricks or CSS magic that you think should be included!