252

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.

d512
  • 32,267
  • 28
  • 81
  • 107
  • 6
    Why not change the left/right/bottom of the inner div to `style="background-color: gray; position: absolute; left: 10px; right: 10px; bottom: 10px;"`? – j08691 Jun 14 '13 at 18:54
  • 22
    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. – d512 Jun 14 '13 at 19:07
  • 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. – rda3000 Oct 08 '13 at 21:56
  • Have a similar issue here: http://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... – rafiki_rafi Dec 12 '13 at 20:35

9 Answers9

281

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.

Community
  • 1
  • 1
Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • 2
    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. – trysis Jan 26 '16 at 17:05
  • 1
    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. – trysis Jan 26 '16 at 17:09
  • 2
    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 ... :P – NotaGuruAtAll Dec 18 '16 at 17:50
  • 1
    @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. – Kevin Christopher Henry Dec 18 '16 at 23:10
  • 1
    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. – Dylan Pierce Mar 07 '17 at 16:40
  • How did I make it this long without knowing the magic of `padding: inherit`?! Great suggestion @KevinChristopherHenry – sambecker May 16 '20 at 22:41
  • Excellent answer re: wrapping in another dev. I'm so glad I'm primarily a back-end dev... – Max Apr 07 '22 at 22:45
82

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.

Winter
  • 2,407
  • 1
  • 19
  • 28
  • 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. – Ogier Schelvis Aug 07 '17 at 07:10
  • 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. – Michael Gummelt Sep 26 '19 at 22:14
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).

NewSpender
  • 437
  • 4
  • 5
9

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

Niloct
  • 9,491
  • 3
  • 44
  • 57
  • Be aware that background (color) is not applied to margins like it is to padding – Paul Jan 15 '20 at 10:34
  • 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). – Marten Koetsier Sep 02 '21 at 20:06
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.

Touch
  • 1,481
  • 10
  • 19
  • 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. – d512 Jun 14 '13 at 19:11
  • 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. – Touch Jun 14 '13 at 19:18
  • 3
    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. – d512 Jun 14 '13 at 19:50
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;
}
bhavya_w
  • 9,186
  • 9
  • 29
  • 38
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/

asankasri
  • 476
  • 1
  • 6
  • 18
3

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>
Balaji
  • 9,657
  • 5
  • 47
  • 47
1

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.

Giga
  • 11
  • 2