Skip to content

Control size and spacing with the box model

You will control the width and spacing of the profile page with the CSS box model. You will also use DevTools to explain an element’s computed content, padding, border, and margin.

Every visible HTML element produces one or more boxes. A reliable box-model strategy helps you build layouts that remain readable when the content, viewport width, or text size changes.

What you will practice

  • Identify content, padding, border, and margin and explain the purpose of each layer.
  • Predict the rendered width of a box that uses content-box or border-box sizing.
  • Use percentages, rem, px, width, and max-width for different sizing jobs.
  • Explain how block and inline boxes participate in normal document flow.
  • Recognize margin collapse and diagnose clipping or overflow caused by fixed dimensions.
  • Use browser DevTools to inspect the computed box model and test temporary spacing changes.
  • New: The four box-model layers, box-sizing, normal flow, block and inline boxes, fluid and maximum widths, logical spacing properties, margin collapse, overflow, and the computed box-model view in DevTools.
  • Reused: The html-profile project, external CSS, element and class selectors, CSS declarations, browser reloading, and DevTools inspection.

Starting point

Before you start

  • The html-profile folder from the preceding CSS foundations lesson.
  • index.html and styles.css at the same folder level.
  • A profile page that already uses the supplied colors, typeface, heading styles, link style, footer border, and .project-entry class.
  • VS Code and a current version of Edge, Chrome, or Firefox.
Current state
The profile page has visual styles, but its content still uses browser-default margins and has no deliberate maximum width or internal spacing system.
First action
Open html-profile/styles.css and find the existing .project-entry rule.
First checkpoint
Each project entry has visible space between its content and its border, and visible space between one project entry and the next.
Help trigger
Use the recovery note or ask for help if a box becomes wider than the page, text is clipped, or DevTools does not show the padding, border, and margin values from styles.css.

You have completed the lesson when:

  • every element uses border-box sizing through one shared rule;
  • the browser’s default body margin is replaced with an intentional page-width rule;
  • header, main, and footer use a fluid width, a maximum width, and automatic inline margins;
  • sections, the current-focus aside, project entries, and the footer use deliberate margin or padding values;
  • project entries have visible content, padding, border, and margin layers;
  • no repeated br elements or empty HTML elements create visual space;
  • ordinary page text can grow vertically without a fixed height or hidden overflow; and
  • you can inspect one project entry in DevTools and identify its content, padding, border, margin, box-sizing, and computed width.

The browser creates a box when it lays out an element. The box model describes four nested layers of that box.

Box model structure

Four layers around an element

Read from the outside toward the center.

The layers always keep this order: content, padding, border, then margin. Each layer changes a different part of the element's size or spacing.

The same structure in text is:

  1. Content: The text, image, or nested elements. width and height control this area under the default sizing model.
  2. Padding: Space between the content and border. The element’s background is visible through the padding.
  3. Border: The visible boundary around the content and padding.
  4. Margin: Transparent space outside the border. Margin separates the element from nearby boxes.

Padding and margin both create space, but they do different jobs. Use padding when the space belongs inside an element’s boundary. Use margin when the space separates that element from another element.

Add all four layers to the project entries

Section titled “Add all four layers to the project entries”

In styles.css, replace the existing .project-entry rule with this version:

html-profile/styles.css — project entry box
/* Reusable project style */
.project-entry {
background-color: #ffffff;
border: 2px solid #9aa9b8;
margin-block: 1rem;
padding: 1.25rem;
}

The project text is the content. padding creates space inside the border. The border shows the element’s boundary. margin-block creates space before and after the article in the page’s block direction, which is top to bottom for this English page.

rem is relative to the root element’s font size. With a common browser default of 16px, 1rem computes to 16px, but a user’s font settings can change that relationship. Relative spacing can therefore respond to the text settings.

  1. Save styles.css and reload the page.
  2. Confirm that each project entry has a complete border on all four sides.
  3. Confirm that project text no longer touches the border.
  4. Confirm that a visible gap separates the two project entries.
  • If the old bottom border remains, confirm that you replaced the full .project-entry rule instead of adding a second incomplete version.
  • If only one project entry changes, confirm that both article elements still contain class="project-entry".
  • If the text touches the border, inspect the spelling of padding and confirm that its declaration is inside the .project-entry braces.

Checkpoint: Each project entry shows the four layers

