Problem with calculating the block height [duplicate] - html

Say we have the following set up:
.container {
background-color: red;
width: 500px;
min-height: 300px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
It's clear that the container element is rendering with a height set to 300px, but the child element has no height whatsoever, despite being set to 100%.
When the height of the container element is set to even 1px, the child element will suddenly fill the entire container with a height of 300px.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 1px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
The container element is clearly rendering at 300px even without height being set so why does it require setting the height before the child element actually applies it's height: 100%?
Edit: To be clear, I'm not looking for a solution to having the child height take up the entire parent element, I would just like to understand why this behaves like this.

In the first case, you don't have any height defined so it's clear that the precentage height on child will fail.
From the specification:
Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
min-height is only a boundary and the height of your element still depend on its content. If you will have one that exceed 300px the element will have more than 300px
.container {
background-color: red;
width: 500px;
min-height: 300px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
In the second case you have specified a height so the precentage will work but the height calculation is a bit tricky since we also have min-height
The following algorithm describes how the two properties influence the used value of the 'height' property:
The tentative used height is calculated (without 'min-height' and 'max-height') following the rules under "Calculating heights and margins" above.
If this tentative height is greater than 'max-height', the rules above are applied again, but this time using the value of 'max-height' as the computed value for 'height'.
If the resulting height is smaller than 'min-height', the rules above are applied again, but this time using the value of 'min-height' as the computed value for 'height'.
In the second case, it's like you explicitely defined height:300px and percentage will consider this value. In this situation, even if the content is bigger the parent element will not grow and you will have overflow. You can even define a height equal to 0.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 0;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
Same logic will happen with max-height but in this case the height need to be very big
.container {
background-color: red;
width: 500px;
max-height: 300px;
height: 99999px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
If you are intrested you can transform your logic using flexbox and you will be able to do what you want without having to set an explicit height.
Relying on the default stretch alignment on the cross-axis
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
}
.child {
background-color: blue;
width: 500px;
/* height: 100%;*/
}
<div class="container">
<div class="child">
</div>
</div>
Or using the flex-grow property instead of height in main axis:
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
flex-direction:column;
}
.child {
background-color: blue;
width: 500px;
flex-grow:0.8; /* this is 80%, use 1 for 100% */
}
<div class="container">
<div class="child">
</div>
</div>
CSS grid can also handle this
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:grid;
grid-template-rows:1fr;
}
.child {
background-color: blue;
width: 500px;
height:80%;
}
<div class="container">
<div class="child">
</div>
</div>

Related

How to set height in percentage when parent height is in min-height? [duplicate]

Say we have the following set up:
.container {
background-color: red;
width: 500px;
min-height: 300px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
It's clear that the container element is rendering with a height set to 300px, but the child element has no height whatsoever, despite being set to 100%.
When the height of the container element is set to even 1px, the child element will suddenly fill the entire container with a height of 300px.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 1px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
The container element is clearly rendering at 300px even without height being set so why does it require setting the height before the child element actually applies it's height: 100%?
Edit: To be clear, I'm not looking for a solution to having the child height take up the entire parent element, I would just like to understand why this behaves like this.
In the first case, you don't have any height defined so it's clear that the precentage height on child will fail.
From the specification:
Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
min-height is only a boundary and the height of your element still depend on its content. If you will have one that exceed 300px the element will have more than 300px
.container {
background-color: red;
width: 500px;
min-height: 300px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
In the second case you have specified a height so the precentage will work but the height calculation is a bit tricky since we also have min-height
The following algorithm describes how the two properties influence the used value of the 'height' property:
The tentative used height is calculated (without 'min-height' and 'max-height') following the rules under "Calculating heights and margins" above.
If this tentative height is greater than 'max-height', the rules above are applied again, but this time using the value of 'max-height' as the computed value for 'height'.
If the resulting height is smaller than 'min-height', the rules above are applied again, but this time using the value of 'min-height' as the computed value for 'height'.
In the second case, it's like you explicitely defined height:300px and percentage will consider this value. In this situation, even if the content is bigger the parent element will not grow and you will have overflow. You can even define a height equal to 0.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 0;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
Same logic will happen with max-height but in this case the height need to be very big
.container {
background-color: red;
width: 500px;
max-height: 300px;
height: 99999px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
If you are intrested you can transform your logic using flexbox and you will be able to do what you want without having to set an explicit height.
Relying on the default stretch alignment on the cross-axis
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
}
.child {
background-color: blue;
width: 500px;
/* height: 100%;*/
}
<div class="container">
<div class="child">
</div>
</div>
Or using the flex-grow property instead of height in main axis:
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
flex-direction:column;
}
.child {
background-color: blue;
width: 500px;
flex-grow:0.8; /* this is 80%, use 1 for 100% */
}
<div class="container">
<div class="child">
</div>
</div>
CSS grid can also handle this
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:grid;
grid-template-rows:1fr;
}
.child {
background-color: blue;
width: 500px;
height:80%;
}
<div class="container">
<div class="child">
</div>
</div>

