Why does my position: absolute child overflow my parent's border? - html

I have a parent container, with some child components inside. The last child has to be placed at the bottom of the container. I tried using justify-content: space-between, but it doesn't work for me because I need that the space between the last element and the other elements is greater and noticeable. I ended up trying position:absolute, bottom: 0, but the width of the child is greater than the parent.
Perhaps there's a better way to do it by mixing with flex, just haven't been able to do it.
.Parent {
background: #F8F8F8;
height: 400px;
padding: 20px;
width: 395px;
position: relative;
max-width: 395px;
border: solid 1px red;
}
.First--Child {
border: solid 1px blue;
height: 40px;
margin: 10px 0;
}
.Second--Child {
border: solid 1px green;
height: 40px;
margin: 10px 0;
}
.Third--Child {
border: solid 1px violet;
height: 40px;
margin: 10px 0;
}
.Last--Child {
border: solid 1px cyan;
height: 60px;
position: absolute;
bottom: 0;
width: 100%;
margin: 0 0 10px 0;
display: flex;
justify-content: space-between;
}
.Left--Button,
.Right--Button {
border: solid 1px gray;
width: calc(100% - 300px);
}
<div class='Parent'>
<div class='First--Child'>
</div>
<div class='Second--Child'>
</div>
<div class='Third--Child'>
</div>
<div class='Last--Child'>
<button class='Left--Button'>Left</button>
<button class='Right--Button'>Right</button>
</div>
</div>

The width of the last child isn't wider than the parent - its the same width. It is the margin that has caused it to be out of alignment.
If the bottom placement is correct for your needs, you could get the horizontal alignment sorted either by removing the padding on the parent, setting the child to:
left: -20px
or
margin-left: -20px
, or adding
box-sizing:border-box
to the parent

If you must use this layout technique, you could calculate the last--child's width minus the padding of the parent.
.Parent {
background: #F8F8F8;
height: 400px;
padding: 20px;
width: 395px;
position: relative;
max-width: 395px;
border: solid 1px red;
}
.First--Child {
border: solid 1px blue;
height: 40px;
margin: 10px 0;
}
.Second--Child {
border: solid 1px green;
height: 40px;
margin: 10px 0;
}
.Third--Child {
border: solid 1px violet;
height: 40px;
margin: 10px 0;
}
.Last--Child {
border: solid 1px cyan;
height: 60px;
position: absolute;
bottom: 0;
width: calc(100% - 40px);
margin: 0 0 10px 0;
display: flex;
justify-content: space-between;
}
.Left--Button,
.Right--Button {
border: solid 1px gray;
width: calc(100% - 300px);
}
<div class='Parent'>
<div class='First--Child'>
</div>
<div class='Second--Child'>
</div>
<div class='Third--Child'>
</div>
<div class='Last--Child'>
<button class='Left--Button'>Left</button>
<button class='Right--Button'>Right</button>
</div>
</div>

Try this for your CSS. I split the buttons into two classes and just floated them while adding a height percentage for the fill. This is assuming you are okay with absolute positioning.
.Parent {
background: #F8F8F8;
height: 400px;
padding: 20px;
width: 395px;
position: relative;
max-width: 395px;
border: solid 1px red;
}
.First--Child {
border: solid 1px blue;
height: 40px;
margin: 10px 0;
}
.Second--Child {
border: solid 1px green;
height: 40px;
margin: 10px 0;
}
.Third--Child {
border: solid 1px violet;
height: 40px;
margin: 10px 0;
}
.Last--Child {
border: solid 1px cyan;
height: 60px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: block;
justify-content: space-between;
}
.Left--Button {
height:100%;
float:left;
border: solid 1px gray;
width: calc(100% - 300px);
}
.Right--Button {
height: 100%;
float: right;
border: solid 1px gray;
width: calc(100% - 300px);
}

