11

Consider the following jsfiddle for reference:

http://jsfiddle.net/apmmw2ma/

<div class='outer'>
    <div class='inner'>
        Inner.
    </div>
    Outer.
</div>
div.outer {
    position: absolute;
    left: 10px;
    top: 10px;
    border: 5px solid green;
    padding: 10px;
}
div.inner {
    position: absolute;
    left: 0;
    top: 100%;
    border: 10px solid red;
    padding: 15px;
}

As you can see, the “inner” box (with the red border) is positioned relative to the outer’s padding-box: left:0 positions it just to the right of outer’s border, and top:100% appears to mean “100% of the content plus padding, but not the border”.

Unfortunately, adding box-sizing: border-box to the outer div seems to have no effect.

I want to position a child element directly below its parent’s border-box, i.e. the two borders should abut no matter how thick they are. Is this possible?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Timwi
  • 65,159
  • 33
  • 165
  • 230
  • You could offset `inner` http://jsfiddle.net/apmmw2ma/1/ – David Alsbright Aug 18 '14 at 15:49
  • @DavidAlsbright: Thanks, but 1) the borders still overlap; I want the inner’s border-box to be *entirely below* the outer’s border-box; and 2) this requires that I know the thickness of the outer’s border. – Timwi Aug 18 '14 at 15:51
  • 1
    Are you able to make the divs siblings and just use [completely standard flow](http://jsfiddle.net/apmmw2ma/2/)? – Roman Starkov Aug 18 '14 at 15:52
  • 2
    Just curious, what is the use case for this. Why not just use a non-child div after the first div? – Paulie_D Aug 18 '14 at 15:53
  • No, it is not possible. They way `border-box` works it doesn't allow for it – Zach Saucier Aug 18 '14 at 15:53
  • In addition to David's comment, you can add top: calc(100% + 5px); to div.inner to make sure it goes entirely below it's parent. Without specifying a left / top value which corresponds with the border-width, I don't think your request is possible. I would suggest changing your HTML structure, if possible. – Leon Aug 18 '14 at 15:56
  • 2
    OK thanks for all of your feedback. Shame that it’s not possible. This seems like an oversight to me; the meaning of `top: x%` should really depend on the `box-sizing` value of the parent... – Timwi Aug 18 '14 at 15:58
  • @Timwi make a suggestion to the working group :-) – TylerH Aug 18 '14 at 16:01
  • @TylerH: Too late, changing it now would be a breaking change. The time to define this would have been when `box-sizing` was introduced. – Timwi Aug 18 '14 at 16:04
  • I've tried many methods with css and html alone and it's hard without js. Sadly, it is impossible to size the inner box outside relative to the outer box since calc() has limitations unless you use js/javascript it is assured possible. – Mike Ante Aug 18 '14 at 16:22
  • @Timwi I disagree; if it's a fix, tell people. If they don't update code as needed, the onus is on them. It is a living standard after all. – TylerH Aug 18 '14 at 17:21
  • @TylerH: It is not entirely clear-cut that it’s a “fix”. Also, I wasn’t so much expressing my opinion on whether breaking changes are desirable, but rather I believe that the suggestion would not be taken seriously from the start because it would be a breaking change without being a clear-cut “fix” to a known “problem”. – Timwi Aug 22 '14 at 14:32
  • Please have a look at my solution below. – gopalraju Jun 19 '15 at 05:51

4 Answers4

5

Unfortunately this is not possible without knowing the border widths in advance. If you don't know the border widths in advance, or if they are dynamic, then you're out of luck.1

The area of an element's containing block is indeed defined as the padding edge of the element forming the containing block. This is explicitly stated in the spec, and is by design; descendants aren't normally supposed to overflow the border of their container, unless the container has overflow: visible and does not establish a BFC (and even then, the effect is only visual; it doesn't affect layout). Otherwise, the border isn't much of a border anymore.

Generally, if you want to lay out elements such that they interact by their border or outer edges, you don't want to lay them out as ancestors and descendants. At the very least you want them to be siblings2, otherwise they should be completely unrelated.

This seems like an oversight to me; the meaning of top: x% should really depend on the box-sizing value of the parent...

The purpose of box-sizing is to change how the size of a box is calculated (i.e. whether or not the padding or the borders should add to the dimensions specified by width and height); while you can use it to alter the size of an element's padding box, the area of the containing block, if the element generates one, is still defined by that padding box.


1 This could conceivably be solved with custom properties, but on the precondition that you must assign the same custom property to both the parent's border-width and to the child's respective offsets, which is basically another way of saying "you must know the border widths in advance" or at least, have control over them.

2 Floats, for example, are highly predisposed to the border edge of boxes, so much so that they can appear to collapse margins in places where you normally wouldn't expect it to occur.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
0

Unfortunately it is not possible to do this without repeating the value of the parent’s border width.

However, if repeating the border width value is acceptable, the following solution works:

div.inner {
    top: <desired top value, e.g. 100%>;
    margin-top: <parent’s border-bottom-width>;
    left: <desired left value, e.g. 0>;
    margin-left: -<parent’s border-left-width>;
}

In the future, the same will be possible with calc(), which at the time of this writing is not widely enough supported:

div.inner {
    top: calc(<desired top value, e.g. 100%> + <parent’s border-bottom-width>);
    left: calc(<desired left value, e.g. 0> - <parent’s border-left-width>);
}

If I may dream for the future, I would like to be able to refer to the property values of the parents/ancestors inside a calc() expression. Then I could write something like:

/* Hypothetical code that will never work */
div.inner {
    top: calc(100% + parent.border-bottom-width);
    left: calc(0 - parent.border-left-width);
}
Timwi
  • 65,159
  • 33
  • 165
  • 230
  • 1
    I'm not sure how calc() isn't widely supported now. IE9+ and all other major browsers support it and have supported it for a while now. Caniuse even has support listed at over 75% (even for unprefixed used). If you're just referring to mobile support (where it is currently supported on all major browsers), that might be appropriate to clarify. – TylerH Aug 18 '14 at 17:25
0

Use box-shadow

This makes use of the box-sizing model the way you expect:

http://jsfiddle.net/apmmw2ma/6/

-webkit-box-shadow:inset 0px 0px 0px 5px green;
-moz-box-shadow:inset 0px 0px 0px 5px green;
box-shadow:inset 0px 0px 0px 5px green;

box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
Alain Jacomet Forte
  • 4,575
  • 6
  • 29
  • 41
0

Try using display:table; for the outer div.

Fiddle: http://jsfiddle.net/apmmw2ma/9/

gopalraju
  • 2,299
  • 1
  • 12
  • 15