Using variables and simple calculation with CSS

I am not familiar with CSS. When setting style for various elements, is there a clean way to set the dimensions of the elements that depend on each others? In the example below, suppose that I need to change the height of either container2 or container3 and keep their total height to be the same as that of container 1, I have to go though the css file and modify their heights manually one by one keeping in mind this summation constraint. For eg, if I have to change the height of container2 to be 100px, I have to change that of container3 to 400px, so as to maintain a sum of 500px. This situation get messier when there are more elements whose dimensions depend on each other. Is there a way to make such changes dynamic?
For eg, can we do something like: set two variables to be height2 and heigh3 and set a constraint height2 + height3 = 500px. So that if either height2 or height3 is changed, some simple calculation can be executed to maintain the 500px constraint?
#container1 {
height: 30%;
width: 300px;
}
#container2 {
height: 70%;
width: 300px;
background-color: blue;
}
#container3 {
height: 300px;
width: 300px;
background-color: yellow;
}
<div id="container1">
<div id="container2">
</div>
<div id="container3">
</div>
</div>
This is just an example of using CSS vars. You can find more info here https://css-tricks.com/difference-between-types-of-css-variables/
:root {
--main-width: 300px;
--height-one: 200px;
--height-two: 300px;
}
#container1 {
background: red;
/* 60px just to show it works, because you don't need to set height anyway here */
height: calc(var(--height-one) + var(--height-two) + 60px);
width: var(--main-width);
}
#container2 {
height: var(--height-one);
width: var(--main-width);
background-color: blue;
}
#container3 {
height: var(--height-two);
width: var(--main-width);
background-color: yellow;
}
<div id="container1">
<div id="container2"></div>
<div id="container3"></div>
</div>
But what you should really do is use percentages, as Paulie_D has suggested in comments.
#container1 {
background: red;
height: 500px;
width: 300px;
}
#container2 {
height: 40%;
background-color: blue;
}
#container3 {
height: 60%;
background-color: yellow;
}
<div id="container1">
<div id="container2">
</div>
<div id="container3">
</div>
</div>
In your particular example, if main container need to adjust the heights of children, you just not need to set its height, it will have its content height by default, and once you set main container height, child div will have 100% width by default.
In general, there is a way to use variables in css using --name notation. and simplee calculations using calc function. like this:
:root { /*define variables*/
--w: 300px;
--h1: 200px;
--h2: 300px;
}
#container1 {
height: calc(var(--h1) + var(--h2)); /* css calculation */
width: var(--w); /* simple use of variable*/
}
#container2 {
height: var(--h1);
width: var(--w);
background-color: blue;
}
#container3 {
height: var(--h2);
width: var(--w);
background-color: yellow;
}
<div id="container1">
<div id="container2">
</div>
<div id="container3">
</div>
</div>

Transition child width 100% when parent width changes

I am having issues coming up with a way to make a child have transitionable width while making the parent change instantaneously.
Using the following example:
.parent {
height: 100px;
width: 25%;
background-color: blue;
}
.child {
width: 100%;
transition: width 1s;
background-color: red;
height: 50px;
}
.parent:hover {
width: 50%;
}
<div class="parent">
<div class="child">
</div>
</div>
When .parent is hovered, its width should increase, and then the child should take 1s to catch up to the parents width.
Is there any way to achieve this? I don't want the parent to transition as it will cause a lot of jumping around as the parent grows instead of moving everything at once.
You can't use transition, since the child's width value doesn't actually change - it was 100% before and 100% after.
In this case you can use an animation that will start from 50% if the new width, and proceed to the 100%. If the hover ends, the child width will go back to the parent's width immediately.
.parent {
height: 100px;
width: 25%;
background-color: blue;
}
.child {
width: 100%;
background-color: red;
height: 50px;
}
.parent:hover {
width: 50%;
}
.parent:hover .child {
animation: 1s both grow;
}
#keyframes grow {
from { width: 50%; }
to { width: 100%; }
}
<div class="parent">
<div class="child">
</div>
</div>
So keep in mind that div elements are block elements. They will fill the full-width of their parent unless you style them otherwise.
This makes using percentages problematic without adding a keyframes animation. Though there is nothing wrong with defining an animation.
But if you give exact widths with other types of css units, you can achieve the affect by also changing the width of the child when the parent is hovered.
Below I changed the parent width to 25vw and assigned the same width to the child. Then, when the parent is hovered, change the child width to 100% will cause it to transition.
In the original case, you were only changing the parents width, and the child's width never transitioned because in both states of the parent, its value was 100%.
.parent {
height: 100px;
width: 25vw;
background-color: blue;
}
.child {
width: 25vw;
transition: width 1s linear;
background-color: red;
height: 50px;
}
.parent:hover {
width: 50%;
}
.parent:hover > .child {
width: 100%;
}
<div class="parent">
<div class="child">
</div>
</div>
The issue is that you're child's width is technically not changing. It remains 100% of the parent's width, so though it's physical size as constrained within the parent changes, it's relative width value is still 100%, so no transition is being applied to it.
Using vw units will allow you to create a fluid layout with the width values being relative to the viewport (window) width instead of the containing div.
.parent {
height: 100px;
width: 25vw;
background-color: blue;
}
.child {
width: 25vw;
transition: width 1s;
background-color: red;
height: 50px;
}
.parent:hover, .parent:hover .child {
width: 50vw;
}
<div class="parent">
<div class="child">
</div>
</div>

