Height of relative div is 100% until I actually set height: 100% - html

Setup
.container {
position: relative;
display: flex;
flex-direction: row;
justify-content: flex-start;
flex: 1 1;
padding: 28px;
width: 100%;
background-color: #eee;
}
.bar {
position: relative;
width: 5px;
background-color: blue;
}
<div class="container">
<div class="bar"></div>
<div>
lskdjf
</div>
</div>
Notice that the blue bar reaches the full height of the container, minus the padding.
If I add height: 100% to the .bar class however, the height disappears.
.bar {
position: relative;
width: 5px;
background-color: blue;
height: 100%;
}
Question
I imagine that actually setting height to 100% confuses the browser because the parent doesn't actually have a height that is set, but what property pre-setting-height-to-100% allows the height to then be 100%? And, given that this is actually my goal, would it be "correct" to just not specify 100%, or is there a better way to ensure the .bar element reaches the full height?

This is due to the stretch default alignment applied to flexbox container that make all the element stretched to fit their parent height.
.container {
position: relative;
display: flex;
flex-direction: row;
justify-content: flex-start;
flex: 1 1;
padding: 28px;
width: 100%;
background-color: #eee;
}
.bar {
position: relative;
width: 5px;
background-color: blue;
}
<div class="container">
<div class="bar"></div>
<div>
lskdjf
</div>
</div>
If the cross size property of the flex item computes to auto, and neither of the cross-axis margins are auto, the flex item is stretched. Its used value is the length necessary to make the cross size of the item’s margin box as close to the same size as the line as possible, while still respecting the constraints imposed by min-height/min-width/max-height/max-width. ref
If you change the alignment this will no more happen
.container {
position: relative;
display: flex;
flex-direction: row;
justify-content: flex-start;
flex: 1 1;
padding: 28px;
width: 100%;
background-color: #eee;
align-items:flex-start;
}
.bar {
position: relative;
width: 5px;
background-color: blue;
}
<div class="container">
<div class="bar"></div>
<div>
lskdjf
</div>
</div>
And if you set any value of height, the size will no more be auto considering the above specification so the stretch will no more apply and you will fall into the issue of percentage height that will make the height fall to auto because the parent height is not explicitely set.
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'. ref

Related

How to make child's height the same as parent

In my application I have a parent div and two other child divs inside this parent. One of these child div's has a set height while the other does not. I want to make the div who does not have a set height to be the same as the parent.
An illustration of what I am referring to can be seen in this jsfiddle: https://jsfiddle.net/ll3333/2Lxuj8wk/10/.
In this example, I want the div with class "child-2" to be the same height as the parent. For some reason, setting its height to "100%" does not seem to be working.
Thanks!
From the MDN on 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. A percentage height on the root element is relative to the initial containing block.
The 100% of the height property that you are setting is telling the element to take up 100% of the parent's height (and this chains all the way to the first absolutely-specified height). However, you never actually specify the height of the parent element itself.
To resolve this, you'll need to set a height of 300px on the parent. Note that this means that the other element could also make use of height: 100%, which would allow you to save on code (though this is not shown below).
.parent {
display: flex;
flex-direction: row;
border: 1px solid purple;
height: 300px;
}
.child-1 {
height: 300px;
background-color: blue;
width: 40px;
}
.child-2 {
height: 100%;
background-color: red;
width: 40px;
}
<div class="parent">
<div class="child-1">
</div>
<div class="child-2">
</div>
</div>
you can add align-items: stretch; for .parent and remove height: 100%; in .child-2
.parent {
display: flex;
align-items: stretch;
flex-direction: row;
border: 1px solid purple;
}
.child-1 {
height: 300px;
background-color: blue;
width: 40px;
}
.child-2 {
background-color: red;
width: 40px;
}
<div class="parent">
<div class="child-1">
</div>
<div class="child-2">
</div>
</div>

Why flex item with flex-basis: auto doesn't get all available space if its content's width is 100%?

.parent {
display: flex;
border: 1px solid black;
}
.first>input {
display: block;
width: 100%;
padding: 0;
}
<div class="parent">
<div class="first"><input type="text"></div>
<div class="second"><button>Button</button></div>
</div>
In this sample I'm doing something with the input's styles that will shrink its width as the .parent's width becomes smaller itself. However, it puzzles me why, as long as the .parent's width is more than enough, the .first>input brotherhood don't take up all the available space? There are no max-width set on them, so why should they freeze up in a flex container? What's the rules here?
flex-basis: auto looks up the main size of the element and defines the size. For example, on a horizontal flex container, auto will look for width and height if the container axis is vertical. If no size is specified, auto will fall back to content.
~ Flex Basis Property in Flexbox
So in your case, no size was specified on the flex container. Set the flex-basis on the parent of the element you are trying to grow. In your case, it would be .first.
.parent {
display: flex;
align-items: center;
border: 1px solid black;
}
.first>input {
display: block;
width: 100%;
padding: 0;
}
.first {
flex-basis: 100%;
}
<div class="parent">
<div class="first"><input type="text"></div>
<div class="second"><button>Button</button></div>
</div>

