
I think many of you who have had to deal with the layout, faced with the need to align elements vertically and know what difficulties arise when aligning an element in the center.
Yes, for vertical alignment, CSS has a special
vertical-align
property
with a lot of values . However, in practice, it does not work as expected. Let's try to figure it out.
')
Compare the following approaches. Alignment with:
- tables,
- indents,
line-height
,- stretching
- negative
margin
transform
,- pseudo-elements
flexbox
.
As an illustration, consider the following example.

There are two
div
elements, one being nested within the other. We give them the corresponding classes -
outer
and
inner
.
<div class="outer"> <div class="inner"></div> </div>
The challenge is to align the inner element with the center of the outer element.
To begin with, consider the case when the dimensions of the external and internal units are
known . Add the
display: inline-block
rule to the inner element, and
text-align: center
and
vertical-align: middle
outer element.
Remember that alignment applies only to elements that have an
inline
or
inline-block
display mode.
Let's set the size of the blocks, as well as the background colors to see their borders.
.outer { width: 200px; height: 200px; text-align: center; vertical-align: middle; background-color: #ffc; } .inner { display: inline-block; width: 100px; height: 100px; background-color: #fcc; }
After applying the styles, we will see that the indoor unit is horizontally aligned, but not vertically:
http://jsfiddle.net/c1bgfffq/Why did it happen? The fact is that the
vertical-align
property affects the alignment of
the element itself, and not its content (unless it is applied to table cells). Therefore, the application of this property to the external element gave nothing. Moreover, the application of this property to the inner element also does nothing, since the
inline-block
blocks are aligned vertically with respect to the neighboring blocks, and in our case we have one line block.
To solve this problem, there are several techniques. Below we take a closer look at each of them.
Table alignment
The first solution that comes to mind is to replace the external block with a table from a single cell. In this case, the alignment will be applied to the contents of the cell, that is, to the internal block.
<table class="outer-wrapper"> <td class="outer"> <div class="inner"></div> </td> </table>
http://jsfiddle.net/c1bgfffq/1/The obvious disadvantage of this solution is that from the point of view of semantics it is wrong to use tables for alignment. The second disadvantage is that to create a table, you need to add another element around the external block.
The first minus can be partially removed by replacing the
table
and
td
tags with a
div
and setting the table display mode in CSS.
<div class="outer-wrapper"> <div class="outer"> <div class="inner"></div> </div> </div>
.outer-wrapper { display: table; } .outer { display: table-cell; }
Nevertheless, the external block will still remain a table with all the ensuing consequences.
Indent alignment
If the heights of the inner and outer blocks are known, then the alignment can be set using the vertical indents of the inner block using the formula: (H
outer - H
inner ) / 2.
.outer { height: 200px; } .inner { height: 100px; margin: 50px 0; }
http://jsfiddle.net/c1bgfffq/6/Minus solution - it is applicable only in a limited number of cases when the heights of both blocks are known.
Alignment with line-height
If it is known that the internal block should occupy no more than one line of text, then you can use the
line-height
and set it equal to the height of the external block. Since the content of the indoor unit should not be transferred to the second line, it is recommended to also add the rules
white-space: nowrap
and
overflow: hidden
.
.outer { height: 200px; line-height: 200px; } .inner { white-space: nowrap; overflow: hidden; }
http://jsfiddle.net/c1bgfffq/12/Also, this technique can be used to align multiline text, if for the indoor unit to override the value of
line-height
, as well as add
display: inline-block
rules
display: inline-block
and
vertical-align: middle
.
.outer { height: 200px; line-height: 200px; } .inner { line-height: normal; display: inline-block; vertical-align: middle; }
http://jsfiddle.net/c1bgfffq/15/The disadvantage of this method is that the height of the outdoor unit must be known.
Alignment with Stretch
This method can be applied when the height of the external unit is unknown, but the height of the internal one is known.
For this you need:
- set relative positioning to the external block, absolute positioning to the internal block;
- add
top: 0
and bottom: 0
rules to the internal block, as a result of which it will stretch to the entire height of the external block; - set the
auto
value for the vertical indents of the indoor unit.
.outer { position: relative; } .inner { height: 100px; position: absolute; top: 0; bottom: 0; margin: auto 0; }
http://jsfiddle.net/c1bgfffq/4/The essence of this technique is that setting the height for a stretched and absolutely positioned block causes the browser to calculate vertical indents in an equal ratio if their value is set to
auto
.
http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-heightThe disadvantage of this method is that the height of the indoor unit must be known.
Alignment with a negative margin-top
This method is widely known and is used very often. Like the previous one, it is used when the height of the external unit is unknown, but the height of the internal one is known.
It is necessary to specify relative positioning for the external block, and absolute positioning for the internal block. Then you need to move the internal block down half the height of the external block
top: 50%
and raise the
margin-top
: -H
inner / 2 up half of its own height.
.outer { position: relative; } .inner { height: 100px; position: absolute; top: 50%; margin-top: -50px; }
http://jsfiddle.net/c1bgfffq/13/The disadvantage of this method is that the height of the indoor unit must be known.
Transform alignment
This method is similar to the previous one, but it can be applied when the height of the indoor unit is unknown. In this case, instead of setting a negative indentation in pixels, you can use the
transform
property and raise the internal block up using the
translateY
function and a value of
-50%
.
.outer { position: relative; } .inner { position: absolute; top: 50%; transform: translateY(-50%); }
http://jsfiddle.net/c1bgfffq/9/Why in the previous method it was impossible to set the value in percent? Since the percentage values of the
margin
property are calculated relative to the parent element, a value of 50% would be equal to half the height of the external block, and we had to raise the internal block by half of its own height. The
transform
property is just suitable for this.
The disadvantage of this method is
limited support for the transform
property by older versions of IE browser.
Alignment with pseudo-element
This is the most universal method that can be used when the heights of both blocks are unknown.
The essence of the method is to add a line block
inline-block
with a height of
100%
inside the outer block and set it to vertical alignment. In this case, the height of the added block will be equal to the height of the external block. The inner block is aligned vertically with respect to the added, and hence the outer block.
In order not to violate the semantics, it is recommended to add a line block using a pseudo-element
before
or
after
.
.outer:before { display: inline-block; height: 100%; vertical-align: middle; content: ""; } .inner { display: inline-block; vertical-align: middle; }
http://jsfiddle.net/c1bgfffq/10/The disadvantage of this method is that it cannot be applied if the indoor unit has absolute positioning.
Align with Flexbox
The most modern method of vertical alignment is to use the
Flexible Box Layout (popularly known as
Flexbox
). This module allows you to flexibly control the positioning of elements on the page, placing them almost as you like. Aligning to the center for Flexbox is a very simple task.
The external block needs to set
display: flex
, and the internal block -
margin: auto
. And it's all! Beautiful, is not it?
.outer { display: flex; width: 200px; height: 200px; } .inner { width: 100px; margin: auto; }
http://jsfiddle.net/c1bgfffq/14/The disadvantage of this method is that Flexbox is
supported only by modern browsers.
Which way to choose?
It is necessary to proceed from the statement of the problem:
- For vertical text alignment, it is better to use vertical indents or the
line-height
. - For absolutely positioned elements with a known height (for example, icons), a method with a negative
margin-top
property is ideal. - For more complex cases when the block height is unknown, you need to use a pseudo-element or the
transform
property. - Well, if you are so lucky that you do not need to support the old versions of the IE browser, then, of course, it is better to use the
Flexbox
.