The CSS Podcast - 001: The Box Model
Say you have this bit of HTML:
<p>I am a paragraph of text that has a few words in it.</p>
Then you write this CSS for it:
p {
width: 100px;
height: 50px;
padding: 20px;
border: 1px solid;
}
The content ends up 142px wide, instead of the 100px you specified, and it breaks out of your element. Why is that?
The box model is a core foundation of CSS. Understanding how the box model works, how it's affected by other aspects of CSS, and importantly, how you can control it, can help you write more predictable CSS.
It's important to remember that everything displayed by CSS is a box, even if
it's just some text, or has a border-radius
that makes it look like a circle.
Content and sizing
Boxes have different behavior based on their display
value, their set
dimensions, and the content they contain. This content could be plain text, or
more boxes generated by child elements. Either way, the content affects the size
of the box by default.
You can control this using extrinsic sizing, or you can use intrinsic sizing to let the browser make decisions for you based on the content size.
Here's a basic demo that explains the difference:
The demo has the words "CSS is awesome" in a box with fixed dimensions and a
thick border. Because the box has a specified width, it's extrinsically sized.
This means it controls the sizing of its child content. However, the word
"awesome" is too large for the box, so it overflows outside the parent box's
border box (more on this later). One way to prevent this overflow is to let
the box be intrinsically sized by either not setting the width, or in this case,
setting the width
to min-content
. The min-content
keyword tells the box to
be only as wide as the intrinsic minimum width of its content (the word
"awesome"). This lets the box fit perfectly around the text.
Here's a more complex example that shows the impact of different sizing on real content:
Toggle intrinsic sizing on and off to see how extrinsic sizing gives you more control with extrinsic sizing and intrinsic sizing gives the content more control. To see the effects add a few sentences of text to the card. When this element has extrinsic sizing, there's a limit to how much content you can add before it overflows, but that doesn't happen when intrinsic sizing is toggled on.
By default, this element has a set width
and height
of 400px
each.
These dimensions give strict bounds to everything inside the element, which are
honored unless the content is too large for the box. You can see this in action
by changing the caption under the flower picture to something that exceeds the
height of the box.
Key term: Overflow happens when content is too big for the box it's in. You can
manage how an element handles overflow content using the overflow
property.
Switching to intrinsic sizing lets the browser make decisions for you based on the box's content size. This makes overflow much less likely because the box resizes with its content.
It's important to remember that intrinsic sizing is the browser's default behavior, and it usually provides much more flexibility than extrinsic sizing.
The areas of the box model
Boxes are made up of distinct box model areas that all do a specific job.
The content box is the area that the content lives in. The content can control the size of its parent, so this is usually the most variably sized area.
The padding box surrounds the content box and is the space created by
the padding
property.
Because padding is inside the box, the box's background is visible in the space
it creates.
If the box has overflow rules set, such as overflow: auto
or
overflow: scroll
, the scrollbars also occupy this space.
The border box surrounds the padding box, and its space is defined by the
border
value, which
creates a visual frame for the element. The element's border edge is the
limit of what you can see.
The final area, the margin box, is the space around your box, defined by the
box's margin
rule. Properties such as
outline
and
box-shadow
occupy this space too because they're painted on top of the element and don't
affect the size of the box. Changing your box's outline-width
of 200px
on
a box doesn't change anything inside the border edge.
A useful analogy
The box model is complex to understand, so here's an analogy for what you've learned so far.
In this diagram, you have three picture frames mounted next to each other on a wall. Elements of the framed image correspond to the box model as follows:
- The content box is the artwork.
- The padding box is the white mounting board, between the frame and the artwork.
- The border box is the frame, providing a literal border for the artwork.
- The margin box is the space between frames.
- The shadow occupies the same space as the margin box.
Debug the box model
Browser DevTools provide a visualisation of a selected box's box model calculations, which can help you understand how the box model works and how it affects the website you're working on.
Try this in your own browser:
- Open DevTools.
- Select an element.
- Show the box model debugger.
Control the box model
To understand how to control the box model, you first need to understand what happens in your browser.
Every browser applies a user agent style sheet to HTML documents that defines how elements should look and behave if they don't have defined CSS. The CSS in user agent style sheets varies between browsers, but they provide sensible defaults to make content easier to read.
One property the user agent style sheet sets a box's default display
. For
example, in a normal flow, a <div>
element's default display
value is
block
, a <li>
has a default display
value of list-item
, and a <span>
has a default display
value of inline
.
An inline
element has a block margin, but other elements don't respect it.
With inline-block
, other elements respect the block margin, but the first
element keeps most of the same behaviors it had as an inline
element.
A block
item fills the available inline space by default, whereas
inline
and inline-block
elements are only as large as their content.
The user agent style sheet also sets box-sizing
, which tells a box how to
calculate its box size. By default, all elements have the following user agent
style: box-sizing: content-box;
. This means that when you set dimensions such
as width
and height
, those dimensions apply to the content box. If you
then set padding
and border
, these values are added to the content box's
size.
Check your understanding
Test your knowledge of box model size impacting properties.
.my-box { width: 200px; border: 10px solid; padding: 20px; }
How wide do you think .my-box
will be?
200px
would be correct if the
box had box-sizing: border-box
.
The actual width of this box is 260px.
Because the CSS uses the default box-sizing: content-box
, the applied width is
the width of the content, and padding
and border
on both sides are added to
that. 200px for the content + 40px of padding + 20px of border makes a total
visible width of 260px.
You can change this by specifying border-box
sizing:
.my-box {
box-sizing: border-box;
width: 200px;
border: 10px solid;
padding: 20px;
}
This alternative box model tells CSS to apply the width
to the border box
instead of the content box. This means our border
and padding
get
pushed in, so when you set .my-box
to be 200px
wide, it actually renders
at 200px
wide.
Check out how this works in the following interactive demo. When you toggle the
box-sizing
value, the blue area shows which CSS is being applied inside the
box.
*,
*::before,
*::after {
box-sizing: border-box;
}
This CSS rule selects every element in the document
and every ::before
and ::after
pseudo element and applies box-sizing: border-box
.
This means that every element now uses this alternative box model.
Because the alternative box model can be more predictable, developers often add this rule to resets and normalizers, like this one.