CSS学习笔记:导航文字垂直居中

25 Mar 2016 , 3485 words

报名成功百度的前端学院挑战之后,我的两名队友就很快消失了。磊神看了遍题说太简单没意思,皇上嘴上说要做要做身体却去了GDC。于是我一个人开始写,能写几个是几个吧。这个学习笔记来自第二题里面的导航垂直居中。新手向。

垂直居中比水平居中麻烦。尤其是像我这样的初学者,望文生义觉得一个 vertical-align:middle 应该就可以搞定,却往往不奏效,很挫败。 这篇老文里用三句话总结了这个问题的根源:

  1. HTML layout traditionally was not designed to specify vertical behavior. By its very nature, it scales width-wise, and the content flows to an appropriate height based on the available width. Traditionally, horizontal sizing and layout is easy; vertical sizing and layout was derived from that.
  2. The reason vertical-align:middle isn’t doing what is desired want is because the author doesn’t understand what it’s supposed to do, but …
  3. … this is because the CSS specification really screwed this one up (in my opinion)—vertical-align is used to specify two completely different behaviors depending on where it is used.

  1. HTML设计时重点就是在水平布局上,垂直上基本指导思想是简单粗暴的「宽不够,高来凑」。 这就从根本上导致水平上调整起来容易,垂直上比较难。
  2. vertical-align 不好用的原因很简单,那就是我们用错了,它不是类似 text-align:center 那样直接的用法。
  3. 而这种误用也怪不得大家,是CSS的设计者在一开始就设计的很奇葩:同一个 vertical-align 在两种情景下,作用完全不同。

具体来说,在 table 中,如果一个单元格的CSS里写了 vertical-align:middle,那么这个单元格就会像我们预期的那这样,内容垂直居中显示。同理,如果是 vertical-align:bottom,则是贴近底部显示:

vertical-align:middle居中(默认) vertical-align:bottom 底部

但前边说了,这只是在 table 这一种情境下。作为其他行内元素的样式时,vertical-align的作用则完全不同:它决定的,与其说是一个元素在父元素中的垂直位置,不如是同一行里的多个元素以什么基准线对齐。

CSS-Tricks的这篇文章将这种情况下 vertical-align 的作用及其几种常见值梳理的很清楚。比如以下几个:

baseline alignment 默认的基线对齐

middle alignment 常用的中间对齐。将元素的垂直中点,与父元素中小写字母的垂直中点对齐。

top alignment 顶部对齐。将元素顶部与行顶部对齐。

bottom alignment 底部对齐。将元素底部与行底部对齐。

看上去很直观,但我最烦CSS的一点就是表面看起来都是理所当然的废话,一写全是坑。上边这几条,尤其是在「居中」时候最喜欢的 vertical-align:middle,实际使用中,并不是表面上读来那么容易理解。比如让icon对齐文字这么一个简单需求,实际写出来,总是诡异地差着那么几个像素。更多的时候,可能是写完自信满满的一刷新,发现页面根本没啥变化。

这篇《Vertical-Align: All You Need To Know》是我找到的最说人话的解释了,但读了三遍了还是似懂非懂,下篇博文就专门翻译下,帮助自己理解好了。

最后说下我找到的让文字导航居中的3个方案:

1.table + table-cell + vertical-display:middle

既然前边说过 vertical-aligntable 中十分听话好使,让文字往哪里对齐就往哪里对齐。那就把要对齐的东西当成表格处理。具体做法是,给要对齐的元素的 父元素display:table,给要对齐的元素 本身 添加 display:table-cell,然后再用 vertical-align:middle 就可以了。

HTML:

<div>
  <ul>
    <li><a>导航项目1</a></li>
    <li><a>导航项目2</a></li>
    <li><a class="text_bottom_alligned">体重过大的导航项目3</a></li>
  </ul>
</div>

CSS:

li{
  list-style: none;
  margin-left: 50px;
  height: 60px;
  float: left;
  display: table;
}
a{
  display: table-cell;
  vertical-align: middle;
}

a.text_bottom_alligned{
  vertical-align: bottom;
} 

2.绝对定位

抛弃不好懂的 vertical-align,直接用绝对定位。具体做法是,将要对齐的元素设置为 position:absolute (相应的父元素应该为 position:relative),然后用 top:50% 让元素顶部垂直居中,再用 margin-top: -5(此处数值应该为元素高的1/2)或 transform: translate(0, -50%) 抵消被挤下去的位置,完成居中。

HTML:

<div>
  <ul>
    <li><a>导航项目1</a></li>
    <li><a>导航项目2</a></li>
  </ul>
</div>

CSS:

li{
  list-style: none;
  height: 60px;
  width: 5em;
  float: left;
  margin-left: 50px;
  position: relative;
}
a{
  postion: absolute;
  top: 50%;
  margin-top: -0.5em;
}

3.行高 line-height

对于单行文字来说,其实只需要文字本身的高度等于它所在的行高,文字自然就会居中。跟前边两个方法想必,这个简单的多。

HTML:

<div>
  <ul>
    <li><a>导航项目1</a></li>
    <li><a>导航项目2</a></li>
  </ul>
</div>

CSS:

li{
  list-style: none;
  height: 60px;
  width: 5em;
  float: left;
  margin-left: 50px;
}
a{
  line-height:60px;
}

前几天去观摩了微软的学生创业大赛,一等奖是个叫「Clove」的和「回家吃饭」一模一样的App。不过 Clove 主打的是有机、生态那一套东西,一看就知道服务的是这边一天两回gym的中产阶级。而在中国类似的产品的卖点大概是个「你妈喊你」的归属感吧,所以红烧肉好像卖的特别好。

有工夫算一盘菜有多少卡路里的当地小孩可真幸福。

MSA Showcase