我知道这已经有几年的历史了,但是在为项目编写重置样式表时,我会在对问题进行一些调查后添加我的想法。
注意** 这是基于浏览 Firefox 源代码,因为它是最容易获得和通读的。但是,基于其他浏览器中的类似行为,实现可能是相似的。
首先,这里的主要问题是元素 - 至少在 Firefox 中 - 是用标签和它的子<button>
元素之间的内部元素构建的。<button>
在 Firefox 中,它被称为moz-button-content
并且不是 CSS 可以达到的东西,并且已设置为显示块而不继承按钮的高度,您可以在useragent 样式表中看到此样式声明:
来自“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;
}
因为你不能影响这个元素的任何样式,你不得不在<button>
标签上添加你的样式。这导致了第二个问题 -浏览器被硬编码以垂直定位按钮的内容。
从“源/布局/表单/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>
这个 bug和Firefox 问题跟踪器中的这个 bug 与我发现的任何实际记录的 bug 差不多。但是线程给人的印象是,尽管这没有出现在任何实际规范中,但浏览器只是以这种方式实现了它“因为其他浏览器正在这样做”
如果您确实想更改默认行为,则可以解决此问题,但它并不能完全解决问题和 YMMV,具体取决于您的实现。
如果您插入一个包装器<span>
作为display: block
按钮的唯一子级并将所有内容放入其中,您可以使用它来跳过moz-button-content
元素。
您需要使该<span>
元素具有height: inherit
正确填充按钮的高度,然后将您的正常按钮样式添加到其中<span>
,您将获得您想要的基本行为。
* {
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>
还值得一提的是外观CSS4 规则(尚不可用):
虽然这不是一个可行的选择(截至 1 月 5 日)。有一项提议重新定义appearance
CSS4 草案中的规则,这实际上可能会做正确的事情,即删除浏览器所做的所有假设。我只是为了完整性而提到它,因为它将来可能会变得有用。
更新 - 30/08/2016
您实际上应该使用 a<span>
而不是 a <div>
,因为div
's 不是<button>
元素的有效子级。我已经更新了答案以反映这一点。