Absolute positioning ignoring padding of parent
Asked Answered
A

9

261

How do you make an absolute positioned element honor the padding of its parent? I want an inner div to stretch across the width of its parent and to be positioned at the bottom of that parent, basically a footer. But the child has to honor the padding of the parent and it's not doing that. The child is pressed right up against the edge of the parent.

So I want this:

enter image description here

but I'm getting this:

enter image description here

    <html>
      <body>
        <div style="background-color: blue; padding: 10px; position: relative; height: 100px;">
          <div style="background-color: gray; position: absolute; left: 0px; right: 0px; bottom: 0px;">css sux</div>
        </div>
      </body>
    </html>

I can make it happen with a margin around the inner div, but I'd prefer not to have to add that.

Antisyphilitic answered 14/6, 2013 at 18:49 Comment(4)
Why not change the left/right/bottom of the inner div to style="background-color: gray; position: absolute; left: 10px; right: 10px; bottom: 10px;"?Emmuela
Yeah I thought of that but it quickly becomes a maintenance headache because every child has to have its own set of offsets to account for it. If they would just honor the parent's padding then you could just set it once in the parent and not worry about all the children.Antisyphilitic
As pointed out above, if you use the value of the (relative-positioned) parent's padding as the left: and right: on the (absolute-positioned) child, your problem is solved. I'm adding this b/c that's the answer others with the same problem are likely to be looking for.Incantation
Have a similar issue here: jsfiddle.net/5n4By/6. The footer is honoring its parent's left padding, but it overflows on the right. You would expect it to honor the right padding as well to stay consistent...Penitential
T
294

First, let's see why this is happening.

The reason is that, surprisingly, when a box has position: absolute its containing box is the parent's padding box (that is, the box around its padding). This is surprising because usually (that is, when using static or relative positioning) the containing box is the parent's content box.

Here is the relevant part of the CSS specification:

In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element.... Otherwise, the containing block is formed by the padding edge of the ancestor.

The simplest approach—as suggested in Winter's answer—is to use padding: inherit on the absolutely positioned div. It only works, though, if you don't want the absolutely positioned div to have any additional padding of its own. I think the most general-purpose solutions (in that both elements can have their own independent padding) are:

  1. Add an extra relatively positioned div (with no padding) around the absolutely positioned div. That new div will respect the padding of its parent, and the absolutely positioned div will then fill it.

    The downside, of course, is that you're messing with the HTML simply for presentational purposes.

  2. Repeat the padding (or add to it) on the absolutely positioned element.

    The downside here is that you have to repeat the values in your CSS, which is brittle if you're writing the CSS directly. However, if you're using a pre-processing tool like SASS or LESS you can avoid that problem by using a variable. This is the method I personally use.

