有了flex布局后,让一个元素居中变得比以前容易了很多,当我们需要全屏展现一个图片时,我们也可以用flex布局使其居中。然而,当这个图片的高度超过外层DIV的高度(宽度占满外层DIV的宽度,高度等比压缩后),我们发现居中后无法滑动到图片的顶部,但是却可以滑动到图片的底部。

我在JsFiddle上做了一个简单的示例,如下:

可以看到,flex-center布局的图片,初始是居中的,但是其顶部部分却再也滑动不到了;而正常的div布局,初始位置从顶部开始,可以一直滑动到顶部。那么这是flex布局的一个Bug么?

解决办法

第一次遇到的时候,我尝试修改align-items: flex-start, 确实如此图片就和普通布局类似,从顶部开始,也可以滑动到底部,然而这会使我们丢失居中的效果。困惑中我Google了一把,遇到了一个特别详细的StackOverflow答案,里面也摘录了MDN上关于flex布局在scroll的局限性:

Flexbox的对齐是一种“真正”意义上的居中, 这一点和我们使用的其他的CSS居中技术不太一样。也就是说,即便当子元素超过父元素的边界时,他们在父元素中仍然是居中存在的。然而这有时候会带来问题,当他们的top超过父元素的top边界,或者其left超过父元素的left边界时(当高度限定,宽度自动延伸时,left就有可能超过父元素的left边界),其超过top的部分(或left部分),虽然确实有内容在哪里,实际上却是无法scroll过去的。在将来的版本中,flex的对齐属性会加入一个“安全”的选项(使得在这种情境下,top部分不至于被吞没)。目前,如果这对您是一个担忧的话,您可以通过子元素的auto margins来达到这种安全的布局。当子元素超过父元素时,他们会使用margin属性,而忽略居中属性。不同于 justify- 的系列属性,通过在flex父容器中的第一个和最后一个元素上面设置margin:auto(如果整个容器内只有一个元素,比如本例,则直接设置在该子元素上面),当有足够的空间给子元素来进行”flex”布局时,flex的布局会生效;否则就会切换到一般的布局方式,也就是 margin:auto

原谅我拙劣直白的翻译和自补充…是不是有点拗口?可以看看链接的原文更清楚哦。

结合我们的当前场景来说,也就是当我们的元素没有超过父元素的高度(此处我们是宽度固定,因此只有高度可能超过父元素),图片会被居中展示;但是当子元素超过了父元素的高度时,如果我们针对子元素设置了margin:auto;, 那么flex布局会采用我们的margin属性来布局, 顶部就可以滑动到,由此解决方案就是在子元素img中,加入margin: auto, 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.flex-center {
display: -webkit-flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
-webkit-align-items: center;
align-items: center;
overflow-y: auto;
width: 250px;
height: 200px;
}

.flex-center img {
display: block;
width: 100%;
margin: auto; // 设置margin属性
}

JsFiddle上的效果如下:

可以看到,如果遇到了图片高度超过父元素高度,其居中对齐的特性会被抹去,而是从顶部开始布局;当图片高度未超过父元素时,遵循正常的flex-center居中布局。至此我们的目的达成!