Editor’s note: This post was last updated by Emmanuel Odioko on 29 April 2024 to include methods such as using line-height
and align-content
for vertical alignment, and to address the accessibility implications of these techniques.
Back in the good old days, the limits of CSS made even “simple” things like vertical centering a challenge, with some developers even relying on JavaScript solutions. It was fragile and very constrained, and there was always that one exception that made it fail.
Whether we were trying to align an icon or image beside the text, create one of those popular hero banners, or create a modal overlay, centering things on the vertical axis was always a struggle.
But CSS has come a long way since, providing many methods that make vertical centering easier every time. In this article, we will look at a summary of some of them, along with their use cases and limitations.
Vertical alignment can be seen everywhere in an application, from navigation menus, form fields, product listings, and so on. To vertically align a text or an element simply means to arrange it within a container or block along its vertical/y-axis. The image below demonstrates this:
The diagram explains the concept of vertical alignment in this way:
N.B., Unless explicitly stated, each strategy highlighted below will work with inline elements as well, which makes sense given that we’ll be directly transforming their position or display properties.
margin: auto
An element with no intrinsic size can be centered by simply using equal values from the top and bottom. When an element has intrinsic dimensions, we can use 0
for the top and bottom, and then apply margin: auto
. This automatically centers the element:
.container{ position:relative; } .element{ position:absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; height: 20px; /*requires explicit height*/ }
The limitation to this approach is, of course, that the element height must be explicitly declared, or it will occupy the entire container.
top:50%
, translateY(-50%)
This is one of the first tricks, and still a go-to, for many developers. By relying on absolute positioning, the inner element at 50 percent from the top of its parent, we can then translate it up to 50 percent of its height:
.container{ position: relative; } .element{ position: absolute; top: 50%; transform: translateY(-50%); }
A fairly solid approach, with the only major limitation being the use of translate
that might get in the way of other transforms, for example, when applying transitions or animations.
A really simple approach and one of the first (back in the day, everything was centered around tables), is using the behavior of table cells and vertical-align
to center an element on a container.
This can be done with actual tables or using semantic HTML, switching the display of the element to table-cell
:
.container{ display: table; height: 100%; } .element{ display: table-cell; text-align: center; vertical-align: middle; }
This works even when both elements are of unknown height. The major limitation is, of course, that if you need to have a non-centered sibling, it might get tricky with the background limits:
Also, bear in mind that this totally fails on screen readers (even if your markup is based on divs, setting the CSS display to table
and table-cell
makes screen readers interpret it as an actual table). So, it’s far from the best when it comes to accessibility.
Another oldie that didn’t catch up for whatever reason is using inline-block
with a ghost (pseudo) element that has 100% height of the parent, then setting vertical-align: middle
for both the pseudo-element and the element we want to center:
.container::before { content: ''; display: inline-block; height: 100%; vertical-align: middle; margin-left: -0.5ch; } .element{ display: inline-block; vertical-align: middle; }
It works quite well, with the most noticeable catch being that it moves the horizontal center just a tiny bit to the right because of the always cringy behavior of white space between inline-block
elements.
This can be dealt with by adjusting the margin on the pseudo-element. In our case, we’ve assigned margin-left: -0.5ch
. We can also get a perfect centering by setting the font size to 0
on the container and resetting it to px
or rem
on the element:
.container { font-size: 0; } .container::before { ... /* margin-left: -0.5ch; */ } .element{ /* ... */ font-size: 16px; }
margin: auto
on a flex
itemFinally, getting into modern CSS territory, flexbox introduced a pretty awesome behavior for auto
margins. Now, it not only horizontally centers an element as it did in block layouts, but it also centers it on the vertical axis:
.container{ display: flex; } .element{ margin: auto; }
This tactic is one of my favorites because of its simplicity. The only major limitation is that it’ll only work with a single element.
flex
containerThis is not the most practical approach in the world, but we can also use flexible, empty, pseudo-elements to push an element to the center:
.container{ display: flex; flex-direction: column; } .container::before, .container::after { content: ""; flex: 1; } .element{ /* ... */ margin: 0 auto; }
This can be useful when we want to keep flexible spacing on a column-oriented flex container with multiple items.
flex
container or the flex
itemFlexbox also introduced really great alignment properties (that are now forked into their own box alignment module). This allows us to control how items are placed and how empty space is distributed in ways that would have required either magic numbers in CSS for a specific number of elements, or clever JavaScript for dynamic amounts.
Depending on the flex-direction
, we might use justify-content
or align-items
to adjust as needed.
On the container:
.container{ display: flex; justify-content: center; align-items: center; }
On a particular flex item:
.container{ display: flex; } .element{ align-self: center; margin: 0 auto; }
There are not many downsides to this approach, except when you need to support older browsers. IE 11 should work, but its implementation of flexbox is quite buggy, so it should always be treated with extra care.
IE 10 requires additional work that has different syntax and requires the -ms
vendor prefix.
vertical-align
for inline elementsYou can also use the vertical-align
property to center inline, inline-block, or table cell elements vertically. One of the many applications for this approach is to vertically align an image with text or to vertically align the contents of a table cell:
.element { display: <inline OR inline-block>; vertical-align: middle; }
See the Pen
Centering (inline): vertical-align by Asaolu Elijah (@asaoluelijah)
on CodePen.
This method not working with the block element could be a deal breaker. Apart from that, it works reasonably well and is also supported by older browsers.
grid
container or the grid
itemCSS Grid includes pretty much the same alignment options as CSS flexbox, so we can use it on the grid
container:
.container{ display: grid; align-items: center; justify-content: center; }
Or we can use it just on a specific grid
item:
.container{ display: grid; } .element{ justify-self: center; align-self: center }
The lack of legacy browser support is the only limitation of this technique.
Similarly to the flexbox alternative, we can use a three-row grid with pseudo-elements:
.container{ display: grid; grid-template-columns: 1fr; grid-template-rows: repeat(3, 1fr); } .container::before, .container::after{ content:""; }
Remember that 1fr
actually means minmax(auto, 1fr)
, so the empty rows won’t necessarily take one-third of the container height. They will collapse as needed all the way down to their minimal value of auto
, which, without content, means 0
.
This might look like a silly approach, but it allows us to easily pull off one of my favorite CSS Grid tricks: combining fr
rows with minmax
ones, which causes the empty fr
ones to collapse first, followed by the mixmax
ones:
So, having the pseudos take the fully collapsible rows allows the auto-placement algorithm to work its magic on our actual elements, except if we need to support IE, which lacks auto-placement. This leads us to the next method.
CSS Grid allows items to be explicitly placed on a specific row, so the same grid declaration as above and the item placed on the second row will be enough:
.container{ display:grid; grid-template-columns:1fr; grid-template-rows: repeat(3, 1fr); } .element{ grid-row: 2 / span 1; /* or grid-row: 2/3 */ }
This can work down to IE10. Believe it or not, IE was one of the first and stronger supporters of CSS Grid, shipping it all the way back in 2011 with IE10. It has a completely different syntax, but we can make it work:
.container{ display: -ms-grid; -ms-grid-rows: (1fr)[3]; -ms-grid-columns: 1fr; } .element{ -ms-grid-column: 1; -ms-grid-row: 2; }
margin: auto
on a grid
itemSimilar to flexbox, applying margin:
auto
on a grid
item centers it on both axes:
.container{ display: grid; } .element{ margin: auto; }
grid
and place-items
Another beautiful and straightforward grid
implementation is applying the center
value to a place-items
property in the same grid element and all its child elements are magically centered:
.container{ display: grid; place-items: center; } .element{ /* Additional styling for child element? */ }
See the Pen
Centering: grid + place-items by Asaolu Elijah (@asaoluelijah)
on CodePen.
However, the place-item
property is still relatively new, and browser support may be an issue given that it is incompatible with older browsers like IE11 and Chrome 4-58.
line-height
By default, this vertically aligns your text, by sharing an equal proportion of space around the text that creates an illusion of vertical centering.
When the line-height
value is greater than the font size of the text, we can, by default, get extra spacing, and the extra space is then distributed evenly above and below the text. This makes the text appear vertically centered within its containing element. The implementation of this is straightforward:
<div class="container"> Vertical alignment can be seen everwhere in an application, we can find it in the Navigation menu, forms field, product listing and so on. </div> CSS .container { line-height: 100px; text-align: center; border: 2px solid steelblue; }
line-height
has full support for all modern browsers, feel free to make the most of it.
align-content
According to the CSS Box Alignment Module Level 3 specification, align-content
can be used to work on the block axis of block
containers and multicol
containers, and we should be able to center the content of these containers just like we do in flex
or grid
containers. All new browser have good support for the align-content
property, but IE 10 may not have this working so well for it:
.parent-container { display: flex; align-content: center; } .parent-container div { width: 160px; height: 150px; background-color: tomato; margin: 20px; }
The brain has an observed pattern: it is designed to read and easily assimilate concepts from the left to the right (left aligned), which makes reading large blocks of text easier. Vertical alignment may stand out aesthetically but those with reading difficulties may find it challenging to work with. Vertically aligned text should be minimal for the sake of accessibility. This means it should be limited to headers to accommodate users with reading impairments.
Vertically aligned, large text is known to reduce reading speed because readers need to pause before finding the next line. This isn’t advisable for long text. If you must slow down the reading speed, it should be for the right reasons, such as emphasizing specific content. Otherwise, text alignment should be kept simple for ease of reading.
For vertical alignment, it is more advisable to settle for CSS flexbox or Grid in most cases because these tools offer a cleaner and more responsive approach compared to mimicking tables with CSS and the rest.
CSS has evolved significantly over the years, making vertical alignment much simpler. This article highlighted 17 methods, each with unique use cases and limitations. Modern approaches like CSS flexbox and CSS Grid provide responsive solutions, while older techniques remain useful for compatibility. Understanding these methods will allow you to choose the best fit for their projects.
If you know other techniques, please share them in the comments.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
10 Replies to "17 ways to implement vertical alignment with CSS"
Thanks Dude For The Tricks!!
Dude i was going nuts and completely forgot Flexbox works so well! ANother tip would be to Use inline-flex so there isn’t all the weird spacing!
MuchĂsimas Gracias !!! :’)
the display:flex solution is very easy and versatile. Thanks
Thank you so much .. !
Just the height:100vh help me get out of my misery!
God bless you dude. I’ve seriously been stuck on this for over 2 hours and your blog post solved my problem like it was nothing
Nice one 🙂
Here’s one I like to use a lot :
.container {
display:grid;
place-content:center;
position:absolute;
inset:0;
}
You can also add this one:
.container {
display: grid;
place-items: center
}
Facu, me gustaria ponerme en contacto con vos, hay un articulo que me intereso y me gustaria discutirlo. Abrazo desde Buenos Aires!