Thermodynamic answered 14/6, 2015 at 4:47 Comment(7)
Why is this the default for position: absolute? It is surprising that the containing box is the padding box, but there must have been a reason for it, just like I am sure there is a reason why (without box-sizing) the width & height do not include the padding or border.Cybernetics
Just an addition: none of this is affected by the box-sizing property, on the parent or child. This is because that affects the sizing, as in width/height, but not the containing box, although I admit itt would make more sense if it affected both.Cybernetics
This is good information, but it is the WRONG answer. The right answer is Winter's below.... use padding: inherit and your Absolute element will get the padding it needs. Don't know why this has more upvotes than the right answer ... :PIdolum
@NotaGuruAtAll: padding: inherit works well if the absolutely positioned div doesn't need any padding of its own, and I've added a mention of that technique. It's less flexible, though, because you can't add any additional padding to the absolutely positioned div (i.e. you can't say padding: inherit + 5px). That's why I prefer the techniques I mention here.Thermodynamic
Padding inherit on the position:absolute child element does indeed work if you're just looking for the child to respect the parent's padding. However, if you're looking to add additional padding onto the child you'll have to keep the ratio of paddings in check in your code. No clean way to do it with just CSS.Simoneaux
How did I make it this long without knowing the magic of padding: inherit?! Great suggestion @KevinChristopherHenryHydrargyrum
Excellent answer re: wrapping in another dev. I'm so glad I'm primarily a back-end dev...Gobioid
P
88

One thing you could try is using the following css:

.child-element {
    padding-left: inherit;
    padding-right: inherit;
    position: absolute;
    left: 0;
    right: 0;
}

It lets the child element inherit the padding from the parent, then the child can be positioned to match the parents widht and padding.

Also, I am using box-sizing: border-box; for the elements involved.

I have not tested this in all browsers, but it seems to be working in Chrome, Firefox and IE10.

Panay answered 10/9, 2015 at 13:43 Comment(2)
I combined this answer and @NewSpender 's answer. In my particular case, the absolute positioned div kept ignoring the padding but was bounded by its parent element. So giving the absolute positioned div with white thick borders mimmicked the padding I needed. A prerequisite though is that your background needs to be the same color.Fusil
But OP doesn't want the child to inherit the parent's padding. He wants the child to be offset according to the parent's padding.Despondent
B
35

Well, this may not be the most elegant solution (semantically), but in some cases it'll work without any drawbacks: Instead of padding, use a transparent border on the parent element. The absolute positioned child elements will honor the border and it'll be rendered exactly the same (except you're using the border of the parent element for styling).

Binge answered 9/11, 2013 at 18:11 Comment(0)
S
10

Use margin instead of padding in the parent div: http://blog.vjeux.com/2012/css/css-absolute-position-taking-into-account-padding.html

Sirrah answered 27/2, 2014 at 19:41 Comment(2)
Be aware that background (color) is not applied to margins like it is to paddingBackside
Also, a percentage vertical padding is calculated as a percentage of the width, not height, which is different as compared to calculation of margin (or border).Tropophilous
P
8

Here is my best shot at it. I added another Div and made it red and changed you parent's height to 200px just to test it. The idea is the the child now becomes the grandchild and the parent becomes the grandparent. So the parent respects its parent. Hope you get my idea.

<html>
  <body>
    <div style="background-color: blue; padding: 10px; position: relative; height: 200px;">
     <div style="background-color: red;  position: relative; height: 100%;">    
        <div style="background-color: gray; position: absolute; left: 0px; right: 0px;bottom: 0px;">css sux</div>
     </div>
    </div>
  </body>
</html>

Edit:

I think what you are trying to do can't be done. Absolute position means that you are going to give it co-ordinates it must honor. What if the parent has a padding of 5px. And you absolutely position the child at top: -5px; left: -5px. How is it suppose to honor the parent and you at the same time??

My solution

If you want it to honor the parent, don't absolutely position it then.

Price answered 14/6, 2013 at 19:7 Comment(3)
Thanks, I appreciate the post, but it's still a workaround for the real issue. What I really want to know is if you can make children honor the padding of the parent element. If it turns out the answer is no, I'll give you the rep.Antisyphilitic
If you absolutely position them, then they won't honor their parent element. They'll honor you. For the same reason, if you don't absolutely position them, then you can't really use stuff like bottom: 10px because they honor their parent element. But what you want to do, I'm guessing will make room for a contradiction and thus, it will differ on browsers. I think only a work around will do.Price
Absolute positioning does honor the parent, that's the coordinate system it uses. When you say top 0px, that means 0px away from the top of the parent. The question is whether or not it should take the parents padding into account. If the parent had a padding of 5px and you gave the child top: -5px, it would put it flush with the parent if the parent's padding was honored, or 5px above the parent if it was not.Antisyphilitic
C
4

add padding:inherit in your absolute position

.box{
  background: red;
  position: relative;
  padding: 30px;
  width:500px;
  height:200px;
 box-sizing: border-box;
 

}
<div  class="box">

  <div style="position: absolute;left:0;top:0;padding: inherit">top left</div>
  <div style="position: absolute;right:0;top:0;padding: inherit">top right</div>
  <div style="text-align: center;padding: inherit">center</div>
  <div style="position: absolute;left:0;bottom:0;padding: inherit">bottom left</div>
  <div style="position: absolute;right:0;bottom:0;padding: inherit">bottom right</div>


</div>
Curl answered 5/5, 2020 at 7:5 Comment(0)
U
3

1.) you cannot use big border on parent -- in case you want to have a specific border

2.) you cannot add margin -- in case your parent is a part of some other container and you want your parent to take the full width of that grand parent.

The Only Solution that should be applicable is to wrap your children's in an another container so that your parent becomes the grandparent and then apply padding to the new children's Wrapper / Parent. Or you can directly apply padding to the children.

In your case:

.css-sux{
  padding: 0px 10px 10px 10px;
}
Unbuild answered 28/5, 2015 at 6:29 Comment(0)
B
3

Could have easily done using an extra level of Div.

<div style="background-color: blue; padding: 10px; position: relative; height: 100px;">
  <div style="position: absolute; left: 0px; right: 0px; bottom: 10px; padding:0px 10px;">
    <div style="background-color: gray;">css sux</div>
  </div>
</div>

Demo: https://jsfiddle.net/soxv3vr0/

Boyett answered 10/11, 2016 at 7:46 Comment(0)
M
3

I would set the child's width this way:

.child {position: absolute; width: calc(100% - padding);}

Padding, in the formula, is the sum of the left and right parent's padding. I admit it is probably not very elegant, but in my case, a div with the function of an overlay, it worked.

Murton answered 6/11, 2020 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.