是啥让 <button> 元素上的文本垂直居中?

Posted

技术标签:

【中文标题】是啥让 <button> 元素上的文本垂直居中?【英文标题】:What makes the text on a <button> element vertically centered?是什么让 <button> 元素上的文本垂直居中? 【发布时间】:2019-12-24 20:39:39 【问题描述】:

似乎&lt;button&gt;element 周围有一些我不明白的魔力。

考虑这个标记:

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

还有这个 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;*/

是什么让按钮元素中的文本垂直居中? Webkit 似乎为&lt;button&gt; 元素预定义了一个-webkit-box-align,其值为center。如果我将其设置为initial,则文本不再与中心对齐。但这似乎不是全部的魔法,因为另一方面,我没有运气使用 -webkit-box-align 属性将文本集中在 div 上。

这是一个小提琴:http://jsfiddle.net/cburgdorf/G5Dgz/

【问题讨论】:

你在多个浏览器上试过了吗?我不确定,但这可能是必须重置浏览器样式的问题。另外,也许这会让您使用按钮更容易找到解决方案? cssbuttongenerator.com 。它并不完美,但每当我想寻找新的按钮样式时,它都非常好用且易于使用。 这里有一个 button 添加到 div jsfiddle.net/v89Bh/2 的默认 webkit css 的小提琴,但这不会给你(我们)你的问题的答案 html 表单元素至少部分由本机操作系统呈现,这就是为什么它们历来如此难以设计的原因。确切的样式并不总是可以用 CSS 样式来解释。 @Johan 但即使在将所有 webkit 默认样式应用于 div 之后,文本仍然没有居中。 @MattCoughlin 是的,我想知道这是否也会影响这个案例。另一方面,按钮似乎对-webkit-box-align 做出反应,但我不明白为什么 div 没有对此做出反应...... 【参考方案1】:

默认情况下,按钮元素垂直居中子元素。它不是以传统的 CSS 方式完成的,因此重写并非易事。

我发现的最佳解决方案是将按钮设置为 flex 列。

button 
  height: 100px; 
  display: flex; 
  flex-direction: column; 


span 
  height: 20px; 
  width: 100px; 
  background-color: blue; 
  display: block; 
<button>
  <span></span>
</button>

一些答案​​建议添加一个内部包装器,并将其高度设置为继承。这可能不适用于动态计算高度的元素。

【讨论】:

【参考方案2】:

如果您需要摆脱这种行为,您可以将span 添加为button 的子代。比试图欺骗所有浏览器效果更好。

【讨论】:

【参考方案3】:

我知道这已经有几年的历史了,但我会在为项目编写重置样式表时对问题进行一些调查后添加我的想法。

注意**这是基于浏览 Firefox 源代码,因为它是最容易获得和阅读的。但是,基于其他浏览器中的类似行为,实现可能是相似的。

首先,这里的主要问题是 &lt;button&gt; 元素 - 至少在 Firefox 中 - 是在 &lt;button&gt; 标记和它的子标记之间使用内部元素构建的。在 Firefox 中,它被称为 moz-button-content,它不是 CSS 可以达到的,并且已设置为显示块而不继承按钮的高度,您可以在 useragent stylesheet 中看到此样式声明:

来自“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;

因为你不能影响这个元素的任何样式,你不得不在&lt;button&gt;标签上添加你的样式。这就引出了第二个问题——浏览器是hard coded to vertically position按钮的内容

来自“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);

鉴于这两个问题,您可以开始了解按钮如何强制内容居中,请考虑:

   <button> tag

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

如果你给button 一个高度 - 就像你的小提琴中的48px 一样,文本将居中,因为moz-button-content 元素是显示块并且只有内容的高度(很可能是行- 默认情况下内容的高度),当放在另一个元素旁边时,您会得到这种行为:

* 
  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>

Firefox 问题跟踪器中的This bug 和this bug 几乎接近我可以找到的任何实际记录的错误。但是线程给人的印象是,尽管这没有出现在任何实际规范中,但浏览器只是以这种方式实现了它,“因为其他浏览器正在这样做”


如果您确实想更改默认行为,可以解决此问题,但它并不能完全解决问题和 YMMV,具体取决于您的实现。

如果您插入一个包装器&lt;span&gt; 并将display: block 作为按钮的唯一子级并将所有内容放入其中,您可以使用它来跳过moz-button-content 元素。

您需要使这个&lt;span&gt; 元素具有height: inherit,以便它正确地填充按钮的高度,然后将您的正常按钮样式添加到&lt;span&gt;,您将获得您想要的基本行为。

    * 
      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>

还值得一提的是appearance CSS4 规则(尚不可用):

虽然这不是一个可行的选择(截至 1 月 5 日)。有一个提议重新定义 CSS4 草案中的appearance 规则,这实际上可能会做正确的事情,即删除浏览器所做的所有假设。我只是为了完整性而提及它,因为它将来可能会变得有用。

更新 - 2016 年 8 月 30 日 您实际上应该使用&lt;span&gt; 而不是&lt;div&gt;,因为div 不是&lt;button&gt; 元素的有效子代。我已经更新了答案以反映这一点。

【讨论】:

现在,这就是答案!感谢您花时间编写它。【参考方案4】:

我认为这种行为的唯一原因是 Google Chrome 或一般浏览器会采用您操作系统的默认样式。

例如,如果您比较在 Windows 7 和 Windows 8 中运行的 Google Chrome 上的按钮或滚动条:

在 Windows 7 中,按钮的中心会有一条水平渐变线

在 Windows 8 中,滚动条能够在单击时淡入淡出

这只是我的看法,希望能给你一些想法:)

【讨论】:

【参考方案5】:

在 Mozilla Firefox 上,我得到了 -moz-appearance 属性:

-moz-appareance: button;

在 HTML5 草稿中,有一个Rendering section,但没有详细说明展示位置:S

【讨论】:

但即使我设置了-webkit-appearance: button; -webkit-box-align: center;,div 也不会像按钮那样呈现。 我知道有一些内部样式的 UI 元素,例如微调按钮和类似的东西。我认为将它们开放给用户样式是一项正在进行的工作。也许你描述的行为属于这一类。 有趣。我一直生活在错误的假设中,即在 2013 年,元素的所有样式都完全使用预定义的 CSS 完成。【参考方案6】:

您可以使用display:table-cell; vertical-align: middle; 作为替代方法。

【讨论】:

谢谢。我也知道这种技术。在弄清楚浏览器如何使其居中之后,我更加关注。【参考方案7】:

你可以使用填充。

例如

padding: 20px 10px;

【讨论】:

是的,这是另一种使文本居中的解决方案。但是,我更了解 webkit 对文本居中的作用。因为好像和-webkit-box-align有关系 这正是按钮类型元素的样式以获得垂直居中效果。 是的,这是真的。这不是问题:)

以上是关于是啥让 <button> 元素上的文本垂直居中?的主要内容,如果未能解决你的问题,请参考以下文章

F# 性能:是啥让这段代码如此缓慢?

单击 <button> 元素时的标准行为是啥?它会提交表格吗?

是啥让线程的执行顺序不可预测?

如何在 <button> 元素中使用光标选择文本?

HTML <span> 标签是啥意思?怎么用?

是啥让某些蓝牙设备在 iOS“我的设备”中列出?