After a couple of waisted hours I've managed to find a solution to my problem, so the question is not "how to", but "why it works like that". Here's my stripped down example:
<div id="header">
<div id="header-element">header</div>
</div>
<div id="footer">footer</div>
CSS:
#header {
width: 100%;
position: relative;
padding-bottom: 5%;
}
#header-element {
position:absolute;
bottom: 0;
}
#footer {
position: relative;
margin-top: 5%;
}
And jsFiddle - http://jsfiddle.net/H7jwm/3/.
My problem was how to position those relatively positioned elements using percentage, first one some % off the top of the document, and the second one from the first one. I've accomplished that by giving padding-bottom to the first one, and margin-top to the second one, but I've got to the solution with a brute force - trying out every remotely logical solution. Now, if you remove the padding, margin-top of the second element becomes margin between that element and the top of the document, not the first element, and that first element "takes" rest of the space to the top.
The question is why that padding works like that? Or, to rephrase it, how does padding work with relative positioning?
Actually, you are mixing positions. Your #header has a height of zero. That's right, zero like in nothing, because it has no relative content. #header-element is absolutely positioned and because #header has a height of 0 it happens to be exactly in the padding-bottom space.
So, if you remove the padding-bottom from #header, the #footer moves up, starting right at the top of the document. Because of the margin-top, there's some space between the document top border and the word 'footer'.
But you still have that absolutely positioned #header-element, which will now be right in that margin-top space.
Related
I've been writing CSS for quite some time now.
I've noticed that
<div style="position: relative; right: 20%; bottom: 20%;">some text</div>
never works!
relative positioning would work with left and top specified but not with right/bottom. Why?
A quick fix around this is to use "absolute" instead and specify right/bottom in pixels, but I need a reason.
Also, correct me if I'm wrong. Irrespective of whether the external container is positioned absolutely or relatively, does it not make much sense to position something "relative" to the boundaries of that container or should elements inside a container always be positioned "absolute"?
Thank you.
From Absolute vs. Relative - Explaining CSS Positioning
Relative positioning uses the same four positioning properties as absolute positioning. But instead of basing the position of the element upon the browser view port, it starts from where the element would be if it were still in the normal flow.
Relative positioning does work with bottom/right values, just not the way you were expecting:
http://cssdesk.com/RX24j
Think about the position values on relative elements as margins, that the surrounding elements simply ignore. The "margins" will always move the element relative to it's previous position in the normal document flow, but remove it from the normal flow at the same time.
When out of the normal document flow, the surrounding elements act as if it were in it's original position in the normal flow... but it's not. This is why a relative element can overlap it's parent (like in Rel 1).
Did you try this?
<div style="position: relative; right: -20%; bottom: -20%;">some text</div>
or rather
<div style="position: relative; right: -80%; bottom: -80%;">some text</div>
not recommended :
left : 0% //will set it to left
left : 100% //will set it to right => you need to get the width of the element and subtract it using calc ( 100% - width)
To people visiting this old post...
if the element that you are trying to position inside something else has a width or height that is larger than the outer element. The position will ignore left, right, bottom, left.
give it width/height auto.
that was the problem that I had. Hope it helps you too!
remove position left, right, top, bottom from the parents element
and put it in the child as you want
.parent_class
{
background: #ff0000 ;
position: absolute;
transition: 0.8s ease-out;
left:0; //" remove this from here"
top:0; // " remove this from here"
z-index: -1;
}
.child_class
{
width: 0px;
height: 70px;
right: 0; //"now it will work"
bottom: 0;//"now it will work"
}
I have a site with absolute positioned elements on it, for example the top Navigation of the site:
#topNav
{
position: absolute;
top: 100px;
left: 50%;
height: 40px;
width: 1000px;
margin-left: -500px;
}
Now I created a sticky footer like on the following site:
http://ryanfait.com/resources/footer-stick-to-bottom-of-page/
Now, the problem is that the footer will "overlap" the topNav,
because the topNav is positioned absolute, which means it's "outside of the normal float of elements". The relative position will not "notice" that there is the topNav before.
Before I start creating additional "pusher divs" for each absolute positioned element I would better ask if there are better practices than "pusher divs" or should I even not use position absolute on my elements?
EDIT:
JsFiddle here: http://jsfiddle.net/dkxUX/15/
When you scale down your browserwindow you'll find #footer overlapping all elements before it.
You could just apply a 140px top margin/padding to the body or other container element which would make the topNav's height and offset accounted for.
Better yet, don't set position to absolute in this case - it appears to me that all you're doing is horizontally centering a 1000px wide div.
/*top-margin of 100px + center the element*/
#topNav {width:1000px; height:40px; margin:100px auto 0;}
Update: I see your jsfiddle now. You could account for all absolutely positioned elements when setting the margin/padding as suggested in the first paragraph You are using absolutely positioned elements when normal document flow could be relied on.
a little bit too late to give an answer but it may help someone in the future, I came up with that problem not too long ago so here was my shot at it, using jquery since I couldn't came up with a CSS solution that wasn't removing the DOCTYPE tag (which isn't something you should do, anyways).
So here it is.
$("#CONTAINERDIV").prepend("<div id='relativefix' style='position:relative;margin-top:"+($("#YOUR_ABSOLUTE_DIV").offset().top+$("#YOUR_ABSOLUTE_DIV").outerHeight()+30)+"px'></div>");
$(window).resize(function(){
$("#relativefix").css("margin-top",($("#YOUR_ABSOLUTE_DIV").offset().top+$("#YOUR_ABSOLUTE_DIV").outerHeight()+30)+"px");
});
So yeah, that's all there is to it, you just dynamically add another div at the start of the container hard-placed under the absolute div, that will force all subsequent relative divs to me placed after it, it is like a clear fix for someone who ran out of ideas.
I have a "ribbon" type header on the top of my website:
#top-wrapper {
border-bottom: 5px solid #A1C1BE;
width: 100%;
background-color: #59554E;
position: absolute;
top: 0;
left: 0;
margin-bottom: 100px;
padding: 10px 0 0 0;
color: #C0C0A8;
}
The absolute positioning is needed to make sure it occupies the complete width of the user's browser (as far as I know). However, the rest of my webpage (the main body which contains all my other divs) is hidden behind this ribbon:
#pagebody {
width: 60%;
margin-left: auto;
margin-right: auto;
}
The only solution I have been able to find is adding a bunch of <br> between the end of top-wrapper and the start of pagebody.
Is there a better way of doing this?
As per my comment in another answer:
You can just use width: 100%, but make sure you remove the default gap it leaves with:
html, body {
margin: 0;
padding: 0;
}
You should also check out necolas' normalize.css. It includes all of this basic CSS rules you're going to need in pretty much every site :)
Absolutely positioned elements (top-wrapper) are always on top of relative elements (pagebody), unless you do some hacky stuff with z-index (and even that is limited). What you probably want to do is move the pagebody element down just past the top-wrapper. I don't know how tall your top-wrapper is because it has no specified height. And you might not know it due to font-size differences. But overall, you simply need to add a top margin or padding to the pagebody tag, something like this:
margin-top:50px;
Absolute positioning takes an element out of the normal flow. You do not need absolute positioning to maximize width. You do that with width:100%.
There are many ways to do this. First, you can place your top wrapper outside the pagebody element and then just define its width as 100%.
If you have a graphic that is a ribbon and it is supposed to overlap the top of the pagebody element - as I think you are saying above - then you would use position absolute and z-index to place it above the pagebody element. Then add the proper padding-top to pagebody.
You didn't provide html so we don't really know what you're up to totally.
I have the following mark up:
<div id="playArea" style="position: relative;">
<div style="position: absolute; left: 295px; top: -1px; width: 313px; height: 269px;">Hello</div>
<div style="position: absolute; left: 63px; top: 35px; width: 80px; height: 42px;">World</div>
<div style="position: absolute; left: 534px; top: 329px; width: 183px; height: 251px;">Bye</div>
</div>
But i would like to have a paragraph of text under the 'playArea' div, but because all the divs inside playArea is absolute, the text doesnt appear at the bottom of the last absolute positioned div.
I have looked into this and found an alternative by using float:left and clear:left however after using this method on the first div, you cannot position the div correctly as the starting point of the second div is under the first div and not at (0,0). Any ideas of how i can get by this.
Thanks
If I understood correctly, you just have to give the "playArea" div the right height.
Edit: I mean, the combined height of everything inside it.
But i would like to have a paragraph of text under the 'playArea' div, but because all the divs inside playArea is absolute, the text doesnt appear at the bottom of the last absolute positioned div.
As you seem to know all the dimensions and positions already, just add another absolutely positioned div to it and put the relative content in it.
I have looked into this and found an alternative by using float:left and clear:left however after using this method on the first div, you cannot position the div correctly as the starting point of the second div is under the first div and not at (0,0). Any ideas of how i can get by this.
You need to remove position: absolute to get the floats right. Just width and height are enough.
Float the three inner divs left, put overflow: hidden; on the playArea div and put your <p> under the three inner divs with clear: both;
After reading the comment thread between you and "BalusC", it appears that you have modified your CSS and are now trying to float your items, and use margin-top and margin-left for positioning. You are totally able to do it that way, but you are forgetting that you can also use negative margins to position your elements as well. For example if you use margin-top:-10px; then it will pull the element up (instead of pushing it down, like a normal positive valued margin). The same goes for all of your other margins.
That seems to be the missing ingredient for you now.
Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}