The last child has to be placed at the bottom of the container. I tried using justify-content: space-between, but it doesn't work for me because I need that the space between the last element and the other elements is greater and noticeable.
With justify-content: space-between (in a vertical container) or align-content: space-between (in a horizontal container) you can pin the last item to the bottom, and not impact the siblings' position, only if there are two items (one stays on top, the other stays at the bottom).
But if there are more than two items, then this method will not work because space-between distributes space evenly between items, causing the items between the first and last to spread out.
Since you have more than two items in your container, you need another method.
Absolute positioning indeed works. It pins the last item to the bottom. However, it also removes the item from the normal flow, meaning that it doesn't take up space and siblings can overlap it.
Flexbox, however, provides a clean and efficient alternative: auto margins. By setting the last item to margin-top: auto, it shifts to the bottom of the container, while its siblings remain at the top.
Here's a complete explanation, which includes a comparison of space-between and auto margins:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
.Parent {
display: flex; /* new */
flex-direction: column; /* new */
height: 400px;
padding: 20px;
max-width: 395px;
border: solid 1px red;
background: #F8F8F8;
}
.First--Child {
border: solid 1px blue;
height: 40px;
margin: 10px 0;
}
.Second--Child {
border: solid 1px green;
height: 40px;
margin: 10px 0;
}
.Third--Child {
border: solid 1px violet;
height: 40px;
margin: 10px 0;
}
.Last--Child {
border: solid 1px cyan;
height: 60px;
margin: auto 0 10px 0; /* adjustment to margin-top */
display: flex;
justify-content: space-between;
}
.Left--Button,
.Right--Button {
border: solid 1px gray;
width: calc(100% - 300px);
}
<div class='Parent'>
<div class='First--Child'></div>
<div class='Second--Child'></div>
<div class='Third--Child'></div>
<div class='Last--Child'>
<button class='Left--Button'>Left</button>
<button class='Right--Button'>Right</button>
</div>
</div>

Related

How to set dynamic div height [duplicate]

This question already has answers here:
Fill the remaining height or width in a flex container
(2 answers)
Fill remaining vertical space with CSS using display:flex
(6 answers)
Closed 1 year ago.
There is the following HTML:
body {
padding: 10px;
border: 2px solid black;
margin: 2px;
}
.div1 {
height: 50px;
border: 2px solid black;
}
.div2 {
/* height: ??? */
border: 2px solid black;
margin-top: 2px;
margin-bottom: 2px;
}
<body>
<div id="div1" class="div1"></div>
<div id="div2" class="div2"></div>
</body>
The height of div1 should be always static 50px, the rest of parent space should be filled with div2. For example,
if body.height == 700px then
div1.height = 50px
div2.height = 650px
How to define and set this dynamic height for the div2?
If the above is your exact case then you can use the css calc()
So, set your css like so:
#div1{
height:50px;
}
#div2{
height:calc(100% - 50px);
}
As long as there is a defined height on body, this should work
grid, padding and box-sizing will help you here:
* {
box-sizing: border-box;
margin: 0;
}
html {
padding: 2px;
height: 100%;
}
body {
padding: 10px;
border: 2px solid black;
/* added*/
min-height: 100%;
display: grid;
grid-template-rows: 50px 1fr;
gap: 2px;
}
.div1 {
border: 2px solid black;
}
.div2 {
border: 2px solid black;
margin-top: 2px;
margin-bottom: 2px;
}
<body>
<div id="div1" class="div1"></div>
<div id="div2" class="div2"></div>
</body>
You can use css flexbox
body {
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 0;
margin: 0;
}
.div1 {
height: 50px;
border: 1px solid red;
}
.div2 {
flex-grow: 1;
border: 1px solid green;
}

Two borders overlapping with different sizes

Is there any better way of setting two borders like in the example below? I could only do it with positioning. I'm new here so I apologize for any mistakes whatsoever.
.border1 {
margin: 0 auto;
height: 300px;
width: 250px;
border: 9px solid red;
position: relative;
}
.border2 {
border: 9px solid blue;
height: 250px;
width: 300px;
position: absolute;
top: 12px;
left: -33px;
}
<div class="border1">
<div class="border2"></div>
</div>
Absolute is indeed a good and easy way here.
You can also use a pseudo and only coordonates to size the second border box.
.border1 {
margin: 0 auto;
min-height: 150px;/* allow it to grow */
width: 250px;
padding:20px 0.5em;
border: 9px solid red;
position: relative;
}
.border2:before {
content:'';
border: 9px solid blue;
pointer-events:none;/* to allow clicking through else you may use a negative z-index */
position: absolute;
top: 12px;
bottom:12px;
left: -33px;
right:-33px;
}
<div class="border1 border2">
add anything here instead setting height
</div>
This is a different approach. I used box-shadow as the second border and you will no longer need a second div for second border.
.border{
margin:0 auto;
height:300px;
width:250px;
border:9px solid red;
position:relative;
box-shadow: 0 0 0px 9px blue;
}
<div class="border"></div>
You can do it with the Flexbox and without unnecessary calculations:
.border1 {
margin: 0 auto;
height: 300px;
width: 250px;
border: 9px solid red;
display: flex; /* displays flex-items (children) inline */
justify-content: center; /* centers them horizontally */
align-items: center; /* and vertically */
}
.border2 {
flex: 0 0 300px; /* doesn't shrink, flex-basis set to "300px" (initial width) */
border: 9px solid blue;
height: 250px;
}
<div class="border1">
<div class="border2"></div>
</div>

