How to deal with elements that only contain absolutely positioned children? - html

I have a box that contains 2 absolutely positioned header and paragraph elements, I am experimenting on ways on how to center text and I tried tinkering using the method from this site.
Now the issue here isn't about ways on how to position text, because that's not my problem so you should not address that.
My problem is this.
How to make the parent element contain it's children?
Since the parent element contains elements that are absolutely positioned, that means the children are not in the flow and in turn the parent collapses.
Now this is a shocker, because I discovered that the containing/wrapping methods used in the same way for floats DO NOT WORK AT ALL.
Clearfix method.
Clearing div method
Overflow method.
They do not work at all!
The only method that decently works is the "Explicit Height" method which is very inefficient, unpredictable (might break on smaller windows) and not fluid.
Here is a simple, fixed-width rounded corner box who's "h1" and "p" elements I'd like to center using the above referred method.
Sample CSS,
body {
margin: 8px;
padding: 0;}
.box {
margin: 0;
padding: 0;
width: 335px;
position: relative;
background: #40331A url(bottom.gif) no-repeat left bottom;}
.inner {
background: url(top.gif) no-repeat left top;}
.box h2 {
width: 180px;
height: 27px;
top: 50%;}
.box p {
width: 120px;
height: 20px;
top: 50%;}
.box h2, .box p {
margin: 0;
position: absolute;}
Sample markup,
<div class="box">
<div class="inner">
<h2>This is a heading.</h2>
<p>This is a paragraph.</p>
</div>
</div>
So my question.
Is there any simple way to make a parent element contain its absolutely positioned children?

The entire point of absolutely-positioned elements is that the parent of those elements should be laid out as if those elements were never there. If you want the layout of your parent element to take into account its children, don't position them absolutely.
Since you're not including any relevant properties other than position: absolute, it seems completely superfluous, given that absolutely-positioned elements default to their static positions anyway. Just remove that declaration. It doesn't get any simpler than that.
The reason none of those methods work is because they are designed for floats, and absolutely-positioned elements are not floats:
You can't really "clear" anything that isn't a float.
Ditto.
The reason setting overflow works for floats is due to a consequence of the way floats participate in block layout, which does not apply to absolutely-positioned elements. What exactly this entails falls outside the scope of this question, but read up on block formatting contexts.

Related

What does a block formatting context actually do?

To preface, I understand how to create a BFC, I am confused on what a BFC actually does.
MDN says that
Elements participating in a BFC use the rules outlined by the CSS Box Model
and the spec says that
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.
MDN gives the example of a floated div that is out of flow, its height independent from the box parent.
<div class="box">
<div class="float">I am a floated box!</div>
<p>I am content inside the container.</p>
</div>
.box {
background-color: rgb(224, 206, 247);
border: 5px solid rebeccapurple;
/* overflow: hidden; */
}
.float {
float: left;
width: 200px;
height: 150px;
background-color: white;
border:1px solid black;
padding: 10px;
}
And then having the box container ending up filling the height of the floated div. once overflow:hidden is declared which creates a BFC.
.box {
background-color: rgb(224, 206, 247);
border: 5px solid rebeccapurple;
overflow: hidden;
}
How does participating in a BFC end up with this outcome? My thought process:
According to MDN's definition, participating in a BFC makes an element adhere to the box model...but don't all elements, even a floated element, adhere to the box model?
According to the spec's definition, all boxes are laid out vertically, but my-floated div and the p tag are side by side.
It seems that a BFC just makes the container fit all elements participating in its BFC, but if this is the case, then how come using a position: absolute instead of a float: left doesn't provide the same outcome of making the container fit the absolutely positioned element?
e.g.
<div class="box">
<div class="abs">I am an absolutely positioned box!</div>
<p>I am content inside the container.</p>
</div>
.box {
background-color: rgb(224, 206, 247);
border: 5px solid rebeccapurple;
overflow: auto;
position: relative;
height: 50px;
}
.abs {
position: absolute;
top: 250px;
left: 100px;
width: 200px;
height: 150px;
background-color: white;
border:1px solid black;
padding: 10px;
}
Could someone explain what the BFC actually does?
Formatting contexts in general establish a set of rules for the layout of their contents.
The rules for Block formatting contexts are that their in-flow contents are laid out vertically one after the other.
In addition, BFCs have a few side-effects, that exist largely to make the rules established for their contents implementable, such as the way they work in the presence of floats inside or next to them.
Taking your points one by one,
According to MDN's definition, participating in a BFC makes an element adhere to the box model...but don't all elements, even a
floated element, adhere to the box model?
Yes they do. MDN does not actual say that it makes them adhere, just that they do adhere. The MDN statement is rather redundant, but not harmful or incorrect.
According to the spec's definition, all boxes are laid out vertically, but my right-floating div and the p tag are side by side.
This is incorrect. The floating div overlaps the p element. Only the inline content of the p element is side by side with the floating div.
It seems that a BFC just makes the container fit all elements participating in its BFC, but if this is the case, then how come
using a position: absolute instead of a float: left doesn't provide
the same outcome of making the container fit the absolutely
positioned element?
As said above, that BFCs contain their floats is best regarded as a side-effect of the BFC, not really what it does.
Finally, although BFCs provide some isolation of their contents from the outside world, it is not complete. For example, inline-block elements establish BFCs for their contents, but their baselines escape this isolation and are used to vertically align the elements with their inline neighbours.
A BFC is a kind of "isolation" to avoid any interaction of the inside and the outside world of an element. From another part of the MDN you can read:
because an element that establishes a new block formatting context will:
contain internal floats.
exclude external floats.
suppress margin collapsing.
Most of the observation you made (box model, absolute, boxes) aren't related to BFC. Just consider the creation of BFC as a way to encapsulate elements inside (mainly float elements because all the other elements are by default "inside"). Of course, this doesn't apply to absolute/fixed elements because they have their own rule that make them out of the flow.

absolute position inside relative with no defined height

I am trying to put an absolute div inside a relatively positioned div. But I don't want to define a height for the relative div.
The relative div has a background colour and when I don't define a height the absolute div goes 'outside' the relative div. I can't control how many lines the text will be so the height of the divs change
HTML
<div class="row top-footer">
<div class="top-footer-text text-center">
<div class="test">
<h1>title</h1>
<div class="footer-btn-wrap">
<div class="footer-btn">button</div>
<div class="footer-btn">button</div>
</div>
</div>
</div>
</div><!-- /top-footer -->
CSS
.top-footer {
position: relative;
background-color: #686a6f;
width: 100%;
padding-top: 40px; margin: 0;
}
.test {
position: absolute;
top: 0px; margin: 0;
}
EDIT
I want .top-footer (position: relative) to contain .test (position: absolute) with space/padding/margin on the top and bottom of .test. the height of the div is unknown because the content may take up more than one line depending on screen size
Adding whitespace around the child div is fairly trivial. However preventing the parent div from collapsing is more tricky and is the thing you need to tackle first. The problem you are having is that with the parent relatively positioned and the child absolutely positioned, the only element on the entire page that actually "knows" where the child is is the parent... and even then it's a fairly bad parent because it won't even make enough space for the child! The rest of the DOM will behave as if the element isn't even there - other non-positioned elements will float over or above it - even text will be obscured by your child div. Assuming you want to put other content in the parent div using absolute positioning in this way only means you're going to have to use absolute positioning all around the place... which can get a bit heavy on the brain debugging layout problems later on.
The only possible solutions I can think of offhand are:
Use javaascript to sniff out the height of the child div and apply that to the parent. A fairly simple job if you use a library like jQuery but that requires extra downloaded files and makes your site unnecessarily bulky if this is the only task you're using it for. THis also wouldn't solve the problem of the child div obscuring other elements on the page.
Rework your CSS (and it might take a lot of reworking depending on how far you've got and the complexity of the styling) to use display:inline-block on the child... this will stop the parent from collapsing but might give you additional layout issues.
Rework your CSS (ditto) to float:left the child div. You would then need to use a CSS "clear hack" in order to prevent the parent divv from collapsing, although this is a tiny piece of CSS you can cut and paste from elsewhere... an easy job.
If you're determined to use absolute positioning like this my preferred solution would be to use jQuery (option 1) because most of my work tends to use a degree of it anyway... it's a tool I would have handy and the code to perform this task would be quite trivial.
EDIT - Here's a little fiddle to get you started. https://jsfiddle.net/fo8mq1vf/
This is how the output of your code looks like: https://jsfiddle.net/s3zLa54t/2/. The parent div (.top-footer) does contain the .test div. What browser are you using to view the output?
As for the padding, I guess you don't see any effect of changing padding-top. Try removing the top: 0px property in the .test div.
If this is not what you were looking for, do clarify the question here.
The answer to your question is simply remove
position:absolute from your absolute div (.test)
position:relative from your relative div (.top-footer)
height:300px from your relative div (.top-footer)
This is the tested version of https://jsfiddle.net/s3zLa54t/3/ with multiple number of divs under your main div. You can check that it is not going beyond the grey background.
.top-footer {
position: absolute;
background-color: #686a6f;
width: 100%;
padding:0px;
margin: 0;
}
.test h1{
padding-left:20px;
position: relative;
top: 5px; margin: 0;
float:left;
color:#FFF;
}
.footer-btn,.footer-btn-wrap
{
padding-left:200px;
color:#FFF;
}
.footer-btn a{
padding:5px 10px;
float:left;
color:#ffffff;
text-transform:capitalize;
text-decoration:none;
}

DIV changed its behaviour when "position:absolute" was added to it. Why?

I'm new to CSS and I have a question.
First, my HTML and CSS code:
<!-- HTML CODE -->
<body>
<div id="container">Container
</div>
<div id="inner">Inner</div>
</body>
<!-- CSS CODE -->
#container {
background-color:#b6ff00;
width:500px;
height:500px;
position:relative;
}
#inner {
background-color:#ffd800;
}
With current code, the browser shows the following page:
This is expected.
But if I add this css property to #inner element position:absolute; there will be a following output:
As you can see, the #inner div, takes only that much space it needs. Why this changed with only position:absolute; property added to #inner div?
That's because when you use position: absolute; the element will take up width upto the elements defined/content it contains., cuz it just gets out of the document flow so it is block level in nature but won't take up entire horizontal space on the document, as it's just out of the flow of the document..
If you want it to be full width you need to define width: 100%; explicitly so that it will take 100% of the relative parent's width as well as the height if you declare height: 100%;
Also, make sure you always use position: absolute; with a wrapper element set to position: relative; or your element will fly out in the wild which will eventually end up taking the viewport as the last relative wrapper if you set the position of the element using top, right, bottom or left.
I've explained here in detail, that how CSS Positioning Works
Worth to note that, you make any element a position: absolute; element, it will behave as a block level element, but you need to define height and width so for example, if you turn an inline span element a position: absolute; you can define height and width without making it display: block; (Unless and until you are using display: none; initially)
position: absolute; does not behave the same as block elements.
You will need to set a width and a height for a div that is absolutely positioned.
This is fundamentally how position absolute works. Once taken out of the flow of the document it becomes an inline-block element that is absolutely positioned within the nearest element that is positioned relatively (or the top most element)
If you need it to then be a certain dimensions you can try to set widths and heights, or you can do things like
#inner {
position: absolute;
left: 0;
right: 0;
}
...which would ensure it always stuck to the left and right sides of the screen.
It's generally good practice to put things that are positioned absolutely inside of an element with "position:relative" on it, as your code stands it suggests you want your #inner element to be placed anywhere on the page, whereas if you wanted it to be of a size and position relative to #container your code should look like this:
<body>
<div id="container">
Container
<div id="inner">Inner</div>
</div>
</body>
with CSS such as:
#container {
position: relative;
}
#inner {
background-color:#ffd800; width:500px;
height:500px;
position:relative;
}
You can see your output here:-
http://jsfiddle.net/KggJd/
Let me explain a little:
Postition: relative
This will align itself in accordance with the elements found before (i.e) Prior Siblings.
You can change the position by using margin-top, margin-left, ....
Position: absolute
This will always consider from the browser's start point and won't be in accordance with anything.
Drawbacks:
You cannot consider this as the parent or anything when absolutely positioned.
You can change its position by using top, bottom, right, left.

