Why does this absolutely positioned element follow the flow? - css

I just stumbled across something baffling:
.parent {
position:relative;
background:lime;
height: 100px;
}
.parent div {
position:absolute;
background-color: yellow;
}
<div class="parent">
Parent
<div id="test">Child</div>
</div>
Notice that the yellow "Child" rectangle is below the word "Parent". Why? The way I understand the default values for top and left are 0, so the element should position itself at the upper-left corner of the parent. In fact, if I remove the text Parent or add top: 0 to the child element, this is what happens. But why does in this case the absolutely positioned box follow the flow?

The absolute position is still anchored in the flow of the content of its parent element when position is auto (which is the default). If you move the child element to the beginning of the parent, you see what you had expected (see snippet below). You can avoid that by adding top: 0; and left: 0;
.parent {
position:relative;
background:lime;
height: 100px;
}
.parent div {
position:absolute;
background-color: yellow;
}
<div class="parent">
<div id="test">Child</div>
Parent
</div>

Ahh, finally found the answer I was looking for! Thanks to #Cbroe for pointing me in the right direction:
https://drafts.csswg.org/css21/visudet.html#abs-non-replaced-height
If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below.

Related

Using position:absolute, the nearest positioned ancestor is having no effect

I have a parent and a child div. Parent has one image. Child div has another image. Child image needs to appear in top-left corner of parent image for which I thought to set position of child image to absolute and parent's position to some non-static position, say relative or absolute. (I set left and top too but let's forget about it for now.)
This is because setting absolute for the child should work only if its first ancestor is positioned non-statically as according to W3Schools absolute means The element is positioned relative to its first positioned (not static) ancestor element.
But I noticed that even if I don't set position of the parent (i.e. its position will be "static" by default), event then the child image still gets positioned nicely in top-left.
Can someone help me understand why I don't have to set position of the parent to some non-static value in order for the absolute property to work properly? or did I understand working of absolute incorrectly?
<div class="parent">
<img src="https://lh4.ggpht.com/wKrDLLmmxjfRG2-E-k5L5BUuHWpCOe4lWRF7oVs1Gzdn5e5yvr8fj-ORTlBF43U47yI=w300">
<div class="child">
<img src="http://xiostorage.com/wp-content/uploads/2015/10/test.png" width="200">
</div>
</div>
/*.parent {
position:relative;
}*/
.child {
display:none;
position:absolute;
left:0;
}
.parent:hover .child {
display:initial;
}
Here is the JSFiddle code.
Update:
Connexo helped with following updated code.
Try uncommenting the position for parent to unlock the mystery. Accepted answer has more information.
<h1>
Positioning test
</h1>
<div class="parent">
<img src="https://lh4.ggpht.com/wKrDLLmmxjfRG2-E-k5L5BUuHWpCOe4lWRF7oVs1Gzdn5e5yvr8fj-ORTlBF43U47yI=w300">
<div class="child">
<img src="http://xiostorage.com/wp-content/uploads/2015/10/test.png" width="200">
</div>
/*
.parent {
position:relative;
}*/
.child {
display: none;
position: absolute;
left: 0;
top: 0;
}
.parent:hover .child {
display:initial;
}
Two general rules to keep in mind:
An absolutely positioned element will be positioned within its containing block, which is defined by the nearest positioned ancestor. However, if there is no positioned ancestor, the containing block is the initial containing block (i.e., the viewport).
Your .parent div is pretty much aligned at the top-left corner of the viewport. That's why your absolutely positioned child will have similar positioning in either containing block.
When you apply position: absolute to an element you remove it from the normal flow. That's it. The element will still be positioned as though it were in the normal flow. It isn't until you apply the CSS offset properties (left, right, top, bottom) that you actually position the element.
You forgot setting top in your JSFiddle so all it did was get aligned to the left side of the page, where your image was as well. As soon as you add top: 0px in your JSFiddle you will notice that the image does end up in the top left corner of the page.
Below a simple demo with top added and a margin pushing the .parent away from the corner.
.parent {
margin: 30px;
/* position: relative;*/
}
.child {
display:none;
position:absolute;
left:0;
top:0;
}
.parent:hover .child {
display:initial;
}
<div class="parent">
<img src="https://lh4.ggpht.com/wKrDLLmmxjfRG2-E-k5L5BUuHWpCOe4lWRF7oVs1Gzdn5e5yvr8fj-ORTlBF43U47yI=w300">
<div class="child">
<img src="http://xiostorage.com/wp-content/uploads/2015/10/test.png" width="200">
</div>
</div>

Why does an absolutely positioned child expand container height and how to prevent this?

