
世界上只有一种真正的英雄主义,
就是认清了生活的真相后还依然热爱它!
———罗曼·罗兰
说明
最近项目中多个图片显示是类似Google样式的,特点是图片的高度是相等的,效果如下图所示:

<div class="search_picture">
<div class="imgBox">
<img src="../assets/images/search/hhl01.jpeg" alt="加载中...">
<div class="info">
<h3 class="title">李白</h3>
</div>
</div>
<div class="imgBox">
<img src="../assets/images/search/hhl02.jpeg" alt="加载中...">
<div class="info">
<h3 class="title">李白</h3>
</div>
</div>
<div class="imgBox">
<img src="../assets/images/search/hhl03.jpeg" alt="加载中...">
<div class="info">
<h3 class="title">李白</h3>
</div>
</div>
// 添加多个,目前是前端假数据,事迹需要从后台获取数据
</div>
最重要的css代码如下:
.search_picture {
/* 父元素flex展示方式,wrap设置为换行 */
display: flex;
flex-wrap: wrap;
margin-top: 10px;
padding: 2px;
}
.search_picture::after {
/* 让最后一行图片不被拉伸 */
content: "";
flex-grow: 999999999;
}
.search_picture .imgBox {
/* 设置相对定位是为了添加hover特效 */
position: relative;
height: 200px;
margin: 8px 4px;
background-color: #fff;
/* 重点,当图片占不满一行时,通过拉伸让图片充满一行 */
flex-grow: 1;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.05);
}
.search_picture img {
/* 图片的宽度一定要这么写才可以,否则出错,与flex布局有关 */
max-width: 100%;
min-width: 100%;
/* 图片高度固定 */
height: 200px;
/* 图片发生裁剪 */
object-fit: cover;
vertical-align: bottom;
cursor: pointer;
}
/* 下面两个样式是给图片信息添加hover特效 */
.search_picture .info {
/* 下面三行是重点 */
position: absolute;
overflow: hidden;
visibility: hidden;
/* 上面三行是重点 */
bottom: 0;
-webkit-transition: -webkit-transform 0.35s;
transition: transform 0.35s;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
height: 30px;
width: 100%;
background: rgba(27, 21, 21, 0.5);
}
.imgBox:hover .info {
transform: translate3d(0, 0, 0);
/* 当hover时元素可见 */
visibility: visible;
}
.search_picture .info .title {
color: #fff;
font-size: 14px;
padding: 5px 10px;
margin: 0;
}
使用 max-width: 100%;min-width: 100%;效果如下:

而使用width:100%时,效果如下,可以看到一张图片占一行,不符合我们的预期:

