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.