How Exactly Does CSS Compute Relative Dimensions - css

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>

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:
div {
border:1px solid;
}
<div style="position:fixed;">
<img
style="width:80%"
src="https://via.placeholder.com/150x100.png"
/>
</div>
<div style="position:fixed;top:150px;">
<img
style="width:80%"
src="https://via.placeholder.com/150x100.png"
/>
</div>
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.
div {
border:1px solid;
}
<div style="position:fixed">
<div style="position:absolute">
<img
style="width:100%"
src="https://via.placeholder.com/150x300.png"
/>
</div>
</div>
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:
div {
border:1px solid;
}
.move {
animation:m 2s linear infinite alternate;
}
#keyframes m {
0% {width:0%}
100% {width:100%}
}
<div style="position:fixed" class="move">
<div style="position:absolute">
<img
style="width:100%"
src="https://via.placeholder.com/150x300.png"
/>
</div>
</div>
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.

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>

Related

Why are the results of img width different in some browsers? Who is correct?

This has a demo:
<div style="position:absolute;">
<img
src="https://i.imgur.com/iQ2rVup.jpg"
style="width:100%;height:100px;"
/>
</div>
On Codepen
Chrome result:
Firefox/IE result:
I saw the W3C document.
Absolutely locate non-displaced elements are calculated as follows.
min(max(preferred minimum width, available width), preferred width)
https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width
Is the result of chrome wrong?
This will probably not answer the question but I will try to explain what is happening with chrome and why both can be correct.
First, you should notice that the same happen even if you consinder inline-block element or float as they are also shrink-to-fit elements
<div style="display:inline-block;">
<img
src="https://i.imgur.com/iQ2rVup.jpg"
style="width:100%;height:100px;"
/>
</div>
<br>
<div style="float:left;">
<img
src="https://i.imgur.com/iQ2rVup.jpg"
style="width:100%;height:100px;"
/>
</div>
Now it's all about the width:100%. Since it's a percentage value, the reference will be the width of the containing block but our containing block is a shrink-to-fit element which means that its width depend on its content. Here we have a kind of cycle.
Here is the part of the specification that describe such behavior:
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. When calculating the containing block’s size, the percentage behaves as auto. Then, unless otherwise specified, when calculating the used sizes and positions of the containing block’s contents: ...
So basically, we consider the width of our image to be auto, we calculate the width of the div (parent element) and then we use width:100% again on that calculated width.
Here come the difference. Firefox is considering the height set to the image in the calculation to find the value of the width of the image (as described in this part of the specification). Now that we have the new width of the image, the parent element will shrint-to-fit this width and we will reconsider the width:100% again based on the previous width.
Chrome is setting the width to auto BUT is not considering the height and in this case the width will use the intrinsic dimension of the image to have the following:
<div style="display:inline-block;">
<img
src="https://i.imgur.com/iQ2rVup.jpg"
style="/*width:100%;height:100px;*/"
/>
</div>
Now that we have the new width, we can calculate the width of the parent element (shrink-to-fit) and now if we set width:100%;height:100px to the image we wil have 100px for height and 100% of the containing block width which is the initial image width.
Now the question is: should we consider the height to calculate the value of new width of the image when this one is considered as auto in order to calculate the width of the containing block? If no Chrome is correct, if yes Firefox is correct.
Worth to note that in both cases the image may get distored. We don't notice this on Firefox in the actual example because the height is small.
Here is an animation to illustrate the distortion and to show the different behavior between both browsers.
img {
width:100%;
height:200px;
}
.wrapper {
border:2px solid;
animation:change 5s linear infinite alternate;
}
.wrapper > div {
border:2px solid green;
}
#keyframes change {
from {
width:500px;
}
to {
width:100px;
}
}
<div class="wrapper">
<div style="display:inline-block;">
<img src="https://i.imgur.com/iQ2rVup.jpg" />
</div>
</div>
The wrapper here is used as the containing block of our shrink-to-fit element and will define the available width. We can clearly see that in Chrome the image is always distored and in Firefix the distortion will happen later.

How to make an element don't widen to the size of its content and stay in width of its inline-block parent with variable width?

