Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What makes the text on a <button> element vertically centered?

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/

like image 818
Christoph Avatar asked Apr 02 '13 12:04

Christoph


People also ask

How do I center text vertically in a button?

Use line-height to center it vertically. I usually use the same value as its height. Works only when you know the height. I set height to 0 and line-height to zero and this worked!

How do you vertically align text in an element?

Answer: Use the CSS line-height property Suppose you have a div element with the height of 50px and you have placed some link inside the div that you want to align vertically center. The simplest way to do it is — just apply the line-height property with value equal to the height of div which is 50px .

How do I align a button vertically in CSS?

It does seem to require "vertical-align: middle" for both IMG and BUTTON. Show activity on this post. You have to increase width of the class btn to width: 251px; because inside the button you set 14px font-size which takes more than 240px ok and you have initialized 200px which cause align break.

How do I center text in a button in Webflow?

To fix this, choose your Button wrapper in the Navigator, and in the Style panel under Layout, set Display to center.


1 Answers

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>

This bug and this bug in the Firefox issue tracker was about a close as I could find to any actually documented bug. But the threads give the impression that despite this not appearing in any actual spec, the browsers have just implemented it this way "because the other browsers are doing it that way"


There is a work-around to the issue if you actually want to change the default behaviour, but it doesn't completely solve the problem and YMMV depending on your implementation.

If you insert a wrapper <span> with display: block as the only child of the button and put all your content inside it you can use it to skip over the moz-button-content element.

You will need to make this <span> element have height: inherit so it correctly fills the height of the button and then add your normal button styling to the <span> instead, you will get basically behaviour you want.

    * {        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;      }      button::-moz-focus-inner {        border: 0;        padding: 0;        outline: 0;      }        button > span {        display: block;        height: inherit;      }        a {        display:inline-block;        background: green;      }        button.styled > span , a.styled{        padding: 10px;        background: yellow;      }
    <button><span>Button content</span></button>      <a><span>Link Content<span></a><br/>      <button class="styled"><span>Button content</span></button>      <a class="styled"><span>Link Content<span></a>

It's also worth mentioning the appearance CSS4 rule (Not yet available):

While this is not a viable option (as of the 5th January) yet. There is a proposal to redefine the appearance rule in the CSS4 draft that might actually do the right thing an remove all assumptions made by the browser. I only mention it for completeness because it may become useful in the future.

UPDATE - 30/08/2016 You should actually use a <span> instead of a <div>, as div's aren't valid children for <button> elements. I have updated the answer to reflect this.

like image 112
Cubed Eye Avatar answered Sep 22 '22 23:09

Cubed Eye