How to vertically align text inside a flexbox?
Instead of using align-self: center
use align-items: center
.
There's no need to change flex-direction
or use text-align
.
Here's your code, with one adjustment, to make it all work:
ul {
height: 100%;
}
li {
display: flex;
justify-content: center;
/* align-self: center; <---- REMOVE */
align-items: center; /* <---- NEW */
background: silver;
width: 100%;
height: 20%;
}
The align-self
property applies to flex items. Except your li
is not a flex item because its parent – the ul
– does not have display: flex
or display: inline-flex
applied.
Therefore, the ul
is not a flex container, the li
is not a flex item, and align-self
has no effect.
The align-items
property is similar to align-self
, except it applies to flex containers.
Since the li
is a flex container, align-items
can be used to vertically center the child elements.
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
ul {
height: 100%;
}
li {
display: flex;
justify-content: center;
/* align-self: center; */
align-items: center;
background: silver;
width: 100%;
height: 20%;
}
<ul>
<li>This is the text</li>
</ul>
codepen demo
Technically, here's how align-items
and align-self
work...
The align-items
property (on the container) sets the default value of align-self
(on the items). Therefore, align-items: center
means all flex items will be set to align-self: center
.
But you can override this default by adjusting the align-self
on individual items.
For example, you may want equal height columns, so the container is set to align-items: stretch
. However, one item must be pinned to the top, so it is set to align-self: flex-start
.
example
How is the text a flex item?
Some people may be wondering how a run of text...
<li>This is the text</li>
is a child element of the li
.
The reason is that text that is not explicitly wrapped by an inline-level element is algorithmically wrapped by an inline box. This makes it an anonymous inline element and child of the parent.
From the CSS spec:
9.2.2.1 Anonymous inline boxes
Any text that is directly contained inside a block container element must be treated as an anonymous inline element.
The flexbox specification provides for similar behavior.
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each contiguous run of text that is directly contained inside a flex container is wrapped in an anonymous flex item.
Hence, the text in the li
is a flex item.
The best move is to just nest a flexbox inside of a flexbox. All you have to do is give the child align-items: center
. This will vertically align the text inside of its parent.
// Assuming a horizontally centered row of items for the parent but it doesn't have to be
.parent {
align-items: center;
display: flex;
justify-content: center;
}
.child {
display: flex;
align-items: center;
}
The most voted answer is for solving this specific problem posted by OP, where the content (text) was being wrapped inside an inline-block
element. Some cases may be about centering a normal element vertically inside a container, which also applied in my case, so for that all you need is:
align-self: center;
RESULT
HTML
<ul class="list">
<li>This is the text</li>
<li>This is another text</li>
<li>This is another another text</li>
</ul>
Use align-items
instead of align-self
and I also added flex-direction
to column
.
CSS
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
}
.list {
display: flex;
justify-content: center;
flex-direction: column; /* <--- I added this */
align-items: center; /* <--- Change here */
height: 100px;
width: 100%;
background: silver;
}
.list li {
background: gold;
height: 20%;
}