实现步骤
- 父元素display:flex
- 设置图片高度为定值,这里我设置了200px
- 通过flex-wrap设置图片超出一行可以换行
- 当某行有剩余空间的话,通过flex-grow特性,设置元素分配剩余空间
- 图片的宽度设为
max-width: 100%;min-width: 100%;而不是width:100%
flex 伸缩特性
上面用到了flexd的拉伸特性,比较陌生,下面重点讲一下该特性,包含flex-grow、flex-shrink、flex-basis三个特性:
flex-grow
简介
flex-grow 属性定义弹性盒子项(flex item)的拉伸因子
| 特性 | 说明 |
|---|---|
| 初始值 | 0 |
| 适用元素 | flex items, including in-flow pseudo-elements |
| 是否是继承属性 | 否 |
| 适用媒体 | visual |
| 计算值 | as specified |
| Animation | type a number |
| 正规顺序 | the unique non-ambiguous order defined by the formal grammar |
语法
CSS 属性值定义语法:<number>
flex-grow: 3
flex-grow: inherit
详细说明
flex布局发生在父容器和子容器之间。父容器需要有flex的环境(display:flex;),子容器才能根据自身的属性来布局,简单的说,就是瓜分父容器的空间。相反就是说如果父容器没有flex的环境,那么子容器就无法使用flex的规则来划分父容器的空间。
讲到瓜分父容器的空看,那么首先需要讲一个很重要的词:剩余空间。
什么是剩余空间呢?具备flex环境的父容器,通常是有一条主轴和一条侧轴,默认情况下主轴就是水平从左向右的,侧轴是垂直从上到下的(类似书写模式)。 剩余空间就是父容器在主轴的方向上还有多少可用的空间。比如看下面这段html结构:
<div class="container">
<span class="B1"></span>
<span class="B2"></span>
<span class="B3"></span>
</div>
container就是父容器,B1 B2 B3就是子容器,假如container的width是500px,那么剩余空间就是:500px - B1.width - B2.width - B3.width。
在上面例子中,我们假设container的width是500px,现在我们再假设B1、B2、B3的width是100px,那么剩余空间就是500-100*3=200。
知道了剩余空间有什么用呢?这个时候flex-grow就该出场了,假如我们这个时候对B1设置flex-grow:1,那么我们会发现,B1把B2和B3都挤到右边了,也就是说剩余的200px空间都被B1占据了,所以此时B1的width比实际设置的值要大。 所以这里flex-grow的意思已经很明显了,就是索取父容器的剩余空间,默认值是0,就是三个子容器都不索取剩余空间。但是当B1设置为1的时候,剩余空间就会被分成一份,然后都给了B1。 如果此时B2设置了flex-grow:2,那么说明B2也参与到瓜分剩余空间中来,并且他是占据了剩余空间中的2份,那么此时父容器就会把剩余空间分为3份,然后1份给到B1,2份给到B2。
flex-basis
这个属性值的作用也就是width的替代品。如果子容器设置了flex-basis或者width,那么在分配空间之前,他们会先跟父容器预约这么多的空间,然后剩下的才是归入到剩余空间,然后父容器再把剩余空间分配给设置了flex-grow的容器。
如果同时设置flex-basis和width,那么width属性会被覆盖,也就是说flex-basis的优先级比width高;此外有一点需要注意,如果flex-basis和width其中有一个是auto,那么另外一个非auto的属性优先级会更高。
flex-shrink
上面讲的都是剩余空间的分配。但是,你有没有想过还有没有其他的情况呢?可以发现,上面讲的例子B1 B2 B3的宽度总和都是没有超过父容器的宽度的。 那如果三个子容器的宽度和超过父容器的宽度呢?那还有剩余空间可以分配吗,此时浏览器又是怎么处理呢?请看下面:
tips:flex环境默认是不换行的,即使父容器宽度不够也不会,除非设置flex-wrap来换行
此时我们会发现,B1设置的flex-grow没有作用,不但没有获取到剩余空间,他的空间甚至是比他定义的300px还要小,而且我们发现B2和B3的空间也相应的被压缩了。 那么这里的问题就是:
- 为什么flex-grow没有作用,反而被压缩呢?
- 三个容器的压缩比例是这样的呢?
这就是这一节的重点了 flex-shrink了。
同样的,三个容器处于flex环境中,所以布局之前,父容器还是会计算剩余空间。 这一次计算的结果是这样的:剩余空间=500px - 300px - 160px - 120px = -80px,剩余空间是一个负数所以很容易理解第一个问题,即使是设置了flex-grow,但是由于没有剩余空间,所以B1分配到的空间是0。
由于flex环境的父容器的宽度500px是不会变,所以为了是子容器的宽度和最多为父容器的宽度,那就只有两个办法:第一个是使子容器换行,第二个是压缩子容器使之刚好撑满父容器的宽度。 因为flex子容器是默认不换行的,所以这里不做讨论。而第二种压缩,实际上就是上面例子表现出来的样式。现在就遇到了上面第二个问题,这三个的压缩比例是多少呢,各自需要压缩的空间是多少呢?
这个时候就需要谈谈flex-shrink,这个属性其实就是定义一个子容器的压缩比例。他的默认值是1,所以上面那个例子,就是三个子容器压缩的比例是一样的 1:1:1。 如果此时我们设置B1的压缩比例是2,那会怎样呢?
我们可以发现,B1被压缩的更多了。而B2和B3得到了跟多的空间。那我们怎么得出他们各自的压缩率呢?我们假设B2 B3的压缩率是X1,那么B1的压缩率就是X2了,那就有了如下方程:
X2 = 2 * X1;
500 = 300 * X2 + 160 * X1 + 120 * X1;
通过上面我们就可以解出X1和X2等于多少了,这样就可以计算出压缩率和被压缩了多少空间了。
总结
通过上面的分析,我们就可以得出这样几个结论:
- 剩余空间=父容器空间-子容器1.flex-basis/width - 子容器2.flex-basis/width - …
- 如果父容器空间不够,就走压缩flex-shrink,否则走扩张flex-grow;
- 如果你不希望某个容器在任何时候都不被压缩,那设置flex-shrink:0;
- 如果子容器的的flex-basis设置为0(width也可以,不过flex-basis更符合语义),那么计算剩余空间的时候将不会为子容器预留空间。
- 如果子容器的的flex-basis设置为auto(width也可以,不过flex-basis更符合语义),那么计算剩余空间的时候将会根据子容器内容的多少来预留空间。
最后实现效果:
