使用 flexbox 并保持 1:1 的纵横比,即使内容大小不同

Posted

技术标签:

【中文标题】使用 flexbox 并保持 1:1 的纵横比,即使内容大小不同【英文标题】:Use flexbox and maintain a 1:1 aspect ratio even though content is sized differently 【发布时间】:2017-10-15 23:33:04 【问题描述】:

关于保持元素的纵横比(有或没有 flexbox)有很多关于 SO 的问题。但是,我的问题略有不同,因为我想覆盖子图像元素的纵横比:

    确保图片完全覆盖元素 (object-fit: cover) 确保元素为 1:1(即完美的圆) 确保溢出的图像被隐藏

换句话说,图像必须表现得好像它是元素的背景(但我不能将它们用作背景图像),其纵横比始终为 1:1 并且具有响应性时间>。

在下面的示例中,除了 <a> 元素适应其图像后代之外,一切正常。但我希望它们保持 1:1 的比例,这样我就能得到完美的圆圈。 (不过,第一行的中间部分必须比其他部分大。)

html 无法更改,但我可以使用现代 CSS 属性,例如 object-fit 和 flexbox。 (只要最新版本的 Chrome/Firefox 支持它。)

*,
*::before,
*::after 
  box-sizing: border-box;
  margin: 0;
  padding: 0;


.img-gallery 
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;


.img-gallery .row 
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;


.img-gallery a 
  display: block;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  padding: 3px;
  flex: 1;
  margin: 0 24px;
  transition: padding 200ms;


.img-gallery a:hover,
#s_country .img-gallery .row:first-of-type a:nth-child(2):hover 
  padding: 0;


.img-gallery a:hover span 
  transform: scale(1.25);


.img-gallery .row:first-of-type a:not(:nth-child(2)) 
  width: 30%;
  width: calc((60% - 96px) / 2);


.img-gallery .row:first-of-type a:nth-child(2) 
  flex: 2;
  padding: 4px;


.img-gallery span 
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  position: relative;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;


.img-gallery img 
  width: 100%;
  height: 100%;
  object-fit: cover;


