A common need in HTML is to center text or images. There are a number of ways to accomplish this. The purpose of this document is to describe many of these ways in detail, including, for some of them, some little-discussed aspects of the parameters of their implementation.
Centering and other types of alignment are performed in relation to the boundaries of the box in which the item to be aligned is contained (or possibly to those of another box or viewport containing that box). With that in mind, it might be useful to clarify how the default box dimensions are set for common box types.
-
Box Width In regular block boxes, the box width will by default be the width of its container, which at the top level is usually the width of the portion of the screen containing the HTML display (the “viewport”).
This also applies to flex boxes (flex-block, not flex-inline), which in most of the ways in which they relate to their containers act the same as block boxes – they are by default as wide as their containers.
And this also applies to flex items (items or blocks within flex boxes), when the flex-direction is set to “column” (so that each item is on a separate row, as for regular block-items).
However, for flex items in a flex box with the default flex-direction of “row” (where the flex items are on the same row, or maybe fill the row and wrap to the next row), the contained flex items (boxes) will by default adjust to the width of their content (rather than of their container). (As a side note, if there are multiple flex items on one row, and their collective width exceeds that of the containing flex box, then they will each by default have a width proportionate to the width of their content relative to the widths of the other flex items in the row such that, if their contents wrap, and they have the same type of content, the (now multi-line) flex item boxes will tend to have the same height.)
-
Box Height In most cases, unless the height is explicitly assigned, block boxes are only as high as the height of their content.
This also applies to flex items when the flex direction is “column”.
For flex items within a flex box with a flex-direction of “row”, each item box will by default have the height of the flex container. If the height of the flex container is not explicitly set, then it will by default be the height of the contained flex item with the greatest height, which will then also be the default height for all the other flex items in the row. If the flex items wrap into multiple rows, the height of each flex item in a given row will be that of the item in that row with the greatest height, and the height of the flex container will be the sum of the height of each row (plus any top and/or bottom margins).
Declaring "text-align: center" for a container will center text within it. It will also center images, though that may not be recommended procedure and may not always be supported in the future. The following code will center the text:
HTML:
<div class='center-non-flex'>Text to be centered</div>
CSS:
.center-non-flex {
text-align: center;
}
Pretty straightforward. (Side note: some other values of “text-align” besides “center” are “left” (default), “right”, and “justify” (which makes all lines the same width with even left and right margins)).
-
Note on Using text-align within a Flexbox In a flex container with the default flex-direction of "row", "text-align" may not seem to work in the contained flex-items. This is because flex-items with flex-direction row are, by default, only the width of their contents, so any centering of their content will not be apparent (unless the item width is adjusted to be wider than the contents). This is not an issue if the flex-direction is column, where the flex items act more like regular blocks.
For a box with a width greater than that of its contents, its contents can be centered by setting the left and right margins to “auto”, e.g.
HTML:
<div class='center-using-auto-margin'>Text to be centered</div>
<img src=’img.jpg’ class=’center-using-auto-margin image’>
CSS:
.center-using-auto-margin {
width: 500px;
margin-left: auto;
margin-right: auto;
}
.image {
width: 200px;
}
Though this technique is more useful for vertical centering (see below), Position and Transform can be used to center horizontally as well. To do so, the content (image or text) is assigned the properties “position: relative” and “left: 50%” to put its left edge in the middle of the box (horizontally), then adjusted to the left by 50% of its own width by adding the property “transform: translateX(-50%)”. This will place it in the center of its container. (It's perhaps even less intuitive, but you could use “right: -50%” instead of “left: 50%”. In that case you would still use “transform: translateX(-50%)).
Note that if you have even padding and/or a border on the content, Position and Transform will still center it properly, even if the box-sizing is not border-box. However, having margins on the content on the reference sides for the translation (e.g. having a non-zero “margin-left” when using “left: 50%”) will throw off the translation.
If one wants to horizontally center content in a box that also contains other content to the left of the content that one wants to center, you may then have to use “position: absolute” (instead of “position: relative”) for the content, and make the box in which you want to center the content a “positioned” box by setting its position property to “relative” (but there's no need to actually reposition it with “left” or whatever).
Centering text and images with flex box is pretty straightforward. The most notable complication is that in flex box there is no “horizontal” or “vertical” axis per se, but rather a “main axis” and a “cross axis”. How these correspond depends on the “flex-direction” property. By default, the “flex-direction” is set to “row”, so that flex items line up horizontally. For “flex-direction: row”, and for “flex-direction: row-reverse”, which put the flex items on the same line (as long as there’s room), the main axis is horizontal, and the cross axis is vertical. If the “flex-direction” property is set to “column” (or to “column-reverse”), the flex items are by default on separate lines, in a column, and the main axis is vertical while the cross axis is horizontal.
To center flex items on the main axis, use “justify-content: center” (other possible values for “justify-content” are “flex-start”, “flex-end”, “space-between”, “space-around”, and “space-evenly”). If the “flex-direction” is “row” (or “row-reverse”), this will center the item or items horizontally (they will all be together at the center of the flex container). If the “flex-direction” is “column” (or “column-reverse”), this will center the item or items vertically.
To center flex items on the cross axis, one can use “align-items: center”. For the default flex-direction of “row”, this will place all items in the vertical center of the box (box height will have to be set for this to be seen, otherwise the height of the box will just be the height of the contents, plus padding and margins). If the flex-direction is “column”, “align-items: center” will center the items horizontally. If there are multiple items or lines of text, they will all group together in the center.
If one wishes instead to spread the items on the cross axis evenly, one can use “align-contents: center”. For a single item (or line of text) this will work the same as “align-items: center”, but for multiple items or lines it will distribute the extra cross-axis space evenly around the items. (to get a similar effect on the main axis, one would use “justify-content: space-around”).
To center text vertically in a non-flex container, there is no convenient built-in syntax, but there are a few ways of accomplishing the task.
(The methods below work for vertical centering whether or not the container is flex):
-
1. One method is by manually setting the vertical margins and/or padding. This requires knowing the height of the content and container boxes in advance, and that neither change with screen size. Generally not the best method to use.
-
2. Another method is that, for one line of text, you can set the line-height equal to the height of the container, or to the height you want the container to be, as shown below (also centers horizontally):
HTML: <div class='center-non-flex'>Text to be centered</div> CSS: .center-non-flex { height: 200px; /* This is unnecessary – without this code box height will just be the line-height */ text-align: center; line-height: 200px border: 1px solid; }
To vertically center multiple lines of text one could divide the line height by the number of lines to spread them out vertically. To center them all together you would have to put them into another container and use one of the techniques described below on that container.
-
3. Center vertically using padding. For some reason this only works if you do not set the container height. But you can decide how high you want the container to be and use top and bottom padding to center your lines:
HTML: <div class='center-non-flex'> <p>Text to be centered</p> <p>2nd line</p> </div> CSS: .center-non-flex { text-align: center; padding: 90px 0 90px 0; border: 1px solid }
Position and Transform can be used to center images or text vertically (as well as horizontally). The content (image or text) is set to have “position: relative” and “top: 50%” to put its top edge in the middle of the box (vertically), then adjusted up by 50% of its own height by adding the property “transform: translateY(-50%)”. This will place it in the center of its container. (Of course, as always, the container has to have a height set higher than that of the content). E.g.:
HTML:
<div class=’container’>
<img src=’img-to-center.jpg’ class=’center-vertically-position-transform image’>
</div>
CSS:
.container {
height: 400px;
}
.center-vertically-position-transform {
position: relative;
top: 50%;
transform: translateY(-50%);
}
.image {
height: 200px;
}
Note that to vertically center text or an image in a container using Position and Transform, the text has to be in its own sub-container within the container that it’s being centered in, so that the Position and Transform properties can be applied to the content and not the outer container. E.g.
HTML:
<div id=’container’>
<div id=’text-to-center’>
Text to center using Position and Transform
</div>
</div>
CSS:
#container {
height: 400px;
}
#text-to-center {
position: relative;
top: 50%;
transform: translateY(-50%);
}
Above, the “position: relative” “top: 50%”* moves the “text-to-center” division down 50% of the height of its container (the division “container”). The “transform: translateY(-50%)” then moves it back up 50% of its own height. If the “text-to-center” division were not there, and/or the Position and Transform values were instead assigned to “#container”, the container itself would be adjusted relative to its container, and its contents would not be vertically centered.
*if one wanted to, one could use “bottom: -50%” instead of “top: 50%”.
As when using Position and Transform for horizontal centering, for vertical centering, if you have even padding and/or a border on the content, Position and Transform will still center it properly, even if the box-sizing is not border-box. In fact, Position and Transform will even center an item that, with padding and border, is larger than its container. However, having margins on the content on the reference sides for the translation (e.g. having a non-zero “margin-top” when using “top: 50%”) will throw off the translation.
If there is another item or are other items in the box between the item being centered and the top of the container, the item will still be moved down by 50% of the container height, but not from the top of the container -- it will be moved down from the position it would have occupied under the other item(s), placing it more than half-way down the box (and also more than half-way down the part of the box under the other item). In this situation, if one still wanted to center the item within the container, you would have to use “position: absolute” so that the item is adjusted relative to the container rather than to the position the item would have been in normally. This, in turn, requires that you make the container a “positioned” item, which can be done by giving it a “position” property of “relative”, but with no need to set an offset (like “top” or “left”). (I have not found a way to achieve this effect elegantly in flexbox – an example of why it’s helpful to know multiple alignment techniques. Also an example of why I wonder why there isn’t a “self” alignment property in flexbox for the main axis analogous to the “align-self” property for the cross-axis). Also note that when using “position: absolute”, the item’s box width, if it had otherwise defaulted to the width of its container, will instead default to the width of its contents. At least, that’s what my tests have shown. However, it can still be explicitly reset to another width or back to the container width (using “width: 100%").
Another possibility: If you know the height of the item(s) above the item to be centered, you can still use position: relative, but use a negative top margin equal to the height of item(s) above the item being centered.
To center both vertically and horizontally can use top 50%, left 50% and transform: translate(-50%, -50%) OR could use top 50% and transformY(-50%) then use margin-left: auto and margin-right: auto. But unlike transformX(), auto margins will only work if the contents are smaller than the container.
Another way to get and item to center vertically without using flexbox is to make the container a table cell, then use the vertical-align property of table cells to align the item. This is perhaps a bit conceptually easier than Position and Transform, and, like Position and Transform, does not require knowing the dimensions of the container or the contents. Unlike Position and Transform, and like Flexbox and text-align, it operates at the level of the container rather than of the content.
CSS (for the container):
display: table-cell;
height: 200px;
vertical-align: middle;
- Notes:
-
There is no “horizontal-align” – table cells typically use “text-align” for that purpose.
-
Other possible values of vertical-align are “baseline”, “top”, “bottom”, “sub”, and “text-top”.
-
It appears that a floated box cannot be made into a table-cell. However, one can put another box inside the floated box, make THAT box into a table-cell, and proceed as above.