Make child width equal to parent height with CSS only

As described by the image there are two elements: A parent (dark gray) and child (not so dark gray). The width and height of the parent is fluid. The ratio of the child i 1:1 or y:y where y is equal to the height of the parent.
I've tried to find ways to solve this using flex, calc, padding etc but have reached the end of the road. Any ideas how to solve this with pure CSS are much appreciated.
EDIT: I realize now I should have added more details regarding the usage of this scenario. As well as what I consider to be a dynamic height. Dynamic height for me suggests that the height is decided by the amount of content it contains. So I added some HTML to clarify. The .content div may be unnecessary if you can put the content directly in the .container div. But that depends on how you write the CSS:
<div class="container">
<div class="content">
Here is some text. It can be long and it can be short.
It will affect the height of the .container thus also
the height and width of the .square.
</div>
<div class="square">1:1</div>
</div>
I think it is not possible to do what you try!You can't get parents height without JS. But maybe there is another solution. Does your parent container also has a fixed proportion?
This question was quite old. But today I found a quite-tricky solution that may help. That is, I utilize the property of image (svg here) that preserve the aspect ratio while scaling. So I insert an empty svg and make its height fit the parent. Then we have its width equals to its height. (You can change the 1 1 in the part <svg viewBox="0 0 1 1" > to change the ratio).
See the example below. Sorry for my bad English.
.outer {
display: flex;
/* This is just for the example */
width: 700px; /* x */
height: 100px; /* y */
font-size: 18px;
font-family: Verdana, Geneva, sans-serif;
}
.left {
flex-grow: 1
/* This is just for the example */
color: #cddfc9;
background-color: #636363;
padding: 10px;
height: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
.child {
height: 100%;
position: relative;
display: inline-flex;
}
/* This is the trick */
.child svg {
height: 100%;
width: 100%;
}
.child > .content {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
/* This is just for the example */
color: white;
background-color: #8a8a8a;
display: flex;
align-items: center;
justify-content: center;
}
<div class="outer">
<div class="left">
Text of various length be here...
</div>
<div class="child">
<svg viewBox="0 0 1 1" ></svg>
<div class="content">
yxy
</div>
</div>
</div>
you can use the vh property for this. Set the height of your parent div in vh and then use the same vh value for the width of your child div and set the height of the child div to 100%.
#parent{
position: absolute;
left: 0;
top:0;
width: 400px;
height: 50vh;
background-color: red;
}
#child{
position: relative;
float: right;
height: 100%;
width: 50vh;
background-color: blue;
}
<div id="parent">
<div id="child"></div>
</div>

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>

Set parent width to width of child aligned to bottom

I am trying to set the width of a div element to the width of it's longest child element, which in this case happens to be a div that I want locked to the bottom of the parent div. I am also not using a fixed height for the parent, because I do not know how big the children will need to be
Here is my html/css:
HTML:
<div id ="header-right">
<div id="content1"></div>
<div id="footer"></div>
</div>
CSS:
#header-right{
background-color: red;
position: relative;
display: inline-block;
height: 300px; /*The actual width is unknown, this is just for example*/
}
#content1{
background-color: blue;
width: 200px;
height: 100px;
}
#footer{
background-color: cyan;
position: absolute;
bottom: 0;
width: 300px; /*Also an unknown value*/
height: 25px;
}
You can have a look at this jfiddle to see what happens:
https://jsfiddle.net/rkdqp9m5/2/
You can see the container div ignores the footer, since it is absolutely positioned.
However, if I do not use absolute positioning for the footer, then I cannot lock the footer to the bottom of the div, as you can see in this jfiddle
https://jsfiddle.net/rkdqp9m5/3/
I want to lock the footer to the bottom of the container, but I also want the parent's width to be based off the footer. I do not want to use tables for this, and I do not wan to used fixed widths or heights, as the container's and the footer's dimensions will be based off of images whose widths I do not know.
Edit: I would also like to keep this strictly in HTML/CSS, if possible
If you're OK with browser requirements of flexbox, you could do:
#header-right {
background-color: red;
padding: 20px 0px 0px 0px;
height: 300px;
display: inline-flex;
flex-direction: column;
justify-content: space-between;
}
#content1 {
background-color: blue;
width: 200px;
height: 100px;
align-self: flex-start;
}
#footer {
background-color: cyan;
width: 300px;
height: 25px;
align-self: flex-end;
}
<div id="header-right">
<div id="content1"></div>
<div id="footer"></div>
</div>
JSFIDDLE DEMO with all the necessary vendor prefixes.
Does this help: Relative parent DIV to inherit the width of absolute child DIV
What it suggests is that you can't use pure CSS, but you can use Javascript to achieve what you're trying to do.