Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

It seems there is some magic around the <button>element that I don't understand.

Consider this markup:

<button class="button">Some Text</button>
<div class="button">Some Text</div>

And this CSS:

.button{
    background: darkgrey;
    height: 40px;
    border: 2px solid grey;
    width: 100%;
    box-sizing: border-box;
    font-size: 14px;
    font-family: helvetica;
    text-align: center;
    margin-bottom: 20px;

    /*I'm aware I could use this to center it*/
    /*line-height: 40px;*/
}

What makes the text in the button element vertically centered? Webkit seems to predefine a -webkit-box-align with a value of center for the <button> element. If I set that to initial the text is no longer aligned to the center. But that doesn't seem to be the full magic, since on the other hand I had no luck centering the text on the div using the -webkit-box-align property.

Here is a fiddle: http://jsfiddle.net/cburgdorf/G5Dgz/

question from:https://stackoverflow.com/questions/15764600/what-makes-the-text-on-a-button-element-vertically-centered

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
130 views
Welcome To Ask or Share your Answers For Others

1 Answer

I know this is a couple of years old, but I'll add my thoughts after some investigation in to issue while writing a reset stylesheet for a project.

NOTE** This is based on looking through the Firefox source because it was the easiest to obtain and read through. However, based on similar behaviour in other browsers the implementation is probably similar.

Firstly, the main issue here is that <button> elements - atleast in Firefox - are built with an internal element between the <button> tag and it's children. In Firefox it's called moz-button-content and isn't something that can be reached with CSS and has been set to display block without inheriting the height of the button, you can see this style declaration in the useragent stylesheet:

From "source/layout/style/res/forms.css"

*|*::-moz-button-content {
    display: block;
    /* Please keep the Multicol/Flex/Grid/Align sections below in sync with
       ::-moz-scrolled-content in ua.css and ::-moz-fieldset-content above. */
    /* Multicol container */
    -moz-column-count: inherit;
    -moz-column-width: inherit;
    -moz-column-gap: inherit;
    -moz-column-rule: inherit;
    -moz-column-fill: inherit;
    /* Flex container */
    flex-direction: inherit;
    flex-wrap: inherit;
    /* -webkit-box container (aliased from -webkit versions to -moz versions) */
    -moz-box-orient: inherit;
    -moz-box-direction: inherit;
    -moz-box-pack: inherit;
    -moz-box-align: inherit;
    /* Grid container */
    grid-auto-columns: inherit;
    grid-auto-rows: inherit;
    grid-auto-flow: inherit;
    grid-column-gap: inherit;
    grid-row-gap: inherit;
    grid-template-areas: inherit;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    /* CSS Align */
    align-content: inherit;
    align-items: inherit;
    justify-content: inherit;
    justify-items: inherit;
}

Because you can't affect any of the styles on this element, you are forced to add you styling on the <button> tags. This leads into the second issue - The browser is hard coded to vertically position the content of the button.

From "source/layout/forms/nsHTMLButtonControlFrame.cpp"

// Center child in the block-direction in the button
// (technically, inside of the button's focus-padding area)
nscoord extraSpace =
    buttonContentBox.BSize(wm) - contentsDesiredSize.BSize(wm);

childPos.B(wm) = std::max(0, extraSpace / 2);

// Adjust childPos.B() to be in terms of the button's frame-rect:
childPos.B(wm) += clbp.BStart(wm);

nsSize containerSize = (buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm);

// Place the child
FinishReflowChild(aFirstKid, aPresContext, contentsDesiredSize,
                  &contentsReflowInput, wm, childPos, containerSize,
                  ReflowChildFlags::Default);

Given these two issues you can start to see how the button force the content to be centered, consider:

   <button> tag

+------------------------+ ^
| button extra space     | |
|                        | |
+------------------------+ |
|| ::moz-button-content || | button height
||   display: block;    || |
+------------------------+ |
|                        | |
| button extra space     | |
+------------------------+ v

If you give the button a height - like the 48px from your fiddle, the text will be centered because the moz-button-content element is display block and will only have the height of the content (most likely the line-height of the content by default) and when put next to another element you get this behaviour:

* {
  box-sizing: border-box;
  margin: 0;
  border: 0;
  padding: 0;
  font-family: san-serif;
  background: none;
  font-size: 1em;
  line-height:1;
  vertical-align: baseline;
 }

button, a {
  height: 3em;
}

button {
  background: red;
}

a {
  display:inline-block;
  background: green;
 }
<button>Button content</button>
<a>Link Content</a>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...