Understanding Reference Boxes for CSS Shapes
CSS Shapes are used to wrap content around custom paths. The paths are defined with shape function values, like
polygon(), and they are positioned within a virtual box, the reference box.
A reference box defines the shape's coordinate system, so it influences how the shape will be drawn and positioned. There are four reference boxes to choose from:
content-box. Each of them yields subtly different results. Read on to learn how they work.
We'll consider a simple circle shape around which we will wrap content. We'll use percentages for the circle radius to observe how reference boxes influence the resulting shape.
If unspecified, the default reference box for a shape is
margin-box. The CSS shape declaration above is equivalent to
shape-outside: circle(50%) margin-box;.
margin-box reference box means that a shape is positioned in a virtual box defined by the outer edges of the host element's margin. The origin of the coordinate system is at the upper-left corner of this box, with the X axis going from left to right and the Y axis going from top to bottom.
We didn't specify a margin in our sample yet, so the
margin-box reference box does not extend beyond the element's content area. It's still ok to imagine the origin of the coordinate system for the shape placed at the upper-left corner of the element.
At this point, the circle's 50% radius yields an actual length of 50px (half the element's width or height).
The shape changes when we do specify a margin.
margin: 50px, the
margin-box reference box extends around the element by 50px in all directions. It builds on the element's dimensions, so the reference box becomes 200px by 200px.
The circle's 50% radius now yields an actual length of 100px and the origin is outside the element’s content area, at the upper left corner of the box defined by the margin.
We use the
margin-box reference box when it's important to wrap content around a shape which stretches beyond the dimensions of the host element.
Margins and shapes
It's very important to understand that all reference boxes define coordinate systems for shapes, but only the
margin-box actually clips the shape. This means that shapes larger than other reference boxes will eventually be clipped by the
margin-box. Therefore, an element's margin can be used to increase the surface where the shape will draw, if it extends beyond other reference boxes.
As its name implies, the
border-box reference box constrains the shape's coordinate system to the box defined by the outer edges of the element's border. In this case, the shape may overlap the element's border, and can extend beyond it if there is a margin around the element.
border: 25px solid yellow;
shape-outside: circle(50%) border-box;
After applying a thick 25px solid border, which, by default, grows the element in all directions, the reference box will be 150px by 150px, (width + 2 * 25px) by (height + 2 * 25px), and the circle's 50% radius yields 75px.
However, if we use
box-sizing: border-box (note the different property), a different algorithm for computing the box model applies and the border value is subtracted from the element's dimensions in such a way that the element's overall size does not change, but its surface for inner content is reduced. In that case, the reference-box ends up being 100px by 100px.
border-box reference box helps keep the shape synchornized with the position of the element if margins are used.
We use the
border-box reference box when it's necessary for the shape to overlap the element's border and keep in sync with the border if that changes.
padding-box reference box constrains the shape's coordinate system to the box defined by the outer edges of the element's padding.
Let's use the
padding-box reference box and specify a padding.
shape-outside: circle(50%) padding-box;
padding: 25px the element grows by 25px in all directions. This effect occurs only if the element's
box-sizing property value remains unchanged from the browser's default of
In this scenario, the reference box becomes 150px by 150px, (width + 2 * 25px) by (height + 2 * 25px). The circle's 50% radius now means 75px, and the coordinate system origin is at the upper left corner of the box defined by the padding.
If we use
box-sizing: border-box, this makes the browser subtract the necessary space for the padding from the element's dimensions, thus reducing the surface for inner content. In this scenario, the reference box becomes 100px by 100px and the circle's 50% radius yields 50px.
In both scenarios, the margin property can be used to adjust the position of the element together with its shape.
We use the
padding-box reference box when it's necessary for wrapped content to overlap part of the host element.
content-box reference box constrains the shape's coordinate system to the available space for content within the element.
It is common for at least one of the element's dimension to not be explicitly defined, for example
width may be set, but
height may be derived from the amount of content. This causes the reference box and the resulting shape to be directly influenced by the element's content.
Let's look at two examples with
content-box reference box.
shape-outside: circle(50%) content-box;
When both dimensions are explicitly set it is predictable what the reference box will be: the box defined by the width and height properties. Even though padding and border may grow the element's perceived size, the reference box remains tied to the initial dimensions.
box-sizing: border-box will, of course, subtract padding and border from those dimensions and the reference box will be identical to the surface that's left available. If the subtraction causes the remaining surface to be zero or negative, there will be no visible shape because there is nowhere to draw it.
That was the predictable case. However, if one of the dimensions isn't defined, the reference box can vary wildly according to other constraints.
shape-outside: circle(50%) content-box;
/* height: 100px; */
Notice that we commented-out the explicit
height property. Now, the
content-box reference box depends on the amount of content within the element with the "shape" class. Different
font-size values or relative size units will also have an impact on the reference box.
Variable dimension reference boxes
For simplicity's sake, in the examples so far, we used dimensions that get us a a square element. In those cases the circle's radius would equate to half the square's edge.
However, computing radii as percentage units for
ellipse() depends on a slightly more complicated formula: sqrt(width2 +height2)/sqrt(2). This is a special case only for
ellips() radii; other shape functions, like
polygon(), are not constrained by this.
Understanding this formula becomes important for mentally visualizing the
content-box reference box when the amount of content can influence one or both dimensions. It's worth noting that this case of variable dimension applies with the other reference boxes as well, it's not endemic to
In the illustration above we observe that the circle does not touch the content-box top and bottom edges yet it extends beyond its left and right edges. This is expected and happens because of two reasons: 1) the radius is computed out of the element dimensions with the formula mentioned above, and 2) we omitted defining where the circle's center should be, so the default was used — the center of the coordinate system (the intersection of the element's diagonals in this case).
At first glance, it looks like the
content-box reference box is too much of a hassle to be worthwhile. However, there is a valid use case: progressive shape disclosure. This means we can create a shape which is much larger than what's immediately needed or visible, but as the amount of content increases more of the shape gets revealed.
polygon() to create a saw-like shape which runs down along the side of the element. CSS Shapes do not yet have a "repeat" property. Using progressive shape disclosure with the
content-box reference box is a way to achieve the same effect using larger shapes composed of a repeated pattern.
margin-box does the actual clipping of oversized shapes. If there is a margin around the element, the shape may extend beyond the
content-box, only to be clipped by the
Creating shapes from reference boxes
It is possible to skip the shape function definition and to infer the shape from the element's reference box. This is particularly useful when
border-radius is used, because that property can influence the shape of the reference box.
border-radius on its own does clip the element, but it does not affect the float area around it — that remains rectangular. Adding
shape-outside: margin-box; (notice, no shape function), the float area around the element respects the shape from
To a great extent, all reference boxes work as previously defined in conjunction with border radii, but there are special cases to consider.
Skipping shape functions and inferring shape from the reference box may come useful when the element is already clipped with
border-radius and duplication of the shape isn't necessary.
Creating shapes with
border-radius sounds deceptively simple, maybe even trivial, but Lea Verou does an excellent job explaining the property's underlying expressive power in her talk, "The Humble Border-Radius".
The table below provides a quick reference on how to compute reference boxes.
|width + height
|width + height
|width + height + padding
|width + height - padding
|width + height + padding + border
|width + height - padding - border
|width + height + padding + border + margin
|width + height - padding - border + margin
Reference boxes help us control the sizing and positioning of CSS Shapes.
They abstract away some of the complexity of coordinate systems and free us from having to manually define dimensions for each element. This contributes to making responsive shapes which are portable both across screens and between projects.Find out why.
This website does not track you.