use margin or position relative to position elements

I have always used margin to move a floating div to the correct position in a parent div (say the logo div within a header div). This has always worked but that meant you have to play with the individual height of the elements else it will affect the remainder of the layout downwards.
I found another method today and that is to make the logo div position: relative; and then use example top: 20px; to move the element around, and this does not appear to affect the layout.
I don't want to adapt to this without knowing that there may be other implications, so can anyone point out common flaws in either of the above methods or possibly suggest a better solution?
// Sample HTML
<div id='header'>
<div id='logo'>
LOGO GOES HERE
</div>
</div>
// Sample CSS
#header {
height: 100px;
}
// Version 1
#logo {
float: left;
margin-top: 20px;
}
// Version 2
#logo {
float: left;
position: relative;
top: 20px;
}
From Mozilla developer:
relative
Lay out all elements as though the element were not
positioned, and then adjust the element's position, without changing
layout (and thus leaving a gap for the element where it would have
been had it not been positioned). The effect of position:relative on
table-*-group, table-row, table-column, table-cell, and table-caption
elements is undefined.
I hope this answers your question.
Sometimes it might be the right thing to use, other times not. It really depends on your layout, if you want to make a responsive design, it might be better to have the margin there.
In your case you have a fixed height on the header, so you can use relative. I think it is a more common practice to use margin. I am only aware on issues concerning position: fixed on mobile devices.
You can learn more about CSS and positioning here.
In postion absolute and fix when u use top or bottom or right or left,you must not use float, you must for its parent use this style
postion:relative;
best regards

