Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现 inline-block 与文本的垂直居中 #75

Open
leeenx opened this issue Apr 16, 2018 · 5 comments
Open

实现 inline-block 与文本的垂直居中 #75

leeenx opened this issue Apr 16, 2018 · 5 comments
Labels

Comments

@leeenx
Copy link
Contributor

leeenx commented Apr 16, 2018

背景

我以前是认为「vertical-align: middle」是垂直居中的意思,并还吐槽为什么浏览器都没有做到这一点。最近才发现,原来不是这样的。

来看一下 vertical-align: middle 的官网解释:

middle
Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

元素的中垂点与 父元素的基线加1/2父元素中字母x的高度 对齐。

简单地说,vertical-align: middle 的位置往往比几何中线低一点,具体数值由 font-size 与 font-family 共同决定,我经常是使用 vertical-align: middle + top: -2px 来做垂直居中的 hack。

以下是网上的一张图片:

image

优雅地实现垂直居中

使用相对定位的 top 的取值不是固定的,很容易因为字体大小改变而发生变化。有资料说:内联元素的对齐受太多因素影响,因此不可能用 CSS 实现。

但我觉得在一定条件下,完全是可以使用 CSS 实现垂直居中的。以下是我觉得可以实现垂直居中的限制条件:
文本与 inline-block 元素混合,inline-block 的高度小于 line box 的 line-height

垂直居中的前提是要绕过 baseline (这个跟 font-size 的大小相关),所以我们可以选用 topbottom,因为它只跟 line box 的高度相关,因为有前提限制,所以 line box 的高度就是 line-height。

.wrapper { 
    font-size: 14px; 
    line-height: 2; 
    background: #efefef;  
}
.arrow {
    display: inline-block; 
    vertical-align: top; 
    width: 16px; 
    height: 16px; 
    border-radius: 100%; 
    background-color: #333; 
    position: relative; 
    top: #{(28 - 16)/2}px; 
}

image

这个文案也适用于 line-height 与 inline-block 元素高度相近时。如果 inline-block 远大于 line-height,可以直接使用 vertical-align: middle 实现,毕竟大尺寸下,几个像素根本不值一提。

font-size: 0; 实现垂直居中

我原来有个错误的理解:line-height: 0时,vertical-algin 的所有参考线都会合并在一起,于是有以下代码:

.wrapper { 
    font-size: 14px; 
    line-height: 0; 
    padding: 7px;
    background: #efefef;  
}
.arrow {
    display: inline-block; 
    vertical-align: middle; 
    width: 16px; 
    height: 16px; 
    border-radius: 100%; 
    background-color: #333;
}

文本并没有完美地居中,如下:

image

原因是明显的:line-height 只能决定vertical-align 的 top & bottom 的初始值。真正能把 vertical-align 所有线(除了 top & bottom)合并在一起的是 font-size: 0。所以,代码可以改成:

.wrapper { 
    font-size: 0; 
    line-height: 28px; 
    padding: 7px;
    background: #efefef;  
}
.inline-block { 
    font-size: 14px; 
    vertical-align: middle; 
}
.arrow {
    display: inline-block; 
    vertical-align: middle; 
    width: 16px; 
    height: 16px; 
    border-radius: 100%; 
    background-color: #333;
}

如下:

image

这个方案有两个问题:

  1. 只能应用于单行
  2. 所有文本都需要一个额外的 inline box 包起

参考资料:

https://zhuanlan.zhihu.com/p/25808995?group_id=825729887779307520
http://www.zhangxinxu.com/wordpress/2010/05/%E6%88%91%E5%AF%B9css-vertical-align%E7%9A%84%E4%B8%80%E4%BA%9B%E7%90%86%E8%A7%A3%E4%B8%8E%E8%AE%A4%E8%AF%86%EF%BC%88%E4%B8%80%EF%BC%89/
https://www.w3.org/TR/CSS2/visudet.html#line-height

@leeenx leeenx added the CSS label Apr 16, 2018
@leeenx leeenx changed the title vertical-align: middle; 垂直居中陷阱 实现 inline-block 与文本的垂直居中 Apr 16, 2018
@h5m1007
Copy link

h5m1007 commented Oct 15, 2018

很不错 虽然现在是flex布局当道 但某些hack技巧也要识知

@xxvv
Copy link

xxvv commented Dec 24, 2018

移动端这个方法适用否? 安卓垂直出现文字向上偏移的情况。高度较大的时候直接使用flex看不出问题,而高度较小的很明显,不管高度多少文字都是偏上,具体看font-size的大小,我测试是font-size为16的时候上下的距离最接近

@leeenx
Copy link
Contributor Author

leeenx commented Dec 24, 2018

@xxvv 适用的。不过,有一些字体(主要是中文字体)在不同系统上渲染会偏上或偏下,这时候会有对不齐的问题。如果是文字没有居中对齐的话,其实是另一个问题。如果是单行的话,我一般使用以下方法来解决:

&::before {
  content: '\20';
  font-family: '宋体', sans-serif;
}

一般 windows 下,使用宋体可以纠正中文的垂直居中问题。sans-serif 则是针对 ios 系统。

@xiaotianhu
Copy link

hack不错,解决了问题.赞一个

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants
@xiaotianhu @leeenx @xxvv @h5m1007 and others