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

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; }

Related

How Exactly Does CSS Compute Relative Dimensions

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>

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.

height, min-height not working

I'm trying to make 2 div's inside a container div (from Twitter Bootstrap) take the max height which is 100%.
I created a fiddle to demonstrate, but somehow it's not showing what I want.
Both div's are floated. And therefore I used class="clearfix". But that didn't work either. What am I missing?
EDIT
What you don't see in the fiddle, is that html and body are already set to 100% height in my application.
EDIT
The child div goes outside it's parent div, and that's why it keeps failing.
The jsfiddle has been updated. Anyone can take a look at it?
To make a nested block-level element take up 100% height even without any content inside of them, one needs to add height: 100%; to the element in question and all its parent elements (including html and body). See this demo.
Giving the divs a height works just fine, but because there is no content inside, the html and body elements don't stretch accordingly.
HTML:
<html>
<body>
<div class=container>
<div class=stretch-this>
</div>
</div>
</body>
</html>
CSS:
.stretch-this {
background-color: khaki;
}
html,
body,
.container,
.stretch-this {
height:100%;
}

Div not getting correct height with img content

I have a simple page with a single div. Inside that div I have an image with dimensions [h:58px, w:173px].
<body>
<div id="main_header">
<img src="logo.gif" style="padding: 0; margin: 0;">
</div>
</body>
It is not wrapped in any other tags. However, Chrome calculates the height of the container div as 63px. There is no associated css with the #main_header. html and body both have margin and padding set to 0.
Can anyone explain why the div's height is coming out to 63 and not 58?
It's because of the parent's line-height. Either set the line-height (or font-size) of the parent to zero, or set the image to display: block.

Div width automatically sizes to the width of its contents within a div which has a set width?

Lets say I have this
<div class="sectionContainer">
<div class="itemsContainer">
<div class="items"></div>
<div class="items"></div>
<div class="items"></div>
</div>
</div>
The css:
.itemsContainer
{
/* width:3000px works, however this is what I want to avoid saying explicitly.*/
}
.sectionContainer
{
width: 1000px;
overflow: auto;
}
.items
{
width: 1000px;
float: left;
}
The sectionContainer has some set width.
The items has some set width.
The items container does not have a set width; it will scale to the size of its contents.
The items container's overflow is set to hidden, so that one can scroll through the items within the div. The items within the div are horizontally displayed IE they are side-by-side, I'm currently doing this with a float.
How can I do this with CSS only? Is it possible? I'm not looking for a JavaScript solution right away but can resort to that if needed.
to be more specific, this would work if I specified the itemsContainer to have a width of 3000. But I'm guessing that since it is the child of its parent div, its width gets sized to 1000. I do not want to explicitly set the size of the itemsContainer because this should be based upon the number of items. If I add more items, I want the itemsContainer to change its width to contain all of those items without having to alter the CSS.
Thanks!
It's not possible for CSS to guess what you want to happen -- meaning that it wants to cascade elements downward as opposed to horizontally, which is what you want.
http://jsfiddle.net/9NHFa/
Set the itemsContainer width to a 100% X the number of elements.
.itemsContainer
{
width:300%; /* since you have 3 elements
}

Resources