I found that the text inside of <button>
is automatically vertically centered, while text inside of <div>
is top aligned.
I tried to find out which CSS rule made the difference but failed.
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text text</div>
<button>text text</button>
<div>text text text text</div>
<button>text text text text</button>
<div>text text text text text text</div>
<button>text text text text text text</button>
As for the above example, comparing all the computed CSS rules from Chrome, I could only find one different pair -- align-items: stretch
for <div>
while align-items: flex-start
for <button>
.
But assigning align-items: flex-start
doesn't help. So I got totally confused.
what confused me is that the text-vertical-alignment is different between <div>
and <button>
even if you set all the CSS rules with the same corresponding value. In other words, with the same CSS rules, <div>
and <button>
behave differently. Why?
What is the magic under the hood?
I can vertically center text inside of <div>
(example below). I'm just curious about what causes the difference between the text-vertical-alignment.
Maybe it's not caused by a particular CSS rule, but because the layout algorithms for the two elements are different in browser?
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
}
div { /* basic CSS rules to button-fy */
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
/* Magic */
div, button {
vertical-align: middle;
}
div span {
display: inline-block;
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
<div><span>text text</span></div>
<button>text text</button>
<div><span>text text text text</span></div>
<button>text text text text</button>
<div><span>text text text text text text</span></div>
<button>text text text text text text</button>
The CSS just sizes the div, vertically center aligns the span by setting the div's line-height equal to its height, and makes the span an inline-block with vertical-align: middle. Then it sets the line-height back to normal for the span, so its contents will flow naturally inside the block.
Other than flexbox property, we can also center align the button horizontally and vertically using a set of CSS properties. Add position: relative to the container class and position: absolute to the class containing the button. Now use left:50% and top:50% to position the button to the center of the container.
CSS Demo: vertical-align The vertical-align property can be used in two contexts: To vertically align an inline element's box inside its containing line box. For example, it could be used to vertically position an image in a line of text. To vertically align the content of a cell in a table.
Since you are using inline-block
, you need to use vertical-align
as the default is baseline
:
Magic CSS:
vertical-align: middle;
The above will fix it:
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
vertical-align: middle;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text</div>
<button>text</button>
And for the text inside the div
to be centred, you need to use line-height
to the height
of the div
.
Magic CSS:
line-height: 4em;
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
vertical-align: middle;
line-height: 4em;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text</div>
<button>text</button>
If you look at Chrome source code you can kind of see how it works, at least for Chrome. It seems there's an anonymous flex box created with a specific style applied. It's not that straightforward — at least not for me — but still, you can deduce what style is applied to this anonymous element. You can see here: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/layout/LayoutButton.cpp?sq=package:chromium
The interesting part:
void LayoutButton::updateAnonymousChildStyle(const LayoutObject& child,
ComputedStyle& childStyle) const {
ASSERT(!m_inner || &child == m_inner);
childStyle.setFlexGrow(1.0f);
// min-width: 0; is needed for correct shrinking.
childStyle.setMinWidth(Length(0, Fixed));
// Use margin:auto instead of align-items:center to get safe centering, i.e.
// when the content overflows, treat it the same as align-items: flex-start.
childStyle.setMarginTop(Length());
childStyle.setMarginBottom(Length());
childStyle.setFlexDirection(style()->flexDirection());
childStyle.setJustifyContent(style()->justifyContent());
childStyle.setFlexWrap(style()->flexWrap());
// TODO (lajava): An anonymous box must not be used to resolve children's auto
// values.
childStyle.setAlignItems(style()->alignItems());
childStyle.setAlignContent(style()->alignContent());
}
This gives something like this :
div span {
display: flex;
text-align: center;
min-width: 0px;
flex-grow: 1;
justify-content: center;
cursor: default;
margin: 0 auto;
height: 100%;
align-items: center;
align-content: center;
}
Then you just need to wrap the div content in that span and apply the style. All these rules are probably not all necessary or accurate but the result seems ok:
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
float: left;
}
div span {
display: flex;
text-align: center;
min-width: 0px;
flex-grow: 1;
justify-content: center;
cursor: default;
margin: 0 auto;
width: 100%;
height: 100%;
align-items: center;
align-content: center;
}
<div><span>text text</span>
</div>
<button>text text</button>
<div><span>text text text text</span>
</div>
<button>text text text text</button>
<div><span>text text text text text text</span>
</div>
<button>text text text text text text</button>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With