HTML extend height of div

div.div1 {
position: relative;
border: 1px solid black;
height: 100px;
width: 100px;
padding: 10px;
}
div.div2 {
background-color: gray;
border: 1px solid black;
padding: 10px;
}
div.div3 {
position: absolute;
border: 1px solid red;
height: 20px;
width: 20px;
bottom: 10px;
left: 10px;
}
<div class="div1">
<div class="div2">Test 123</div>
<div class="div3">A</div>
</div>
I use the above code to display a big div with two divs in it. For the first one I use position: absolute to place it on bottom left of the div.
How can I extend the height of the second gray one so that it's 5 pixels above the first, but without having to measure its exact height in pixel (like the pic below)? I can set height: 50px; for example but is there another way?
I would use a flexbox approach rather than absolute positioning (comments in css below)
div.div1 {
display: flex;
flex-direction:column;
/* add the above styles*/
border: 1px solid black;
min-height: 100px; /*I would also change this to min-height otherwise it may cause issues if your text goes to 2 lines*/
width: 100px;
padding: 10px;
}
div.div2 {
flex-grow:1; /* make div grow to fill the space */
margin-bottom:5px; /* minus the amount of margin you wanted */
background-color: gray;
border: 1px solid black;
padding: 10px;
}
div.div3 {
/* remove absolute positioning */
border: 1px solid red;
height: 20px;
width: 20px;
}
<div class="div1">
<div class="div2">Test 123</div>
<div class="div3">A</div>
</div>
EDIT: I suggest that, if you can focus on the modern browser features, going the flexbox way as shown by Pete is definitely a cleaner approach than the ones I've shown bellow. That being said, here are the alternatives:
You can use calc to dynamically determine the height of div2:
div.div1 {
position: relative;
border: 1px solid black;
height: 100px;
width: 100px;
padding: 10px;
}
div.div2 {
background-color: gray;
border: 1px solid black;
padding: 10px;
height: calc(
100%
- 20px /* div1: padding top and bottom */
- 2px /* div1: border top and bottom */
- 20px /* div3: height */
- 2px /* div3: border top and bottom*/
- 5px /* desired separation*/
);
}
div.div3 {
position: absolute;
border: 1px solid red;
height: 20px;
width: 20px;
bottom: 10px;
left: 10px;
}
<div class="div1">
<div class="div2">Test 123</div>
<div class="div3">A</div>
</div>
You can avoid including padding and border width in your calculations if you set the box-sizing for your divs to border-box (You might want to set this for all elements):
div {
box-sizing: border-box;
}
div.div1 {
position: relative;
border: 1px solid black;
height: 100px;
width: 100px;
padding: 10px;
}
div.div2 {
background-color: gray;
border: 1px solid black;
padding: 10px;
height: calc(
100%
- 20px /* div3: height */
- 5px /* desired separation */
);
}
div.div3 {
position: absolute;
border: 1px solid red;
height: 20px;
width: 20px;
bottom: 10px;
left: 10px;
}
<div class="div1">
<div class="div2">Test 123</div>
<div class="div3">A</div>
</div>
There's this rather new, hip CSS property called 'flex' which you're now going to love because it does it exactly that without the need of positioning absolute etc. I did something similar yesterday where I had a vertical nav bar and I wanted one menu at the top and one at the bottom. In a responsive environment; using your approach of positioning absolute it would've resulted in a nasty mess of working out heights to stop the content from overlapping. Flex prevented this! Yeyyyyy
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
In your example you want to do something like this:
.div1 {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: space-around;
}
.div2 {
align-self: flex-start;
flex-grow:1;
width:100%;
}
.div3 {
align-self: flex-end;
width:100%;
}
Now your div 3 will always be at the bottom. Although now .div3 will extend the entire width so within the div insert your content and BOOM done.
You can use calc on the heightsetting as in my snippet below. That setting is 100% minus (20 + 10 + 2) for the height, border and bottom of the lower DIV minus (5 + 2) for the distance and the border of the first DIV minus 10px for the padding of the parent, summing up to 49px .
div.div1 {
position: relative;
border: 1px solid black;
height: 100px;
width: 100px;
padding: 10px;
}
div.div2 {
background-color: gray;
border: 1px solid black;
padding: 10px;
height: calc(100% - 49px);
}
div.div3 {
position: absolute;
border: 1px solid red;
height: 20px;
width: 20px;
bottom: 10px;
left: 10px;
}
<div class="div1">
<div class="div2">Test 123</div>
<div class="div3">A</div>
</div>

