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?
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.
When the user clicks again and the flex item style is reset, all items are properly rendered.
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>
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With