What now works
Each project article contains text, internal padding, a complete border, and outside margin that separates it from the next article.
Files changed
html-profile/styles.css
What remains
Make width calculations predictable, constrain the page width, and add spacing to the larger page regions.
Next action
Go to the top of styles.css and add the shared box-sizing rule from the next section.
If it does not work
Inspect one project article and confirm that .project-entry supplies its border, margin-block, and padding declarations.

Normal flow is the browser’s default method for placing boxes when no layout system or positioned layout takes over. The profile page already uses normal flow: the page regions and text appear in source order from top to bottom.

Two common box behaviors matter here:

Box behavior Profile-page examples Default behavior
Block header, main, section, article, h2, p, and footer Starts on a new line and normally uses the available inline width. The next block box follows it.
Inline a and text inside a paragraph Participates in a line of text, fits its content, and can wrap with the text. A normal inline box does not take a declared width in the same way as a block box.

The HTML element still describes the content’s meaning. The CSS display value controls the box behavior. Changing a link to a block box would not change it into a section, and changing a section’s display would not remove its semantic purpose.

You do not need to change display in this lesson. The next lesson will introduce Flexbox when related boxes need a one-dimensional layout instead of normal block flow.

Most elements use box-sizing: content-box by default. Under this model, a declared width controls only the content area. Padding and border add to the rendered outer width.

Worked size comparison

The same width declaration can produce two outer widths

Both examples use width: 240px, padding: 24px, and a 4px border on every side.

content-box

The declared width controls the content area.

Calculation
240 + 48 + 8 = 296px
Included
240px content, 48px padding, and 8px border

border-box

The declared width controls the content, padding, and border together.

Calculation
240px total
Included
184px content, 48px padding, and 8px border
border-box keeps the declared outer width stable. Margin stays outside the width in both sizing models.

For the content-box example, the horizontal size is:

content-box width calculation
240px content
+ 24px left padding + 24px right padding
+ 4px left border + 4px right border
= 296px outer width

For the border-box example, the declared 240px already includes the content, padding, and border. The browser gives the content the remaining 184px.

Margin remains outside the declared width under both sizing models. Height calculations follow the same principle with top and bottom padding and borders.

Add this rule at the top of styles.css, before the body rule:

html-profile/styles.css — predictable sizing
/* Predictable sizing */
* {
box-sizing: border-box;
}

The universal selector * matches every element. The rule makes future width calculations include content, padding, and border. This lesson uses the universal selector for one shared sizing default; later CSS lessons will cover more selector patterns.

The rule might not create an obvious visual change yet because the project entries do not have a declared width. It changes how the browser will interpret the page-width rules in the next section.

  1. Save styles.css and reload the page.
  2. Inspect one project entry in DevTools.
  3. Find box-sizing in the Computed, Layout, or equivalent panel.
  4. Confirm that the computed value is border-box.
  • If DevTools shows content-box, confirm that the selector is * and the declaration is box-sizing: border-box;.
  • If the complete stylesheet stops applying after this edit, confirm that the rule has both braces and appears outside every other rule.

A long line of text becomes difficult to scan. The page can use the available width on a small viewport and stop growing when the viewport becomes wide.

First, add margin: 0; to the existing body rule. Use this complete rule so the earlier text and color settings stay intact:

html-profile/styles.css — page defaults
/* Page defaults */
body {
margin: 0;
color: #1f2937;
background-color: #f4f7fb;
font-family: Arial, sans-serif;
line-height: 1.6;
}

Browsers normally add a small default margin to body. Setting it to 0 removes that unknown outer space. The next rule provides the intentional page margins.

Add this rule after the body rule:

html-profile/styles.css — page width
/* Page width */
header,
main,
footer {
width: 90%;
max-width: 48rem;
margin-inline: auto;
}

The commas form a selector list. The browser applies the same declaration block to each named element.

Each value has a different job:

  • width: 90% lets each region use 90 percent of its containing block’s width. The remaining space prevents the content from touching a narrow viewport’s edges.
  • max-width: 48rem stops the regions from growing beyond a readable measure.
  • margin-inline: auto distributes the remaining inline space equally on both sides, so each block is centered. The inline direction runs from left to right on this English page.

