Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different implementation of Flexbox in Firefox and Chrome

Tags:

The following code works as expected in Firefox, but in Chrome, the images become much bigger than the flex container.

.r {
  width: 100%;
  height: auto;
  min-width: unset;
  max-width: 100%;
}

.container {
  display: flex;
  width: 600px;
}
<div class="container">
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
</div>

Firefox: enter image description here

Chrome: enter image description here

like image 630
SteinTheRuler Avatar asked Mar 03 '19 19:03

SteinTheRuler


2 Answers

The following code works as expected in Firefox

I disagree with this because for me Chrome is behaving as expected for 2 reasons:

  1. You set the width of the image to be 100% which means 100% of their containing block (container) that is defined by 600px. So each image will be 600px

  2. The image cannot shrink past its content size due to the default min-width configuration (note that using unset is equivalent to initial in this case so it's somehow useless). So the image will be kept at 600px

If you add min-width:0 the image will shrink only in width:

.r {
  width: 100%;
  /*height: auto; useless */
  min-width: 0;
  max-width: 100%;
}

.container {
  display: flex;
  width: 600px;
}
<div class="container">
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
</div>

the behavior of chrome seems to have changed so the below is no more needed in the last version

Now if we consider the height you are facing the stretch effect that is also not the same in both browser. It's a bit trikcy to explain1 but if you change the default alignment you will get the expected result within chrome:

.r {
  width: 100%;
  /*height: auto; useless */
  min-width: 0;
  max-width: 100%;
}

.container {
  display: flex;
  width: 600px;
  align-items:flex-start;
}
<div class="container">
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
</div>

Or if you change the height using percentage value you will make it fail and also have what you want (this is a bit hacky because we are triggering another issue to fix the actual one)

.r {
  width: 100%;
  height:658%; /*any value here with %*/
  min-width: 0;
  max-width: 100%;
}

.container {
  display: flex;
  width: 600px;
}
<div class="container">
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
  <img src="https://via.placeholder.com/1000x500" class="r" >
</div>

Why Firefox is behaving like that?

I don't know exactly, but the logical explanation is that Firefox is not considering the default min-width configuration and is giving priority to keeping ratio and not to the stretch effect.


1 Initially your image are defining the height of the container since they are big (around 700px in height), this height is used by the container then we apply the properties to our image so they shrink in width and since the default alignment is stretch they will stretch to the height of the container that was initially defined by their own intial height creating this rendring.

If we remove the stretch effect, the image will try to keep their ratio since we removed the height constraint.

Same logic if we consider percentage value for height. This one will fail to auto and we get back to the default behavior (keeping the aspect ratio)


Another alternative

The issue arised due to the use of image that are replaced element with intrinsic dimension where the calculation of width/height is not as simple as other element.

To avoid such behavior, better wrap the image inside a div and avoid having them as flex items.

.r {
  width: 100%;
  max-width: 100%;
}

.container {
  display: flex;
  width: 600px;
}

img {
  max-width: 100%;
}
<div class="container">
  <div class="r"><img src="https://via.placeholder.com/1000x500"></div>
  <div class="r"><img src="https://via.placeholder.com/1000x500"></div>
  <div class="r"><img src="https://via.placeholder.com/1000x500"></div>
  <div class="r"><img src="https://via.placeholder.com/1000x500"></div>
</div>
like image 114
Temani Afif Avatar answered Oct 21 '22 10:10

Temani Afif


@TheRuler, The best solution is to wrap the image tag in a div or span, to render the images as per Firefox. Firefox will also work fine if you wrap the images in a div or span.

Now you can ask me why this is correct.

Basically display flex has defaults value attached to it, which are:

flex-grow: 0
flex-shrink: 1
flex-basis: auto
flex: 0 1 auto /* Shorthand */

Now, for both case Firefox and Chrome the default value is same. But still the rendering is different in the both browser specially in case of image as a flex child.

Now who is correct is debatable, and who is following the guidelines properly is also debatable.

If you look at the specification of flex, it says, flex rules should prevail over the CSS width and height properties. So in this case Firefox is shrinking the size of images to fit it properly in 600px parent.

Now if you see this example,

.container { display: flex; flex-direction: column;}
.container > div { flex: 1; height: 300px;}

<div class="container">
  <div>Single line in Firefox, but 300px tall in Chrome!</div>
</div>

So if you see this code in both browser you will see the difference. Chrome values the height property of the flex child where as Firefox doesn't value it. Same goes for image height and image width. Chrome doesn't prevail the height.

So both browser went with their own implementation, which is in this case doesn't match each other and it is debatable who is correct.

So wrap them in span or div to make it work in both the browser which should be the correct answer with no hack. Other solution will solve the problem but they are kind of hack to solve the problem.

Please let me know if you get it Thanks

like image 38
Sakti Chourasia Avatar answered Oct 21 '22 11:10

Sakti Chourasia