Suppose you have a parent div that contains several normal children and one absolute child.
I've read practically everywhere that a child with position: absolute will not influence parent's height, since it is out of the normal flow. However in my case, an absolute element expands the parent, and I can't understand why.
(I tried reading the spec but I'm really lost.)
HTML
<div class="container">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="outsider"></div>
</div>
CSS
.container {
overflow: hidden;
}
.block, .outsider {
width: 100%;
height: 1000px;
}
.block {
background: red;
}
.outsider {
position: absolute;
left: 0;
top: 3000px;
background: green;
opacity: 0.5;
}
Why does the browser let me scroll past the element's supposed height? It seems consistent in Chrome, Safari and Firefox so I presume it's part of the spec.
How do I prevent this behavior? I'd like absolutely positioned element to be cropped if it doesn't fit into the container height “dictated” by “normal” children.
See it live.
You are missing a position on your parent container. Add
.container{
position: relative;
}
The absolutely positioned element will go back up the DOM to find the nearest positioned parent, in this case you don't have one explicitly defined, so it's going back up to <body>

css overflow and margin-left

I have three divs inside a parent div with overflow:hidden; and I want to show the third. So I thought, I could give the first div an margin-left and the two other will be shift to the left.
<div style="width:1000px;background:red;overflow:hidden;height:50px;">
<div style="width:1000px;height:50px;float:left;margin-left:-2000px;">
1
</div>
<div style="width:1000px;height:50px;float:left;">
2
</div>
<div style="width:1000px;height:50px;float:left;">
3
</div>
</div>
But it shows the second div. But if I add margin-left:-1000px; to the second div and replace margin-left:-2000px; to -1000px on the first div it will work correctly. I don´t understand why.
When you set -1000px to div, this div is no longer in relative position, so the another divs assumes relative position from parent.
Fiddle Example for testing:
http://jsfiddle.net/FvBwC/5/
<div class="parent">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
</div>
.parent { width:1000px; background:red; overflow:hidden; height:50px; }
.one, .two, .three { width: 1000px; height: 50px; float: left; }
.one { background: blue; margin-left: -1000px; }
.two { background: yellow; margin-left: -1000px; }
.three { background: green; }
But for better solution I'd go with display: none in CSS or .hide() in jQuery.
Because the first div is moved 2000 px left outside the parent element. This basically "removes" it from the relative positioning of everything else inside the parent. In other words, the remaining elements are positioned inside the parent as if the first div was never there. Div 2 is positioned relatively as if it was the first element in the parent, i.e. at left:0. If you want to position div 2 outside the parent, you need to explicitly define its position (like setting its margin:-1000px).
To see whats happening clearer, go to your fiddle and set the 3 child divs to width of 100px, keeping the parent at 1000px. Play with the margins some more. You should see whats happening.
EDIT: If all you are trying to do is show a specific div and hide the other two, just set the other two to display:hide.

Absolute positioning and float left/right

This is apparently contradictory. What I need is to have two child elements positioned at the left and right edges of the parent element while vertically centered and overlaid over all other sibling elements.
You can use left and right for that.
.child
{
position: absolute;
top: 50%;
}
.child .left
{
left: 0;
}
.child .right
{
right: 0;
}
The top: 50% will align the top edge of the child to halfway down the parent. If your parent has a constant size, use pixel sizing. Otherwise you'll probably need some javascript to get it exactly right.
edit in response to comment:
To make it relative to the parent instead of the page, you need to give the parent position: relative; and it will work. The default position is static and that won't work for this.
If I undestand correctly:
<div class="parent" style="position:absolute;height:70%;width:70%;top:15%;left:15%;background-color:#eee;border:solid blue 1px;">
<div class="left" style="position:absolute;width:30%;height:70%;top:15%;left:0%;background-color:black;z-index:20;">left box vertically aligned</div>
<div class="right" style="position:absolute;width:30%;height:70%;top:15%;left:70%;background-color:black;z-index:20;">right box vertically aligned</div>
</div>​
see : http://jsfiddle.net/dankpiff/zmYEf/
If you set the elements underneath with a lower z-index they will be covered by the 'left' and 'right' boxes
Is this what you mean?

How to position a div horizontally based on a value?

How to position a div horizontally?
I used "Float:left" that works. what i need is , want to position that div based on a value( like margin) that value is the distance between the outer divs and inner div that is illustrated in image
I used the margin-left but it compares the distance between the previous child ,instead of the parent(outer div)
I tried the "left" $(area).css(left: LeftVal); that is also not working as expected. In my case I cant use the offset too.
How to achieve this ?
Note: The 100pxs in the image is for a example, i might use different values.
Set the positions as follows :
parent(container) {position:relative;}
child1 {position:absolute;left:100px;top:0;}
You can use position:absolute to position elements absolutely with respect to the parent.
<style>
.outer {
background: blue;
width: 200px;
height: 200px;
position: relative;
}
.inner {
position: absolute;
float: left;
background: red;
height: 200px;
}
.inner1 {
margin-left: 20px;
}
.inner2 {
margin-left: 120px;
}
</style>
<div class="outer">
<div class="inner inner1">Inner1</div>
<div class="inner inner2">Inner2</div>
</div>
You can choose not to use float if you don't want the div to resize based on the content. Instead, you could set the width manually for each div.

Resources