The width can shrink below 48rem; the max-width only sets an upper limit. The element keeps its natural height, so its content can wrap and add more lines.

  1. Save and reload the page.
  2. Make the browser window narrow. Confirm that the three page regions remain inside the viewport and keep space on both sides.
  3. Make the window wide. Confirm that the content stops growing and remains centered.
  4. At 200% browser zoom, confirm that the page text wraps and remains visible.
  • If a region touches the viewport edge, confirm that it matches the header, main, footer selector list and that width is 90%.
  • If the regions stay on the left, confirm that margin-inline has the value auto and that the regions have a width smaller than their containing block.
  • If the page has horizontal scrolling, inspect the widest visible element and confirm that the universal border-box rule applies.

Checkpoint: The page width is fluid and limited

What now works
Header, main, and footer use 90 percent of the available width, stop at 48rem, and remain centered. Every inspected element uses border-box sizing.
Files changed
html-profile/styles.css
What remains
Add deliberate vertical spacing, account for collapsing margins, test overflow, and inspect computed dimensions.
Next action
Add the section, aside, and footer spacing rules from the next section.
If it does not work
Inspect header or main and confirm that width, max-width, margin-inline, and box-sizing all appear as active declarations.

Use CSS to control visual spacing. Keep the semantic HTML unchanged. Repeated br elements and empty elements do not describe content, and they make the spacing difficult to maintain.

Add these rules after the page-width rule:

html-profile/styles.css — region spacing
/* Region spacing */
section,
aside {
margin-block: 2rem;
}
aside {
border-inline-start: 0.25rem solid #1f4e79;
padding-inline-start: 1rem;
}
footer {
margin-block-start: 2rem;
padding-block: 1.5rem;
}

margin-block controls the outside space at the start and end of the block direction. padding-inline-start adds inside space between the aside’s left border and its content on this English page. These logical properties describe the writing direction instead of naming a physical side.

The existing footer border now has padding below and above its content. The footer’s top margin separates its border from the preceding page content.

Vertical margins of adjacent block boxes in normal flow can collapse. When the bottom margin of one box meets the top margin of the next box, the browser uses one combined margin instead of adding both positive margins together.

The new sections use margin-block: 2rem. When two sections are adjacent, the space between them is normally 2rem, not 4rem. If two positive adjoining margins differ, the larger margin normally determines the collapsed space.

This behavior applies to some vertical block margins in normal flow. Padding and borders do not collapse. Horizontal margins do not collapse. Flex and grid items also follow different margin behavior.

Do not add extra empty HTML to compensate for a margin that collapsed. Inspect the two boxes, then decide whether the space belongs inside one box as padding or between boxes as margin.

  1. Save and reload the page.
  2. Confirm that the main sections and current-focus aside have clear vertical separation.
  3. Confirm that the aside’s text has space after its left border.
  4. Confirm that the footer text has space inside the top border.
  5. Inspect the gap between two adjacent sections. Confirm in DevTools that each section has a 2rem block margin even though the visible gap is not 4rem.
  • If an aside border touches its text, confirm that padding-inline-start is on the aside rule, not the section, aside rule.
  • If the footer border disappears, keep the existing border-top declaration from the preceding lesson in the earlier footer rule.
  • If a gap is larger than expected, inspect both adjacent elements and identify every active margin before changing a value.

Overflow occurs when content does not fit inside the box dimensions available to it. The browser’s default visible overflow protects content from being silently clipped, but it can also reveal an unsuitable fixed size.

Run this temporary experiment in the .project-entry rule:

Temporary overflow experiment — remove after the test
.project-entry {
background-color: #ffffff;
border: 2px solid #9aa9b8;
height: 4rem;
margin-block: 1rem;
overflow: hidden;
padding: 1.25rem;
}

Save and reload. A project description can become partly or completely hidden because 4rem must contain the text, padding, and border. Zooming the browser or adding text makes the problem more severe.

Remove height: 4rem; and overflow: hidden;, then save and reload again. The project entries return to their content-based height, and all text remains visible.

overflow: auto can provide a scrollbar for a deliberately constrained region, such as a code sample. It is not a good default repair for ordinary article text. Let a text container grow unless the interface has a specific reason to constrain it.

  1. Confirm that you observed clipped content during the temporary experiment.
  2. Confirm that both temporary declarations are now removed.
  3. Reload at 200% zoom and confirm that each project entry grows to contain all of its text.
  • If nothing becomes clipped, temporarily reduce the height to 3rem or add one sentence to a project description. Remove the temporary change after the observation.
  • If text remains clipped after the test, search styles.css for height and overflow and remove the two temporary declarations from .project-entry.

