Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flex-box items don't re-render correctly on chrome

I came across different browser behaviors when programmatically changing dimensions or the position property of flex-box items. The layout doesn't return to its original state on Chrome.

In this pen, when the user clicks an image, I'm changing the item position to absolute and modifying its width and height (actually it could be anything that affects the layout, e.g. padding). When the user clicks again, I rollback the changes, so I expect the layout to reset accordingly.

A js workaround is to force the layout to re-render by quickly changing the items padding by 1px back and forth, but I wonder:

Why does this happen and is there a css-only workaround?

Chrome

When the user clicks again and the flex item style is reset, flex-basis is not taken into account anymore and the layout is broken. Chrome

Firefox

When the user clicks again and the flex item style is reset, all items are properly rendered. Firefox

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>
like image 728
rzb Avatar asked Oct 02 '17 08:10

rzb


1 Answers

The issue looks unusual but the fix is rather simple. Add min-height: 0 to .ig-item.

Possibly the issue seems to be how browsers manifest the fact that the min-height property for flex items is auto by default.

See demo below:

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>
like image 193
kukkuz Avatar answered Oct 18 '22 20:10

kukkuz