It's possible to obtain the following masterpiece of recursive positioning of DIVs
by using the following code.
html, body { width: 100%; height: 100%; margin: 0; }
.outer {
width: 100%; height: 100%;
display: flex; flex-direction: column;
}
.inner {
margin: 10px;
border: 10px solid gray; border-radius: 10px;
display: flex; flex-direction: column;
flex: 1;
}
<div class="outer">
<div class="inner">
<div class="inner">
<div class="inner">
</div>
</div>
</div>
</div>
But something is odd about it. My attempts to display a border for the outer box fail (and box-sizing: border-box; doesn't help).
Can you modify this code to use styling for just html, body as well as one-box, where one-box would be used for both the outer DIV as well as an arbitrary nesting of inner DIVs?
Or does HTML5/CSS3 really require this baroque treatment of the base case when recursively nesting DIVs?
My attempt:
html, body {
width: 100%; height: 100%; margin: 0;
box-sizing: border-box;
}
.one-box-to-rule-them {
width: 100%; height: 100%;
display: flex;
flex-direction: column;
flex: 1;
margin: 10px;
border: 10px solid gray; border-radius: 10px;
box-sizing: border-box;
}
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
</div>
</div>
</div>
</div>
fails. Adding a border to the outer box using a unified box makes the boxes go out of bounds.
Explanation
A teacher who solves the problem I was having is valuable. A teacher who (also) points out how my knowledge was misleading me is invaluable. There are at this moment four (nice and correct) answers, but the insight into what I was misunderstanding is provided in a comment made by Temani Afif. Let me illustrate it with a diagram.
My mistake was thinking that when one changes box-sizing from its default content-box and specifies instead box-sizing: border-box;, the box calculation includes all four, content, padding, border, and margin. As its names implies, box-sizing: border-box; includes in the calculation the border-box. It does not include the margin.
You can rely on flexbox and the default stretch alignment to do this without the need of specifying height or width or box-sizing:
body {
height: 100vh;
margin: 0;
display: flex;
}
.inner{
margin: 8px;
border: 8px solid gray;
border-radius: 10px;
display: flex;
flex-grow: 1;
}
<div class="inner">
<div class="inner">
<div class="inner">
<div class="inner">
<div class="inner">
</div>
</div>
</div>
</div>
</div>
Remove the width: 100% from all elements, replace margins with paddings, and remove the redundant flex rules:
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
.one-box-to-rule-them {
height: 100%;
padding: 10px;
border: 10px solid gray;
border-radius: 10px;
}
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
</div>
</div>
</div>
</div>
Your problematic rule is margin because no matter if you set your box-sizing to border-box, margin is never included in the dimensions of the element in the box-model, it is basically "outer-spacing". You also don't need the flexbox rules for what you want! But of course you need some kind of spacing for your desired effect, I therefore chose to create a pseudo-element that will receive the border, position it absolutely to fit the dimensions of the parent and give the parent a double-border-width padding to mimic the spacing you had before:
html, body {
width: 100%; height: 100%; margin: 0;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
.one-box-to-rule-them {
height: 100%;
padding: 20px;
position: relative
}
.one-box-to-rule-them:before {
border: 10px solid gray; border-radius: 10px;
content: '';
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
}
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
<div class="one-box-to-rule-them">
</div>
</div>
</div>
</div>
EDIT: #Ori Drori solution is cleaner, but uses the two-classes approach, mine uses just one but is more "ugly" CSS (in my opinion) =D
EDIT: #Temani Afif should be the accepted solution!
Is this what you want?
if I understand it correctly the the problem with width 100% only
Like this:
html, body { height: 100%; margin: 0; }
.outer {
height: 100%;
display: flex; flex-direction: column;
}
.inner {
margin: 10px;
border: 10px solid gray; border-radius: 10px;
display: flex; flex-direction: column;
flex: 1;
}
<div class="outer">
<div class="inner">
<div class="inner">
<div class="inner">
</div>
</div>
</div>
</div>
Related
I'm having problem with my div with contenteditable=true which break my whole page.
When you type a lot of text, instead adding scrollbar it make div bigger so it move others parts of the page...
So what I would like my editable div fill remaining width and height of the page but add scrollbar when text being too big whitout moving others elments of the page. Thanks
JsFiddle
HTML
<body>
<h1>TEXT</h1>
<div class="all">
<div class="container">
<div class="lines"></div>
<div class="editor" contenteditable="true" spellcheck="false"></div>
</div>
<div class="manage">
<h1>TEXT</h1>
</div>
</div>
</body>
CSS
html, body {
margin: 0;
padding: 0;
display: flex;
height: 100%;
width: 100%
}
h1 {
margin: 20px;
}
.all {
display:flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.container {
display: flex;
width: 100%;
height: 400px;
overflow: auto;
}
.lines {
background-color: red;
border-radius: 20px 0 0 20px;
height: 100%;
width:40px;
}
.editor {
border-radius: 0 20px 20px 0;
background-color: orange;
width: 100%;
height: 100%;
}
All you need to do is to add a max-width property to your .editor class.
Here is a working code: https://codesandbox.io/s/html-code-editor-forked-g27d9o?file=/index.html
I made a parent div and three childs div inside it,
i want to make the three childs in a row by float with some margin between each other,
i made the box-sizing property to be border-box, but the property doesn't work so the margin property value is added to the width value as shown in the image, what is the problem?
* {
margin: 0px;
padding: 0px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
div.child {
float: left;
background-color: black;
width: 200px;
margin: 8px;
text-align: center;
color: white;
}
<div>
<div class="one child">one</div>
<div class="two child">two</div>
<div class="three child">three</div>
</div>
margin is added in all box models. Only border and padding can be included.
Also, you shouldn't try to implement layouts using float in 2022.
Use flex box, or CSS grid:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.child {
background-color: black;
text-align: center;
color: white;
}
.parent {
display: grid;
grid-template-columns: repeat(3, 200px);
gap: 8px;
}
<div class="parent">
<div class="child">one</div>
<div class="child">two</div>
<div class="child">three</div>
</div>
This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Fill remaining vertical space with CSS using display:flex
(6 answers)
Closed 3 years ago.
I have a <div> that takes up 60% of the window space, and it contains two things:
a narrow header line
an image that I want to take up the remainder of the div.
How can I do this with pure CSS (no Javascript)? I've been trying a bunch of things, no luck.
This is the closest I can get; the image sneaks outside of the green border of the div.container
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
Here's my attempt at using flex but that fails.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
}
div.header {
flex: 0;
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
#Christian's approach works if you know the height of the header element, however alternatively you could use flex.
This allows the element to grow to fill the remaining space dynamically, so your header can be any height.
html,
body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
position: relative;
}
div.img-container img {
opacity: 0.5;
height: 100%;
position: absolute;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
If you look at div.img-container in Chrome Inspector, you can see what the issue is - the img element is doing its job and filling its container, but the container itself is overflowing.
This is happening because it is set to height: 100% - what this says is "make my height 100% of my parent's height", but this does not mean "fill the remaining space." The browser just reads the computed height of the element's parent, and then multiplies it by your % value - basically, it's all in absolute terms. You can see that the blue box is 100% as tall as the box outlined in green, but because it sits below a line of text, it overflows by the height of that text.
flex could be used to solve this problem, but you can patch this pretty quickly by using calc to subtract out the height of that text. In your example, it's 19px, and I would recommend manually setting the height of that text element container just to be sure nothing will break in edge cases. Then, the .img-container gets height: calc(100% - 19px) and it works as expected.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
/*
ADDED CODE BELOW
*/
/* optional, just to be safe */
.header {
height: 19px;
}
/* overrides .img-container from above */
.img-container {
height: calc(100% - 19px) !important;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
With Flex, you may use the flex property and overflow (or min-height). Example:
html, body {
height: 100vh;
margin: 0px;
display:flex;
flex-direction:column;
}
div.container {
flex:6;/* instead height:xx% */
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow:hidden; /* or min-height:0 if scroll is needed */
}
div.rest {
flex:4;/* instead height:xx% */
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
min-height:0; /* or overflow:hidden; */
}
div.header {
min-height:1.6em; /* if you need something alike ?? */
}
div.img-container img {
max-height: 100%;
opacity:0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
This question already has an answer here:
Margin collapsing with floated element, why there is an extra margin added?
(1 answer)
Closed 3 years ago.
I would like to create a conainer element, which is at least the height of the page. I set it like this: min-height: 100vh
The body has no margin.
For some reason, an empty space appears under the element. How is it possible to eliminate that?
I can observe this error in Chrome and Edge, but not in Firefox.
My code:
body {
margin: 0;
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
This is how it looks like:
You can get it to work by removing the margin of the last .item element.
body {
margin: 0;
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
.item:last-child {
margin:0;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
The issue is caused by the .container margin to center with auto and the .item children having a bottom margin. For some reason the causing a lack of collapse which is, in turn, causing the margin to overflow (or append to) it's owner, even if margin-bottom: 0 is applied to .container.
To resolve this, we have come up with a different way, by not using margin: auto;, of centering the .container.
As well as, to force a collapse by setting a height relationship between culprit of the overflow and it's parent. We will accomplish this by setting height: 100%; to html, body.
I will propose three solutions which solve the display discrepancy.
Option 1
Edit: This solution does not seem to be consistent to me in Edge upon further testing. Sometimes I have to open DevTools and toggle min-height: 100vh; in .container to get it to render correctly.
html, body {
height: 100%;
}
.container {
/* Remove the margin */
/* margin: auto; */
position: relative;
left: 50%;
transform: translateX(-50%);
This fixes the issue in Edge and Chrome. To answer the question, this is the only edit required.
jsFiddle
html,
body {
height: 100%;
}
body {
margin: 0;
background: red;
}
.container {
position: relative;
left: 50%;
transform: translateX(-50%);
min-height: 100vh;
max-width: 200px;
background: grey;
}
.item {
position: relative;
margin-bottom: 1em;
height: 100px;
background: white;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
Option 2
This method is a slight modification to how the .item margin is applied where we will apply to all .item's except the last one using :not(last-child).
jsFiddle
html, body {
height: 100%;
}
body {
margin: 0;
background: red;
}
.container {
margin: auto;
min-height: 100vh;
max-width: 200px;
background: grey;
}
.item {
position: relative;
height: 100px;
background: white;
}
.item:not(:last-child) {
margin-bottom: 1em;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
Option 3
If you're familiar with Flexbox, you could solve it that way with the following edits to your CSS:
body {
margin: 0;
background: red;
display: flex;
flex-direction: column;
justify-content: center;
}
.container {
/* Without a min height set the width
/* will default to the content's width */
/* max-width: 200px; */
width: 200px;
margin: auto;
background: gray;
min-height: 100vh;
box-sizing: border-box;
}
.item {
position: relative;
margin-bottom: 1em;
height: 100px;
background: white;
}
<body>
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
</body>
Here, we set body as flexbox, set as column direction, and center the content (direct children).
Importantly, we have to set a minimum width so that if our content is less than 200px it won't get squished.
You can just set height: 100% on the container for it to be the height of the page at all times.
The below modified code should help you. Set margin: 0 in the html and body elements
html, body { /* or use * to apply this margin reset to all elements */
margin :0;
}
body{
background: red;
}
.container {
margin: auto;
max-width: 200px;
background: gray;
height:100vh;
box-sizing: border-box;
}
.item {
background: white;
margin-bottom: 1em;
height: 100px;
}
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
You might try to add some padding to your .item
First div should fill up remaining height that's left while second div should be positioned at the bottom with it's initial height.
DEMO:
.container {
width: 240px;
height: 400px;
background: #E0E0E0;
display: flex;
flex-direction: column;
}
.first {
border :1px solid black;
padding: 1em;
box-sizing: border-box;
}
.second {
border: 1px solid blue;
padding: 1em;
box-sizing: border-box;
}
<div class="container">
<div class="first">
I SHOULD FILL WHATS REMAINING AFTER SECOND ONE
</div>
<div class="second">
<div>
I SHOULD BE AT THE BOTTOM FILLING ONLY MY OWN HEIGHT
</div>
</div>
The answer to this would vary from markup to markup, but in your case you can just add this to your first element:
height: 100%;
This works because of your flex display property of the container. A different property on the container would likely require another solution.
Demo
Full code
.container {
width: 240px;
height: 400px;
background: #E0E0E0;
display: flex;
flex-direction: column;
}
.first {
height: 100%;
border :1px solid black;
padding: 1em;
box-sizing: border-box;
}
.second {
border: 1px solid blue;
padding: 1em;
box-sizing: border-box;
}
<div class="container">
<div class="first">
I SHOULD FILL WHATS REMAINING AFTER SECOND ONE
</div>
<div class="second">
<div>
I SHOULD BE AT THE BOTTOM FILLING ONLY MY OWN HEIGHT
</div>
</div>
You need to make height auto to container class so depend on length of string your height is increase.
<style>
.container {
width: 240px;
height: auto;
background: #E0E0E0;
display: flex;
flex-direction: column;
}
.first {
border :1px solid black;
padding: 1em;
box-sizing: border-box;
}
.second {
border: 1px solid blue;
padding: 1em;
box-sizing: border-box;
}
</style>
<div class="container">
<div class="first">
I SHOULD FILL WHATS REMAINING AFTER SECOND ONE
</div>
<div class="second">
<div>
I SHOULD BE AT THE BOTTOM FILLING ONLY MY OWN HEIGHT
</div>
</div>