Make height of input and div equal to their parent

I've got the following code:
.wrapper {
display: flex;
height: 25px;
}
.myInput {
width: 50px;
height: 100%;
border: 1px solid grey;
border-right: none;
}
.myInputAddon {
width: 25px;
height: 100%;
background-color: green;
border: 1px solid green;
}
<div class="wrapper">
<input class="myInput">
<div class="myInputAddon" type="number"></div>
</div>
I thought, when I give a hardcoded height to my wrapper div (in the example 25px) and then height: 100%; to his child-elements, they would flex correctly and have the same height.
But in my snippet, my input is higher than my div.
If I remove the height from the wrapper div and give the input a height 23px and to the child-div 25px, it works. But I would like to set it a little bit dynamically.
It should look like this:
How can I do this?
Thanks and cheers.
The problem is default padding of input element so you can just add box-sizing: border-box and keep padding inside height of element.
.wrapper {
display: flex;
height: 25px;
}
.wrapper * {
box-sizing: border-box;
}
.myInput {
width: 50px;
height: 100%;
border: 1px solid grey;
border-right: none;
}
.myInputAddon {
width: 25px;
height: 100%;
background-color: green;
border: 1px solid green;
}
<div class="wrapper">
<input class="myInput">
<div class="myInputAddon" type="number"></div>
</div>
The input element has default styling from the browser:
Make the following adjustments:
.wrapper {
display: flex;
height: 25px;
}
.myInput {
width: 50px;
height: 100%;
border: 1px solid grey;
border-right: none;
box-sizing: border-box; /* NEW; padding and border now absorbed into height:100% */
}
.myInputAddon {
width: 25px;
height: 100%;
background-color: green;
border: 1px solid green;
box-sizing: border-box; /* NEW */
}
<div class="wrapper">
<input class="myInput">
<div class="myInputAddon" type="number"></div>
</div>

Make Divs on both sides of another div expand to the edge of the container

Best way to demonstrate what I want is to show it:
I want the left and right div to expand to the left and right edge of the container div automatically.
It can be done with Javascript and with flex but I'm wondering is there is another way that supports IE9+ (flex is IE11+)
I created this live demo (click "Run with JS") with a dynamically changing center div (since the "real life" problem doesn't have a static size)
Using a display: table-cell would make it easy for you.
Demo: http://jsfiddle.net/abhitalks/VytTX/1/
HTML:
<div class="outer">
<div id="left" class="inner"></div>
<div id="center" class="inner">...</div>
<div id="right" class="inner"></div>
</div>
CSS:
body { width: 100%; }
div.outer {
width: 90%;
border: 1px solid gray;
background-color: rgb(12, 34, 43);
text-align: center;
display: table;
border-spacing: 10px;
}
div.inner {
border: 1px solid gray;
height: 200px;
display: table-cell;
min-width: 20px; width: 20px;
padding: 4px;
background-color: rgb(212, 234, 143);
}
You could achieve that like this :
An example: http://codepen.io/srekoble/pen/rugxh (change the variable of the center width $width)
It's a sass file for a variable usage:
* {
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
div.outer {
width: 100%;
border: 1px solid gray;
background-color: rgb(12,34,43);
text-align: center;
margin: 0 auto;
font-size: 0;
}
div.inner {
border: 1px solid gray;
height: 200px;
display:inline-block;
min-width: 20px;
}
$width: 50%;
#center {
width: $width;
background: red;
}
#left,
#right {
width: ( 100% - $width ) / 2;
background: yellow;
}
<style>
body
{
background: #0B222A;
}
.outer
{
width: 400px;
height: 300px;
background: #D3EA8F;
margin: auto;
}
.inner
{
width: 60%;
height: 300px;
background: #D3EA8F;
border-left: solid 10px #0B222A;
border-right: solid 10px #0B222A;
margin: auto;
}
</style>
<div class="outer">
<div class="inner"></div>
</div>