Why does height: 100% on a child element not apply when the parent element has a min-height/max-height value but no height value?

Say we have the following set up:
.container {
background-color: red;
width: 500px;
min-height: 300px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
It's clear that the container element is rendering with a height set to 300px, but the child element has no height whatsoever, despite being set to 100%.
When the height of the container element is set to even 1px, the child element will suddenly fill the entire container with a height of 300px.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 1px;
}
.child {
background-color: blue;
width: 500px;
height: 100%;
}
<div class="container">
<div class="child">
</div>
</div>
The container element is clearly rendering at 300px even without height being set so why does it require setting the height before the child element actually applies it's height: 100%?
Edit: To be clear, I'm not looking for a solution to having the child height take up the entire parent element, I would just like to understand why this behaves like this.
In the first case, you don't have any height defined so it's clear that the precentage height on child will fail.
From the specification:
Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
min-height is only a boundary and the height of your element still depend on its content. If you will have one that exceed 300px the element will have more than 300px
.container {
background-color: red;
width: 500px;
min-height: 300px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
In the second case you have specified a height so the precentage will work but the height calculation is a bit tricky since we also have min-height
The following algorithm describes how the two properties influence the used value of the 'height' property:
The tentative used height is calculated (without 'min-height' and 'max-height') following the rules under "Calculating heights and margins" above.
If this tentative height is greater than 'max-height', the rules above are applied again, but this time using the value of 'max-height' as the computed value for 'height'.
If the resulting height is smaller than 'min-height', the rules above are applied again, but this time using the value of 'min-height' as the computed value for 'height'.
In the second case, it's like you explicitely defined height:300px and percentage will consider this value. In this situation, even if the content is bigger the parent element will not grow and you will have overflow. You can even define a height equal to 0.
.container {
background-color: red;
width: 500px;
min-height: 300px;
height: 0;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
Same logic will happen with max-height but in this case the height need to be very big
.container {
background-color: red;
width: 500px;
max-height: 300px;
height: 99999px;
padding:10px;
}
.child {
background-color: blue;
width: 500px;
height: 400px;
animation:change 2s linear infinite alternate;
}
#keyframes change{
from {
height:100px;
}
}
<div class="container">
<div class="child">
</div>
</div>
If you are intrested you can transform your logic using flexbox and you will be able to do what you want without having to set an explicit height.
Relying on the default stretch alignment on the cross-axis
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
}
.child {
background-color: blue;
width: 500px;
/* height: 100%;*/
}
<div class="container">
<div class="child">
</div>
</div>
Or using the flex-grow property instead of height in main axis:
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:flex;
flex-direction:column;
}
.child {
background-color: blue;
width: 500px;
flex-grow:0.8; /* this is 80%, use 1 for 100% */
}
<div class="container">
<div class="child">
</div>
</div>
CSS grid can also handle this
.container {
background-color: red;
width: 500px;
min-height: 300px;
display:grid;
grid-template-rows:1fr;
}
.child {
background-color: blue;
width: 500px;
height:80%;
}
<div class="container">
<div class="child">
</div>
</div>

Is there a way to display a div with width in % and no content?

For example this div is displayed:
<div class="circle"></div
.circle {
width: 300px;
height: 300px;
background: red;
border-radius: 50%;
}
but when width and height are in % it collapses:
.circle {
width: 30%;
height: 30%;
background: red;
border-radius: 50%;
}
Is there a way to get it displayed?
This is because the div has no height. width: 30%; will always make the div 30% width of the parent (<body>, in this case), which is what you want. However, height behaves a little differently.
You need to specify a 100% height for body and html like so:
html,
body {
height: 100%;
}
Working Fiddle
You can read why height: 100%; behaves like that here
You need to declare a hard width/height somewhere, in this example I put a hard width/height on a container div:
http://jsfiddle.net/exrNm/1/
<div class="con">
<div class="circle"></div
</div>
.con{
width:300px;
height:300px
}
.circle {
width: 30%;
height: 30%;
background: red;
border-radius: 50%;
}
You could easily set a hard width somewhere up the parent chain. The % needs a hard value to calculate against.