there is a certain CSS behaviour that I want to understand better. It's not related to a concrete problem, I just encountered it while debugging a website.
Let's have a full width image in a fixed positioned div.
<div style="position:fixed">
<img
style="width:100%"
src="https://via.placeholder.com/150x300.png"
/>
</div>
This renders the image in its original size. So my assumption is, the browser looks through the ancestor elements of the image until it finds one with defined width. But it stops at the fixed positioned div and can't obtain any results, so it lets the image have its own width.
But then, why does the following render the image at width 0?
<div style="position:fixed">
<div style="position:absolute">
<img
style="width:100%"
src="https://via.placeholder.com/150x300.png"
/>
</div>
</div>
According to my logic, the browser should look at the absolutely positioned container, but it has no width set, so it looks further and ends up at the fixed positioned container, from which it should obtain the same width (auto or undefined?) as in the first example?
Also, I couldn't replicate this behaviour with something other than images. Do images behave somehow special in CSS?
[EDIT] I also don't understand why the following results in the image having its own size and not taking up the full viewport width:
<div style="position:fixed;width:100%">
<div style="position:absolute">
<img
style="width:100%"
src="https://via.placeholder.com/150x300.png"
/>
</div>
</div>
CodePudding user response:
What you are facing is called "cyclic dependency" related to how percentage works. In the specification you can read:
Sometimes the size of a percentage-sized box’s containing block depends on the intrinsic size contribution of the box itself, creating a cyclic dependency
It's a bit tricky to follow that specification so I will try to use easy words. It's clear that width:100%
on the image means 100% of the parent element (containing block) BUT your containing block is a position:fixed
so its width is also based on its content so we have a cycle.
In such case, the browser will first ignore the percentage width and consider it as auto (so your image will get its initial width) to define the width of the parent element.
The width of a fixed element element is defined here: https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width (absolute and fixed follow the same rules)
If you read the different cases you will end with the shrink-to-fit algorithm to define your width:
min(max(preferred minimum width, available width), preferred width).
What is important to note here is the "available width" which is big enough in your first example so the "preferred width" is the one used.
So the browser will set the width of the fixed element to its "preferred width" considering the image having a width auto and this will make the width of fixed element equal to the initial width of the image. Later we resolve the percentage width of the image based on the one of the fixed element. In other words, its own width! that's why width:100%
will keep the initial image width
Add some border and use a different percentage to better understand:
In the above, the image will take 80% of its own width because the width of its containing block is equal to the initial width of that same image.
Now let's move to the other example where you have an image inside an absolute element inside a fixed one.
The difference here is that "available width" of the shrink-to-fit algorithm. I know this one is a bit tricky but since our absolute is inside a fixed element (which also follow the same shrink-to-fit behavior) the "available width" will be equal to 0.
In this case, the absolute element will end having a width equal to 0 and width:100% of the image applied to 0 will also give you 0.
If your slowly increase the width of the fixed element you will increase the "available width". See the below animation to understand:
In the above I am increasing the "available width" making the absolute element growing until it reach the "preferred width".
Remember our equation:
min(max(preferred minimum width, available width), preferred width).
We have min()
that's why the width of the absolute is limited to the "preferred width" and we just saw how that width was calculated and it's the initial width of the image.
CodePudding user response:
The width
of elements with position: absolute
are automatically set to zero. You just need to add a width
to the position: absolute
div:
<div style="position:absolute; width: 500px;">
<img style="width:100%" src="https://via.placeholder.com/150x300.png" />
</div>