.img-gallery span::before 
  content: "";
  background-image: linear-gradient(60deg, transparent 48%, #ffc5e7 100%);
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 2;
  border-radius: 50%;
  opacity: .72;
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/b3/9c/54/b39c54776074d07ee0b567826768730a.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/88/3b/dd/883bddab14168f5f0807fec021002d8d.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

说明当 Terry 的代码不起作用时的代码:风景图片。

*,
*::before,
*::after 
  box-sizing: border-box;
  margin: 0;
  padding: 0;


.img-gallery 
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;


.img-gallery .row 
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;


.img-gallery a 
  display: block;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  padding: 3px;
  flex: 1;
  margin: 0 24px;
  transition: padding 200ms;


.img-gallery .row:first-of-type a:not(:nth-child(2)) 
  width: 30%;
  width: calc((60% - 96px) / 2);


.img-gallery .row:first-of-type a:nth-child(2) 
  flex: 2;
  padding: 4px;


.img-gallery span 
  height: 0;
  display: block;
  border-radius: 50%;
  position: relative;
  padding-bottom: 100%;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;


.img-gallery img 
  width: 100%;
  object-fit: cover;
  transition: transform 250ms;


.img-gallery a:hover img 
  transform: scale(1.25);


.img-gallery span::before 
  content: "";
  background-image: linear-gradient(60deg, transparent 48%, #ffc5e7 100%);
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 2;
  border-radius: 50%;
  opacity: .72;
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/b3/9c/54/b39c54776074d07ee0b567826768730a.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/13/7c/3d/137c3d3bd9f25aa9d2677136d9336d74.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

【问题讨论】:

所有图片都是纵向模式? (即高度>宽度) @vals 不,尺寸无法提前知道。 【参考方案1】:

保持响应式元素的纵横比,您可以使用padding technique。请注意,您不应该在 flex 子元素的底部/顶部填充上使用百分比, see here for more info. 您可以制作responsive squares 的网格并添加边框半径以使它们成为圆形。

对于图像,object-fit: cover; 属性完全符合您的需要:保持图像原始纵横比并完全覆盖元素。 我将第一张图像更改为风景图像,以显示该技术也适用于这些图像。

这是一个如何实现目标的示例(我删除了一些 CSS 以保持演示简单):

*,*::before,*::after 
  box-sizing: border-box;
  margin: 0;
  padding: 0;


.img-gallery 
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;


.img-gallery .row 
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;


.img-gallery a 
  display: block;
  position:relative;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  flex: 1;
  margin: 24px;

.img-gallery a::before
  content:'';
  display:block;
  padding-bottom:100%;



.img-gallery .row:first-of-type a:not(:nth-child(2)) 
  width: 30%;
  width: calc((60% - 96px) / 2);


.img-gallery .row:first-of-type a:nth-child(2) 
  flex: 2;


.img-gallery span 
  position:absolute;
  top:3px;left:3px;right:3px;bottom:3px;
  border-radius: 50%;
  overflow: hidden;
  transition: transform 250ms;


.img-gallery img 
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:transform 0.5s;

.img-gallery a:hover img
  transform:scale(1.25);
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/88/3b/dd/883bddab14168f5f0807fec021002d8d.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

请注意,根据您需要支持的浏览器,您需要为转换和转换属性添加供应商前缀。 transforms 和 transitions 参见 canIuse。

【讨论】:

这与特里的答案之间的差异并不明显。提问者可能应该提供一些风景图片以供使用,这样您就可以展示您的图片是否可以与它们一起使用(提问者需要)。 好点@BoltClock。我将第一张图片更改为横向图片,以表明 object-fit : cover; 属性也适用于这些。 哦,好东西。我也没有注意到提问者确实已经编辑以添加风景图像。【参考方案2】:

这很简单:您可以使用padding-bottom: 100% hack 来强制设置 1:1 的纵横比。根据 CSS 规范,垂直边距/填充,当以百分比声明时,引用父宽度。这背后的逻辑从未被清楚地解释过,但我怀疑是为了防止循环计算。

无论如何,现在您知道可以使用padding-bottom: &lt;percentage&gt; 来强制固定纵横比;)现在我们只需将其应用于.img-gallery span。请记住将其高度设置为 0,因为我们不再需要指定高度:

.img-gallery span 
  height: 0;
  display: block;
  border-radius: 50%;
  position: relative;
  padding-bottom: 100%;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;

p/s:我不太清楚您为什么在悬停时将 :nth-child(2n) 元素上的填充设置为 0,所以我现在将其删除。

这是一个概念验证示例:

*,
*::before,
*::after 
  box-sizing: border-box;
  margin: 0;
  padding: 0;


.img-gallery 
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;


.img-gallery .row 
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;


.img-gallery a 
  display: block;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  padding: 3px;
  flex: 1;
  margin: 0 24px;
  transition: padding 200ms;


.img-gallery .row:first-of-type a:not(:nth-child(2)) 
  width: 30%;
  width: calc((60% - 96px) / 2);


.img-gallery .row:first-of-type a:nth-child(2) 
  flex: 2;
  padding: 4px;


.img-gallery span 
  height: 0;
  display: block;
  border-radius: 50%;
  position: relative;
  padding-bottom: 100%;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;


.img-gallery img 
  width: 100%;
  object-fit: cover;
  transition: transform 250ms;


.img-gallery a:hover img 
  transform: scale(1.25);


.img-gallery span::before 
  content: "";
  background-image: linear-gradient(60deg, transparent 48%, #ffc5e7 100%);
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 2;
  border-radius: 50%;
  opacity: .72;
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/b3/9c/54/b39c54776074d07ee0b567826768730a.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/88/3b/dd/883bddab14168f5f0807fec021002d8d.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

【讨论】:

不幸的是,这遇到了我之前遇到的问题:这仅在所有图片都具有纵向方向时才有效,而我的所有示例都巧合。在我的 OP 中,我添加了一个风景图片的示例,表明这不能按预期工作。 (跨度没有被图像覆盖。)

以上是关于使用 flexbox 并保持 1:1 的纵横比,即使内容大小不同的主要内容,如果未能解决你的问题,请参考以下文章

保持网格内div的纵横比[重复]

如何保持并排图像的纵横比,保持图像高度相同并在图像之间固定填充?

如何维护多层 ImageView 并根据最大的一个保持它们的纵横比?

如何在 Qt 中保持小部件的纵横比?

根据高度保持div的纵横比[重复]

如何在FFMpeg中连接两个或多个具有相同宽度和不同高度的视频并保持相同的纵横比?