Inspect the computed box model in DevTools

Section titled “Inspect the computed box model in DevTools”

DevTools can show the browser’s final used dimensions after it applies percentages, relative units, the cascade, and the sizing model.

  1. Reload the saved page.
  2. Right-click one project entry and select Inspect.
  3. Move to the selected article class="project-entry" in the element tree if DevTools selected a nested heading or paragraph.
  4. Open the Computed, Layout, or equivalent panel.
  5. Find the box-model diagram. Identify the values for content size, padding, border, and margin.
  6. Find box-sizing and confirm that its value is border-box.
  7. In the Styles or Rules panel, change padding: 1.25rem temporarily to padding: 2rem.
  8. Confirm that the content area becomes smaller while the article’s available outer width remains stable.
  9. Reload the page. The temporary DevTools edit disappears.
  10. Inspect main, resize the browser, and watch its computed width change until it reaches the 48rem maximum.

The exact panel name and displayed numbers depend on the browser and viewport width. The required evidence is the relationship: content sits inside padding, padding sits inside the border, margin remains outside, and border-box includes the first three parts in a declared width.

  • If the diagram shows zeros for padding or margin, confirm that DevTools selected the article rather than its child heading.
  • If a value appears crossed out, another declaration won in the cascade. Select the active declaration to identify its source file and line.
  • If a temporary DevTools change remains after reload, confirm that you did not also save the same value in styles.css.

Checkpoint: The computed box model matches the CSS

What now works
DevTools shows each project entry's content, padding, border, margin, border-box sizing, and computed width. Temporary DevTools edits disappear after reload.
Files changed
html-profile/styles.css
What remains
Complete the final checks and explain how the sizing and spacing rules produce the visible page.
Next action
Complete the self-check against the saved source and rendered page.
If it does not work
Select article.project-entry first, then inspect one layer or computed property at a time.

Self-check

Complete these checks against the required result.

  1. Point to one project entry and identify its content, padding, border, and margin in the rendered page.
  2. Confirm that the universal selector sets box-sizing to border-box for every inspected element.
  3. Explain why the 240px content-box example becomes 296px wide and why the border-box example remains 240px wide.
  4. Confirm that header, main, and footer use width: 90%, max-width: 48rem, and margin-inline: auto.
  5. Explain why the percentage, rem, and px values have different jobs in the page styles.
  6. Identify one block box and one inline box in the profile page and describe their normal-flow behavior.
  7. Confirm that sections, the current-focus aside, project entries, and footer have the required margin or padding.
  8. Explain why two adjoining 2rem vertical margins can produce a 2rem gap instead of a 4rem gap.
  9. Search index.html and confirm that no repeated br elements or empty elements create visual spacing.
  10. Search styles.css and confirm that .project-entry no longer contains the temporary height or overflow declarations.
  11. View the page in a narrow browser window and at 200% zoom. Confirm that all content remains visible and that the page has no unintended horizontal scrolling.
  12. Use DevTools to identify the computed content size, padding, border, margin, and box-sizing of one project entry.

The browser first places the profile page’s block and inline boxes in normal flow. It then resolves relative sizes against their containing blocks and font sizes. max-width limits the fluid page regions, and automatic inline margins center them.

For each box, the browser calculates the content area, adds padding and border according to box-sizing, and places margin outside the border. Some adjoining vertical block margins collapse. Content can increase the box’s height because the required styles do not force a fixed height.

This model provides a stable base for Flexbox. Flexbox will change how a container arranges its direct children, but every flex item still has the same content, padding, border, and margin layers.

After the required self-check passes, record the working state in the existing html-profile repository:

Commit and push the box-model work
git status
git diff
git add index.html styles.css
git diff --staged
git commit -m "Improve profile sizing and spacing"
git push

If index.html did not change, stage only styles.css. Reload GitHub and confirm that the newest commit contains no temporary overflow experiment.

The required lesson is complete when the profile page uses predictable sizing, fluid but limited page widths, deliberate spacing, and content-based heights, and when you can explain the computed box model in DevTools.

Continue to Arrange content with Flexbox to arrange related boxes along a row or column while preserving the box-model rules from this lesson.

If you stop here, leave yourself this resume note: The box model and page width are working. Next, open the Flexbox lesson and identify which direct children should become flex items.