Flex-box 项目无法在 chrome 上正确重新渲染

Posted

技术标签:

【中文标题】Flex-box 项目无法在 chrome 上正确重新渲染【英文标题】:Flex-box items don't re-render correctly on chrome 【发布时间】:2018-03-13 07:17:45 【问题描述】:

在以编程方式更改尺寸或弹性框项目的位置属性时,我遇到了不同的浏览器行为。布局不会在 Chrome 上恢复到其原始状态。

在这个pen 中,当用户单击图像时,我将项目位置更改为绝对位置并修改其宽度和高度(实际上它可能是影响布局的任何东西,例如填充)。当用户再次单击时,我会回滚更改,因此我希望布局会相应地重置。

一个 js 解决方法是通过快速来回更改项目填充 1px 来强制重新渲染布局,但我想知道:

为什么会发生这种情况?是否有仅使用 css 的解决方法?

当用户再次单击并重置 flex 项目样式时,不再考虑 flex-basis 并且布局被破坏。

火狐

当用户再次单击并重置 flex 项目样式时,所有项目都会正确呈现。

new Vue(
  el: '#app',

  data() 
    return 
      activeImageIndex: null,
      images: [
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '50%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '50%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
      ]
    
  ,


  methods: 
    onClick(index) 
      this.activeImageIndex = this.activeImageIndex === index ? null : index
    
  ,
)
#app 
  width: 800px;


.ig-container 
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  margin: 0 -5px;
  position: relative;
  height: 500px;


.ig-item 
  flex: 1 1;
  padding: 10px;
  box-sizing: border-box;


.ig-item:hover>div 
  border-color: green;


.ig-item.active 
  position: absolute;
  z-index: 3;
  width: 100%;
  height: 100%;


.ig-item.active img:hover 
  cursor: zoom-out;


.ig-item>div 
  height: 100%;
  width: 100%;
  background-color: blue;
  position: relative;
  border: 5px solid gainsboro;
  overflow: hidden;


.ig-item .ig-overlay 
  position: absolute;
  height: 100%;
  width: 100%;
  z-index: 3;
  background-color: rgba(0, 0, 0, 0.4);
  color: #fff;
  font-size: 3rem;
  display: flex;
  align-items: center;
  text-align: center;


.ig-item .ig-overlay span 
  width: 100%;


.ig-item img 
  height: 100%;
  width: 100%;
  object-fit: cover;
  position: absolute;
  z-index: 2;
  transition: transform .3s;


.ig-item img:hover 
  cursor: zoom-in;


.ig-item .loading-overlay.ig-loading 
  position: absolute;
  z-index: 1;


.ig-item .loading-overlay.ig-loading .loading-icon:after 
  top: -2.5em;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>

<div id="app">
  <div class="ig-container">
    <div class="ig-item" :class="active: activeImageIndex === index" :style="image.style" v-for="(image, index) in images">
      <div>
        <img @click="onClick(index)" title="" :src="image.url">
      </div>
    </div>
  </div>
</div>

【问题讨论】:

【参考方案1】:

这个问题看起来不寻常,但修复相当简单。将min-height: 0 添加到.ig-item

问题可能在于浏览器如何显示弹性项目的 min-height 属性默认为 auto

请看下面的演示:

new Vue(
  el: '#app',

  data() 
    return 
      activeImageIndex: null,
      images: [
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '50%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '50%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
        
          url: 'https://unsplash.it/600',
          style: 
            flexBasis: '30%'
          
        ,
      ]
    
  ,


  methods: 
    onClick(index) 
      this.activeImageIndex = this.activeImageIndex === index ? null : index
    
  ,
)
#app 
  width: 800px;


.ig-container 
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  margin: 0 -5px;
  position: relative;
  height: 500px;


.ig-item 
  flex: 1 1;
  padding: 10px;
  box-sizing: border-box;
  min-height: 0; /* ADDED */


.ig-item:hover>div 
  border-color: green;


.ig-item.active 
  position: absolute;
  z-index: 3;
  width: 100%;
  height: 100%;


.ig-item.active img:hover 
  cursor: zoom-out;


.ig-item>div 
  height: 100%;
  width: 100%;
  background-color: blue;
  position: relative;
  border: 5px solid gainsboro;
  overflow: hidden;


.ig-item .ig-overlay 
  position: absolute;
  height: 100%;
  width: 100%;
  z-index: 3;
  background-color: rgba(0, 0, 0, 0.4);
  color: #fff;
  font-size: 3rem;
  display: flex;
  align-items: center;
  text-align: center;


.ig-item .ig-overlay span 
  width: 100%;


.ig-item img 
  height: 100%;
  width: 100%;
  object-fit: cover;
  position: absolute;
  z-index: 2;
  transition: transform .3s;


.ig-item img:hover 
  cursor: zoom-in;


.ig-item .loading-overlay.ig-loading 
  position: absolute;
  z-index: 1;


.ig-item .loading-overlay.ig-loading .loading-icon:after 
  top: -2.5em;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>

<div id="app">
  <div class="ig-container">
    <div class="ig-item" :class="active: activeImageIndex === index" :style="image.style" v-for="(image, index) in images">
      <div>
        <img @click="onClick(index)" title="" :src="image.url">
      </div>
    </div>
  </div>

</div>

【讨论】:

以上是关于Flex-box 项目无法在 chrome 上正确重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 flex-box 和 styled-components 水平排列项目列表

获取 flex-box 列以填充可用空间

检测css“flex-box”和“flex-wrap”支持的正确方法是啥?

布局在 Chrome 中无法正确呈现

CSS flex-box:尽管 justify-content 和 align-items 设置正确,但文本并不完全居中

ReactJs / Flex-box 在三的倍数之间对齐