Imagine a structure:
<div class="container">
<div class="first">Variable, but Desired Width</div>
<div class="second">Text that may be long. But it should not exceed the width of the element above.</div>
</div>
I am looking for a pure CSS solution (if it is possible) to the following:
.first is inline-block and its width may vary depending on its content.
I want .second to take the full width of .first, and do not exceed it.
A picture is worth a thousand words:

CSS: can change height by px, but not by %

I am trying to edit the CSS of my Wordpress theme.
I have an element whose height I can successfully change from within Element Inspector, if I specify a certain pixel height, for example:
height=100px;
But when I try to change the height by specifying a percentage, for example:
height=50%;
The element does not change height. Any thoughts on what I'm doing wrong, or how to troubleshoot?
None of the parent elements appear to have any height properties.
Short Answer
Length values defined in percentage(%) gets value based on the value of containing box. Set the height of parent box to any absolute values (like height: 500px).
Long Answer
The default value of length properties(height,width) have default value auto, we should know how these values works(in block display):
auto: Width is set in such a way that the block's overall width(including border,padding,margin) occupies the parent block's width.
However, Height is always set according the calculated height of child elements (including border,padding,margin).
`percentage(%): The length properties gets value according to that of the containing box.
The elements like body and div fill up the available width while having only the height required for the available content.
Before
<body>
<div style="height: 100%"> <!-- This have same affect as "height: auto" -->
Hello World!
</div>
</body>
After
<body>
<div style="height: 500px;">
<div style="height: 100%;"> <!-- sets the height of div equal to 500px -->
Hello World!
</div>
</div>
</body>
http://jsfiddle.net/cMYdw/
The reason you are unable to change height % is because you need to set a 100% height on your parent element, in this case your body.
Now, it doesn't necessarily have to be the body, it can be any parent element, but I've used body in my example to get the idea across. For example, have a look below.
html, body { height: 100%; }
div { height: 100%; background: #F52887; }

Prevent paragraph from increasing the width of a floated parent

I often find myself using code blocks for inline article images like the following:
...article text.
<div class="article-image right" style="width: 250px;">
<img src="..." width="250" alt="" />
<p class="caption">Potentially long image caption</p>
</div>
More article text...
Or, the more succinct HTML5 version:
...article text.
<figure class="right" style="width: 250px;">
<img src="..." width="250" alt="" />
<figcaption>Potentially long image caption</figcaption>
</figure>
More article text...
Since I use a CMS that processes images on the fly, I've been defining the size of the image (250px in this case) dynamically, and I've also been applying that size restriction to the parent element that contains both the img and its caption. This way, the caption never increases the size of the parent element beyond the defined width of the img tag.
My question is if there is some CSS trick I can apply to one of the elements that will accomplish the same thing without manually defining the width? Some way to prevent the captions from expanding their parent element in width, yet allowing them to influence the height? Of course the parent element's width still needs to adapt to the img's width...
To stop children elements from affecting parent width apply this to the child:
min-width: 100%;
width: 0;
This gets around solutions using absolute positioning.
For vertically lining them up, also use:
vertical-align: top;
JSFiddle: http://jsfiddle.net/ETkkR/87/
CSS code to div or figure element is alone enough.
style="width: 250px;
**max-width:250px;"**
This will set static width to the div or figure tag even when the width of the image is higher

Parent Floating Element won't resize with percent width child

I have a floating parent div containing a child using width: 30%.
It seems this parent div won't resize if using percent as the width unit, but it works well when using px or ems.
Is there any way to make the parent div adjust its width when using width: 30% since I would like to have a fluid layout?
Please have a look at this example for more details:
http://jsfiddle.net/sBzYH/
<div class='percent container'>
<div>
<h3>width: 30%</h3>
<p>
When using the child div
with percent width, the floating
parent div keeps expading 100%.
</p>
</div>
</div>
<div class='pixel container'>
<div>
<h3>width: 100px</h3>
<p>
When using the child div
with pixel width, the floating
parent div resizes accordingly.
</p>
</div>
</div>
The parent container will already be a fluid width, because it's a div it will default to the full available width but you can explicitly limit that. This CSS will make your two examples approximately the same size:
.container {
width: 66%;
min-width: 325px;
}
If there's more than (just under) 500px available for the container then it will expand to take up 66% of the available space, but it will stay wide enough that the 30% width child element is always at least 100px wide.

Resources