How to make the wrapping div element with relative position match child elements height?

I have a simple problem where I have 2 divs, 1 is relative positioned. The child element is absolute positioned. This child has varying height.
The code so far:
HTML
<div id="wrap"><div id="inner"></div></div>
CSS
#wrap {
width: 100%;
background: #ccc;
position: relative;
min-height: 20px;
}
#inner {
width:30%;
background: #000;
position: absolute;
right: 0;
top: 0;
height: 200px;
}
The problem I have is that the #wrap element doesn't adjust its height to match the child element and therefor the child element hangs outside the edge of the parent. Can this be done with relative and absolute positioned elements?
I know this can be achieved with floating elements and following them with css => cleared: both, but I'd like to know if its possible with this method.
I've created a jsfiddle of this problem over here if anybody would like to help me out!
Thanks a lot.
Absolute positionned elements are outside the flow so parents can't adjust their height.
But you can simply use:
#wrap {
width: 100%; /* useless */
background: #ccc;
overflow:hidden; /* establish a new formatting context */
min-height: 20px;
}
#inner {
width:30%;
background: #000;
float:right;
}
No, you can't make a parent with position: relative adjust its height to fit a child element with position: absolute.
This is because:
In the absolute positioning model, a
box is explicitly offset with respect
to its containing block. It is removed
from the normal flow entirely (it has
no impact on later siblings). An
absolutely positioned box establishes
a new containing block for normal flow
children and absolutely (but not
fixed) positioned descendants.
However, the contents of an absolutely
positioned element do not flow around
any other boxes.
http://www.w3.org/TR/CSS21/visuren.html#absolute-positioning
If you wanted to stick with your position based code, you'd have to use JavaScript to set the height of the parent div.
Otherwise, stick to using floats if they work for your case. #MatTheCat's answer looks good to me.
Just for completeness, here's a demo of #MatTheCat's answer with height: 200px added, so you can see the parent div does adjust in height: http://jsfiddle.net/gR2wL/3/