Centering a div - such a trivial exercise, something you have surely done numerous times if you work in web development, and something I have done numerous times, almost automatically, as if it’s muscle memory.
As I believe this is a source of frustration for many frontend-newbies, I decided to challenge myself to come up with a few solutions to this problem. It might come as a surprise, but I’ve also encountered this issue as an interview question! In this article, I will present 6 approaches and discuss their advantages and disadvantages. The goal:
Center a div in its parent element both horizontally and vertically.
If you are not interested in the detailed breakdown of each case, but you would like to view the code for all of them at once, please visit this CodePen.
See the Pen The many ways to center a div with CSS by Olivia Gardiner (@oliviaisarobot) on CodePen.
In these examples, I’m going to use SCSS, but I will show you the compiled version too for easier understanding. SCSS or SASS gives us the freedom to use variables to define the width and the height of the elements, so we can play around and see how each solution we come up with works out with different ratios. The following solutions will work for non-square elements just as well as square ones.
$container-height: 150px;
$container-width: 120px;
$div-height: 45px;
$div-width: 25px;
.container {
height: $container-height;
width: $container-width;
div {
height: $div-height;
width: $div-width;
}
}
Solution #1 - Pure margin
.container {
div {
margin: calc(#{$container-height} / 2 - #{$div-height} / 2) auto;
}
}
Just one line, and oh, isn’t it wonderful? If only there was an “auto” property for vertical alignment too, right?! Nevertheless, you have probably used this solution as
margin: 0 auto;
for just horizontally aligning your DOM element. As simple as this method might seem, its merit lies in older CSS versions and older browsers supporting it. It also works whether its parent container uses block or flex display!
When should you use this approach?
Definitely every time you are looking for a simple alignment option, great browser support, and you are not using a complex layout system such as flexbox or grid.
Solution #2 - Flexbox, the nemesis
.container {
align-items: center;
display: flex;
justify-content: center;
}
The flexbox layout system might be quite mind-boggling at first sight, but it actually gets gradually simpler as you practice. If well thought-out, it also grants you a responsive, fluid interface that has the ability to reorder, and change the alignment of the DOM elements with just a few simple properties - no complicated calculations or confusing numbers! Its browser support is also quite decent these days, and you really need to dust off the attic to find some ancient browser version it won’t run on.
When should you use this approach?
When you aim to utilize multiple advantages of the flexbox, or you are combining multiple flex elements to create a fluid layout - and if you like it!
Solution #3 - The grid
.container {
display: grid;
div {
place-self: center center;
}
}
If you ever tried to design a complex layout with flexbox, you might have noticed, that above a certain scale, it becomes quite challenging to control every element in question, without pulling your hair out. That’s when grid comes into play, which allows you to control your layout responsively on two axis.
If you need to support older browsers (under IE 10), the grid might not be the best solution. It’s also worth noting that Edge really doesn’t like the place-self: center center;
property (even in its newest version), so you might want to switch that line out for
align-self: center;
justify-self: center;
just to be on the safe side, in case your audience has some Edge fans too!
When should you use this approach?
The grid is viable only above a certain scale. For a single element, it’s probably an overkill, but if you are already using this is a layout system, there is always an option to center an element with simple properties.
Solution #4 - Relative positioning
.container {
div {
left: calc(50% - #{$div-width} / 2);
position: relative;
top: calc(50% - #{$div-height} / 2);
}
}
A definite perk of this approach is the wide browser support. You may wonder what the heck is all that calculation, it is basically to support different container-to-element ratios. Flat values work just as well if you have a constant container-to-element ratio.
When should you use this approach?
Whenever you need a simple and widely supported solution.
Solution #5 - Absolute positioning
.container {
position: relative;
div {
left: calc(50% - #{$div-width} / 2);
position: absolute;
top: calc(50% - #{$div-height} / 2);
}
}
It looks very similar to the relative positioning, doesn’t it? You might know by now, that for an absolute positioned element to do your bidding, you need to set its parent element to display: relative
, because the browser default is display: static
, which will not serve as a reference point for your absolute positioned element.
Without any further code, this setup will also open the possibility for your parent element’s width and height to reach zero, should you put the whole thing inside a flex element! You can circumvent this by setting the min-width
of your container.
When should you use this approach?
Whenever you need a widely supported solution, and whenever you feel comfortable with controlling the consequences of an absolute positioned element.
Solution #6 - CSS3 transform
.container {
div {
transform: translate(calc(#{$container-width} / 2 - #{$div-width} / 2), calc(#{$container-height} / 2 - #{$div-height} / 2));
}
}
The calculation to support all ratios makes it look more complicated than it initially is. However, if you have a very symmetrical setup, it’s best to use direct values, such as this one:
It’s important to know that this only works with squares where the container-to-element ratio is 2:1, and the margins and paddings are reset or normalized.
If you are using non-symmetrical elements that still have a constant ratio, it’s worth figuring out the direct values for the translate, because calc()
does not work in Edge <14 and IE, when used inside a transform.
When should you use this approach?
It’s simple and works well in newer browsers (given that you use direct values instead of a calc()
). To top it off, it’s some fancy, neat and clean CSS3, which is demanded by many modern coding jobs as CSS3 modules are gradually becoming the standard, so it’s better if you get familiar with it! Bear in mind that this solution however, does not always work well with responsiveness - if you allow your container to scale, the element inside will still be transformed based on the container’s initial width and height that you set, even if your elements are perfectly square, and you use an approach similar to transform: translate(50%, 50%)
!
Single axis alignment alternatives
It’s worth mentioning a few other properties that might come in handy if you only need to consider the horizontal, OR the vertical aspect. That being said, vertical-align: middle
is an excellent way to vertically position table cell contents, or inline images, while text-align: center
gives you similar powers on the horizontal axis, also usable in block elements or table cells!
If the contents are not wrapped in another DOM element, and you are only trying to center some text both horizontally and vertically, in addition to ‘text-align: center’, you can also set the line-height of your element equal to its height. As a result, any text inside will stay neatly and orderly in the center.
...and how NOT to center a div
While the above examples work well in different, specific scenarios, it must be emphasized that there are also bad practices when it comes to aligning elements.
Tables are not meant for creating layouts
Some of you might ask why do I even bring this one up. In the early days of the internet, and web pages, with no need for responsiveness, and in the absence of tools such as the grid system, tables were the go-to option for creating complex layouts.
Certain developers might still be tempted today to “cheat” a little bit, and position the element by wrapping it in a seemingly nice table. The many problems with this approach are that it’s tedious to make tables responsive, they are hard to control, and they completely destroy the semantic structure of the web page, making it harder for assistive technologies, such as screen readers to process the page.
Tables still have their place in a website, but only when they are actually used for what they are: displaying data records in an organized manner.
Pixel positioning
I don’t think this is a persistent problem, but many of us might be guilty of pixel positioning in our early days. Did you ever run into that problem, when you had a paragraph of text and a block of image under that, and you couldn’t help but notice that the left edge of the block does not line up perfectly with the the paragraph above? It was off by just a few pixels for some odd reason.
And did you perhaps, sneakily add a margin-left: -3px;
(or padding) to the block?
While this might seem to solve your problem, it’s really a virtual solution, or rather a hack. The fact that two blocks don’t line up when they should means that you don’t have proper control over your margins and paddings, and it’s worth revisiting their parent container, and the individual blocks too, to eliminate the discrepancy that might come back to haunt you later on, when you are using the same styles on new elements, or when you realize that on a different screen resolution, the desired “adjustment” would be 4 pixels instead of 3!
Wrapping it up
There are a few tricks you can use to escape the never-ending hamster wheel of positioning elements to the center. I would like to further encourage you to follow suit, and investigate seemingly trivial topics of frontend development and site-building, just to exercise your neurons a bit. You might run into solutions you have never heard of, but you will certainly strengthen your core sitebuilder skills - a steady foundation and a source of confidence that will come in handy in your journey as a developer.