CSS Box Model — Why width: 100% Adds 64px Overflow
A button with width: 100% and padding rendered 64px wider than its container.
20+ years shipping production JavaScript and front-end systems at scale. Written from production experience, not tutorials.
- ✓Basic programming fundamentals
- ✓A computer with internet access
- ✓Willingness to follow along with examples
- The box model: every element is a rectangular box with content, padding, border, margin
- Default box-sizing is content-box: declared width excludes padding and border
- Border-box includes padding and border in width — the production standard
- Margin is outside (transparent), padding inside (background fills it)
- Vertical margins collapse to the larger value; horizontal margins never collapse
- Browser DevTools Computed tab shows the real box model in 2 seconds
The CSS Box Model is the fundamental layout system that governs how every HTML element renders on screen. Every element is a rectangular box composed of four concentric layers: content (the actual text or child elements), padding (inner space between content and border), border (the visible edge), and margin (outer space separating the element from neighbors).
When you set width: 100% on an element, that 100% applies only to the content area by default — padding, border, and margin are added on top, which is why a full-width container with 32px of padding and a 1px border on each side overflows its parent by 66px. This behavior is the single most common source of layout bugs in CSS, and it's why box-sizing: border-box exists: it makes width include padding and border, preventing overflow.
The box model isn't just theory — it's what you're debugging every time you open DevTools and see an element's computed dimensions differ from what you set. Alternatives like box-sizing: content-box (the default) or using to subtract padding manually exist, but in production, calc()border-box is the standard reset used by Bootstrap, Tailwind, and virtually every modern CSS framework because it makes layout math predictable.
Imagine every element on a webpage is a framed photo hanging on a wall. The photo itself is the content. The white space between the photo and the frame is the padding. The frame itself is the border. And the gap between this frame and the next one on the wall is the margin. CSS is simply the set of instructions you give the browser to style each of those framed photos — their size, colour, font, and spacing. Once you see it that way, CSS stops feeling random and starts feeling logical.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Every website you've ever visited — from Google's homepage to your favourite online shop — is built on three technologies working together: HTML for structure, JavaScript for behaviour, and CSS for visual appearance. CSS is what separates a wall of plain black text from a polished, professional interface. Without it, the web would look like a 1994 university library page. Understanding CSS isn't optional for anyone building for the web; it's the difference between shipping something people trust and something they immediately close.
The single biggest source of confusion for CSS beginners is spacing. Why is my button too big? Why is there a mysterious gap under my image? Why did adding a border break my layout? Almost every one of those questions has the same answer: you don't fully understand the CSS Box Model yet. The box model is the rulebook the browser uses to calculate how much space every element takes up on screen. Master it, and layout clicks into place.
By the end of this article you'll be able to write real CSS that styles text, sets colours and backgrounds, controls spacing with margin and padding, adds borders, and — most importantly — predict exactly how much space an element will occupy before you even open the browser. You'll also know the one property that most tutorials forget to mention, which trips up even experienced developers.
What CSS Actually Is — Selectors, Properties and Values
CSS stands for Cascading Style Sheets. Don't worry about the 'cascading' part yet — we'll get there. For now, think of CSS as a list of rules. Each rule says: 'Find these elements on the page, and make them look like this.'
Every CSS rule has three parts. A selector tells the browser which element to target. A property tells it what aspect to change (colour, size, font, etc). And a value tells it what to change it to. The syntax looks like this: selector { property: value; }. That's the entire grammar of CSS in one line.
You can write CSS in three places: directly in an HTML tag using the style attribute (called inline styles), inside a style tag in your HTML file (called internal styles), or in a completely separate .css file linked to your HTML (called external styles). For anything beyond a quick experiment, always use an external file. It keeps your HTML readable and lets you reuse styles across multiple pages without copying and pasting.
Selectors are how you aim. The three you'll use every day are the element selector (targets all tags of a type, like p or h1), the class selector (targets any element with a matching class attribute, written with a dot like .card), and the ID selector (targets one unique element, written with a hash like #main-header). Classes are the workhorse — use them constantly. IDs are for one-off unique elements.
/* ── Element selector ───────────────────────────────────────────────────── Targets every <p> tag on the page. 'color' sets the text colour. 'font-size' sets how big the text appears. */ p { color: #333333; /* Dark grey — easier on the eyes than pure black */ font-size: 16px; /* 16px is the browser default — we're being explicit */ line-height: 1.6; /* 1.6x the font size — makes reading comfortable */ } /* ── Class selector ─────────────────────────────────────────────────────── Targets any element that has class="highlight-box" in the HTML. A class can be reused on as many elements as you like. */ .highlight-box { background-color: #fffbcc; /* Pale yellow background */ color: #5a4a00; /* Dark warm text for contrast */ font-weight: bold; /* Makes the text thicker / heavier */ } /* ── ID selector ────────────────────────────────────────────────────────── Targets the ONE element with id="page-title" in the HTML. Use IDs sparingly — one per page per unique landmark. */ #page-title { font-size: 32px; color: #1a1a2e; /* Deep navy — feels professional */ text-align: center; /* Centre the heading horizontally */ } /* ── Combining selectors ────────────────────────────────────────────────── You can target multiple selectors at once by separating with a comma. Both h2 and h3 will get the same bottom border. */ h2, h3 { border-bottom: 2px solid #e0e0e0; /* Subtle dividing line below headings */ padding-bottom: 4px; /* Small gap between text and the line */ }
The CSS Box Model — The Four Layers Every Element Has
Here's the mental model that changes everything. Every single element on a webpage — a paragraph, a button, an image, a div — is a rectangular box. Even if it looks round or irregular, the browser is still treating it as a rectangle underneath. And every one of those boxes is built from four nested layers.
The innermost layer is the content — your actual text, image, or whatever is inside the element. Wrapping around the content is the padding — transparent space inside the element, between the content and the border. Think of it as interior cushioning. Next comes the border — an optionally visible line around the element. Finally, on the outside, is the margin — transparent space between this element and everything around it.
Here's the critical part that confuses almost everyone. By default, when you set width: 200px on an element, you're only setting the width of the content area. The browser then adds padding and border on top of that. So if you set width: 200px, padding: 20px and border: 5px, the element actually takes up 250px (200 + 20 left + 20 right + 5 left + 5 right). That unexpected size jump is the #1 source of broken layouts for beginners.
The fix is one line of CSS that every professional stylesheet starts with. We'll cover it in the code example below — and once you understand why it works, you'll never forget it.
/* ── THE FIX: Apply this at the top of every stylesheet you ever write ──── box-sizing: border-box tells the browser: when I say width: 200px, I mean the TOTAL width including padding and border — not just the content. The * selector targets every element on the page. ::before and ::after target pseudo-elements (generated content). */ *, *::before, *::after { box-sizing: border-box; /* The single most important CSS reset line */ } /* ── Demo: A product card ───────────────────────────────────────────────── Let's build a simple card to see every layer of the box model at work. */ .product-card { width: 300px; /* Total width = 300px (because of border-box) */ /* PADDING — space INSIDE the card, between content and border */ padding-top: 20px; padding-right: 24px; padding-bottom: 20px; padding-left: 24px; /* Shorthand for the line above: padding: 20px 24px; (top/bottom, left/right) */ /* BORDER — the visible frame around the card */ border: 2px solid #d0d0d0; /* 2px thick, solid line, light grey */ border-radius: 8px; /* Rounds the corners — doesn't affect box model */ /* MARGIN — space OUTSIDE the card, between it and other elements */ margin-bottom: 24px; /* Push the next card 24px below this one */ margin-left: auto; /* Auto left + right margin = horizontally centred */ margin-right: auto; /* Visual styling */ background-color: #ffffff; font-family: Arial, sans-serif; } .product-card__title { font-size: 20px; color: #1a1a2e; margin-top: 0; /* Remove default browser top margin on headings */ margin-bottom: 8px; } .product-card__price { font-size: 24px; font-weight: bold; color: #e63946; /* Red price — draws the eye */ margin: 0; } .product-card__description { font-size: 14px; color: #555555; line-height: 1.5; margin-top: 12px; margin-bottom: 0; } /* ── Padding shorthand reference ────────────────────────────────────────── padding: 20px; all four sides = 20px padding: 20px 24px; top & bottom = 20px, left & right = 24px padding: 10px 20px 30px; top=10, left&right=20, bottom=30 padding: 10px 20px 30px 40px; top, right, bottom, left (clockwise) */
Margin vs Padding — Knowing Which One to Use When
Margin and padding both create space, so beginners often swap them and wonder why things look slightly off. Here's a clear rule: padding is space inside the element; margin is space outside the element. The practical difference matters more than you'd think.
Background colour and border stop at the edge of padding. They don't extend into margin. So if your element has a background colour and you want the colour to extend further into the space around your text, you need more padding. If you want empty air between two separate elements, you need margin.
There's also a quirk called margin collapse that only affects top and bottom margins (never left/right). When two vertically stacked elements both have vertical margins, the browser doesn't add them together — it uses whichever is larger. So if one element has margin-bottom: 30px and the next has margin-top: 20px, the actual gap between them is 30px, not 50px. This is intentional (it makes typography spacing consistent) but it confuses everyone the first time they encounter it.
A practical rule for deciding which to use: if you're adding space between an element and its neighbours, use margin. If you're adding breathing room between an element's edge and its own content, use padding. Think of a button: the text-to-edge gap is padding, the gap between the button and other buttons is margin.
/* ── Demonstrating the visual difference between margin and padding ────── */ /* Reset so we start from a clean slate */ *, *::before, *::after { box-sizing: border-box; } /* A container with a background to make spacing visible */ .notification-banner { background-color: #e8f4fd; /* Light blue — clearly bounded area */ border: 1px solid #90caf9; border-radius: 6px; /* PADDING: space between the banner's edge and the text inside it. Remove this and the text will press right up against the border. */ padding: 16px 20px; /* MARGIN: space between this banner and whatever comes before/after it. The background colour does NOT extend into this space. */ margin-bottom: 20px; font-family: Arial, sans-serif; font-size: 15px; color: #1565c0; } /* ── Margin collapse in action ──────────────────────────────────────────── These two paragraphs are stacked vertically. p.first has margin-bottom: 40px. p.second has margin-top: 24px. The actual gap between them will be 40px — NOT 64px. The browser collapses them and keeps the larger value. */ p.first-paragraph { margin-bottom: 40px; /* This one wins — it's larger */ background-color: #fff3cd; padding: 8px 12px; } p.second-paragraph { margin-top: 24px; /* This gets collapsed/ignored — smaller value */ background-color: #d4edda; padding: 8px 12px; } /* ── Button spacing: padding for internal room, margin for external gap ─── */ .action-button { display: inline-block; background-color: #1a73e8; color: #ffffff; font-size: 15px; font-weight: bold; /* PADDING pushes the edges of the button away from the text */ padding: 12px 28px; /* MARGIN creates space between this button and a sibling button */ margin-right: 12px; border: none; border-radius: 4px; cursor: pointer; }
Debugging Box Model Issues in the Browser DevTools
The browser's Developer Tools are your best friend for diagnosing box model problems. No guessing, no trial-and-error. The Computed tab shows you exactly what the browser is using for every layer of the box.
Open DevTools (F12 on Windows/Linux, Cmd+Option+I on Mac), select an element, and go to the Computed tab. You'll see a visual diagram of the box model: content, padding, border, margin — all with exact pixel values. Hover over each section to see the dimensions breakdown.
Here's a common workflow: you notice an element is wider than you intended. Open Computed, look at the width value. If it's bigger than your CSS width, the extra is coming from padding or border being added on top. The solution is either to reduce padding/border or add box-sizing: border-box. The DevTools also show you which CSS rule sets each property — so you can trace it back to the source file and line number.
Another powerful trick: use the :hov button in the Styles panel to force element states like :hover or :focus. This lets you debug interactive states without having to keep hovering. Also use the 'Toggle Element State' feature to see how padding or margins change on hover.
/* No code for this section — it's about using DevTools. But here's a quick CSS snippet to test the box model visually. */ .debug-card { width: 200px; padding: 30px 20px; border: 10px solid red; margin: 50px auto; background: #e0e0e0; } /* After applying this, open DevTools → Computed tab → see that the total width is 200 + 20+20 + 10+10 = 260px. Changing box-sizing to border-box reduces it to 200px. */
Putting It All Together — A Real Styled Web Card
The best way to cement CSS basics and the box model is to build something real from scratch. No contrived examples — let's style an actual profile card you could drop into a real project today.
The HTML gives us the structure: a container div with a profile image, a name, a job title, and a short bio. The CSS then layers on typography, colour, spacing, and a subtle shadow using everything we've covered. Read each comment in the code carefully — there's intentional teaching in every property choice.
Pay attention to how margin: 0 auto centres the card horizontally. This works on block elements with a defined width. The auto value tells the browser to distribute remaining horizontal space equally on both sides — which centres the element. It's one of those CSS tricks that's been around since the early 2000s and still works perfectly today.
Also notice the use of a box-shadow. It isn't part of the box model — it doesn't affect layout at all. Box shadows are purely decorative and are drawn outside the element without changing its size or pushing anything around. That makes them safe to add to any element without worrying about breaking your layout.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Profile Card — CSS Box Model Demo</title> <style> /* ── Global reset ──────────────────────────────────────────────────── Always start here. Every professional project does this. */ *, *::before, *::after { box-sizing: border-box; margin: 0; /* Remove all default browser margins */ padding: 0; /* Remove all default browser padding */ } /* ── Page background ─────────────────────────────────────────────── */ body { background-color: #f0f2f5; /* Soft grey — makes white cards pop */ font-family: 'Segoe UI', Arial, sans-serif; display: flex; /* Center the card on the page */ justify-content: center; /* Horizontal centre in flex */ align-items: center; /* Vertical centre in flex */ min-height: 100vh; /* Full viewport height */ padding: 24px; /* Breathing room on small screens */ } /* ── The card itself ─────────────────────────────────────────────── */ .profile-card { background-color: #ffffff; width: 320px; /* Fixed width — border-box keeps it exact */ border-radius: 12px; /* Rounded corners — modern feel */ /* Box shadow: horizontal-offset vertical-offset blur spread colour This creates depth — the card appears to float above the page. Crucially, box-shadow does NOT affect the box model — it adds no size and pushes nothing around. */ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.10); overflow: hidden; /* Clips the avatar image to card edges */ } /* ── Coloured header strip at the top of the card ────────────────── */ .profile-card__header { background-color: #1a73e8; /* Brand blue */ height: 80px; /* Fixed height for the colour strip */ } /* ── Avatar: the circular profile photo ─────────────────────────── */ .profile-card__avatar { display: block; width: 80px; height: 80px; border-radius: 50%; /* 50% border-radius = perfect circle */ border: 4px solid #ffffff; /* White ring makes it stand out */ background-color: #4caf50; /* Placeholder — replace with <img> */ /* Pull the avatar up over the header strip using negative margin */ margin-top: -40px; /* Negative margin — overlaps the header */ margin-left: 24px; /* Align to left with breathing room */ } /* ── Card body: all the text content ─────────────────────────────── */ .profile-card__body { padding: 12px 24px 24px 24px; /* Less top padding — avatar took some space */ } .profile-card__name { font-size: 20px; font-weight: 700; /* Bold weight — 700 is standard bold */ color: #1a1a2e; margin-bottom: 4px; /* Tight gap before job title */ } .profile-card__job-title { font-size: 13px; font-weight: 500; color: #1a73e8; /* Blue — ties back to the header colour */ text-transform: uppercase; /* ALL CAPS for the job title */ letter-spacing: 0.05em; /* Slight spacing between letters */ margin-bottom: 16px; /* Bigger gap before bio paragraph */ } .profile-card__bio { font-size: 14px; color: #555555; line-height: 1.6; /* 1.6x line height = comfortable reading */ } /* ── Follow button ───────────────────────────────────────────────── */ .follow-button { display: block; /* Block so we can set width */ width: 100%; /* Full width of the card body */ margin-top: 20px; padding: 12px 0; /* Top/bottom padding — no left/right needed */ background-color: #1a73e8; color: #ffffff; font-size: 15px; font-weight: 600; text-align: center; border: none; border-radius: 8px; cursor: pointer; } /* Hover state — interactive feedback */ .follow-button:hover { background-color: #1558b0; /* Darker blue on hover */ } </style> </head> <body> <div class="profile-card"> <!-- Blue header strip --> <div class="profile-card__header"></div> <!-- Circular avatar (use an <img> tag in production) --> <div class="profile-card__avatar"></div> <!-- Text content --> <div class="profile-card__body"> <h2 class="profile-card__name">Sarah Chen</h2> <p class="profile-card__job-title">Senior Frontend Engineer</p> <p class="profile-card__bio"> Building fast, accessible web interfaces for over 8 years. Passionate about clean CSS architecture and performance. </p> <button class="follow-button">Follow</button> </div> </div> </body> </html>
The Box-Sizing Trap – Why Your Layout Breaks at 3 AM
You set a width of 400px, but the element spills out to 450px. That's box-sizing: content-box biting you. By default, CSS adds padding and border on top of your declared width. So width: 400px with 20px padding and 5px border? You get a real rendered width of 450px. The fix: box-sizing: border-box tells the browser to include padding and border inside the defined width. Now 400px means 400px no matter what padding you add. This single property change stops dozens of layout bugs. Apply it globally with the universal selector at the top of every stylesheet.
// io.thecodeforge // Apply border-box to all elements globally const style = document.createElement('style'); style.textContent = ` *, *::before, *::after { box-sizing: border-box; } `; document.head.appendChild(style); // Example: card won't overflow const card = document.querySelector('.card'); card.style.width = '400px'; card.style.padding = '20px'; card.style.border = '5px solid #333'; // In content-box: real width = 400 + 40 + 10 = 450px // In border-box: real width = 400px (padding+border inside) console.log(`Rendered card width: ${card.offsetWidth}px`); // Output: Rendered card width: 400px
Margin Collapse – The Silent Spacing Killer
Two stacked divs each with margin-bottom: 30px. You expect 60px gap. You get 30px. That's margin collapse: adjacent vertical margins combine into the larger value. It's not a bug — it's the CSS spec. But it will break your layout at 2 AM when you're shipping a feature. The mechanics: only vertical margins collapse (top/bottom), not horizontal. Only block-level elements collapse. Inline blocks, floats, and absolutely positioned elements don't collapse. To prevent it: use padding on the parent instead of margin on children, or add display: flow-root to the parent to create a new block formatting context.
// io.thecodeforge // Prevent collapse by creating a new BFC with display: flow-root const parent = document.createElement('div'); parent.style.display = 'flow-root'; parent.style.border = '1px solid red'; const child1 = document.createElement('div'); child1.style.marginBottom = '30px'; child1.textContent = 'First child'; const child2 = document.createElement('div'); child2.style.marginTop = '20px'; child2.textContent = 'Second child'; parent.append(child1, child2); document.body.appendChild(parent); // Without flow-root: margins collapse to max(30,20)=30px // With flow-root: separate BFC, total gap = 30+20 = 50px console.log(`Gap between children: ${ child2.offsetTop - (child1.offsetTop + child1.offsetHeight) }px`); // Output: Gap between children: 50px
The Mystery 20px Overflow That Broke a Checkout Page
- Always include box-sizing: border-box as a global reset in every project
- Never assume width means total width — check box-sizing first
- When an element overflows, the computed tab in DevTools confirms the box model instantly
Right-click element → Inspect → Computed tab (or press F12, then Ctrl+Shift+E in Firefox)Check if box-sizing is content-box or border-box. Look for padding adding to width* { box-sizing: border-box; } to CSS. Change width to max-width if parent constraint is the real issueIn first element: styles panel → check margin-bottom value. In second: margin-topRecognise collapse: if both values differ, the browser uses the larger one, not the sumIn DevTools, click the `+` button in Styles to add a new property: `padding: 12px 20px`Check if the button has a fixed width that becomes too tight after adding padding. If so, switch to `width: auto` or `box-sizing: border-box`padding: 0.75em 1.5em for responsive spacing| Aspect | padding | margin |
|---|---|---|
| Where it creates space | Inside the element, between content and border | Outside the element, between it and neighbours |
| Background colour fills it? | Yes — background extends into padding | No — margin is always transparent |
| Border extends into it? | No — border wraps around padding | No — border stops at padding's edge |
| Collapses vertically? | Never — padding never collapses | Yes — vertical margins collapse to the larger value |
| Use it when... | You want internal breathing room inside an element | You want space between separate elements |
| Affected by box-sizing? | Yes — border-box includes padding in total width | No — margin is always added outside the total width |
| Can be negative? | No — padding cannot be negative | Yes — negative margin pulls elements closer or overlaps them |
| Affects clickable area? | Yes — padding is part of the clickable element | No — clicking in a margin doesn't trigger the element |
| File | Command / Code | Purpose |
|---|---|---|
| styles.css | /* ── Element selector ───────────────────────────────────────────────────── | What CSS Actually Is |
| box-model-demo.css | /* ── THE FIX: Apply this at the top of every stylesheet you ever write ──── | The CSS Box Model |
| margin-vs-padding.css | /* ── Demonstrating the visual difference between margin and padding ────── */ | Margin vs Padding |
| debugging-devtools.css | /* No code for this section — it's about using DevTools. | Debugging Box Model Issues in the Browser DevTools |
| profile-card.html | Putting It All Together | |
| BoxSizingReset.js | const style = document.createElement('style'); | The Box-Sizing Trap – Why Your Layout Breaks at 3 AM |
| MarginCollapseFix.js | const parent = document.createElement('div'); | Margin Collapse – The Silent Spacing Killer |
Key takeaways
Common mistakes to avoid
3 patternsForgetting box-sizing: border-box
Using margin to push content away from an element's own border
Being surprised by margin collapse
Interview Questions on This Topic
Can you explain the CSS box model and describe what each layer — content, padding, border and margin — actually does? How does box-sizing: border-box change the calculation?
What is margin collapse? When does it happen and when doesn't it? Give me a concrete example of two elements where you'd expect the gaps to add up, but they don't.
If I set width: 500px, padding: 25px, and border: 5px on a div — what's the actual rendered width with the default box-sizing? What would it be with border-box applied? Walk me through the arithmetic.
Frequently Asked Questions
The CSS box model is the rule that every element on a webpage is a rectangular box made of four layers: the content in the middle, padding (space inside between content and the edge), a border (the visible frame), and margin (space outside between this element and others). The browser uses these four layers to calculate how much room every element takes up on screen.
By default, when you set width: 300px on an element, that 300px only covers the content area. The browser then adds padding and border on top, making the element larger than you specified. Setting box-sizing: border-box changes this so that your declared width includes padding and border — meaning width: 300px always means 300px total, period. This makes layout far more predictable.
Use padding when you want breathing room inside an element — between its content and its border. The background colour and border apply to the padding area. Use margin when you want space between two separate elements — it's always transparent and sits outside the element's background. A good test: if you want the gap to share the element's background colour, use padding. If you want empty air between two things, use margin.
Open your browser's Developer Tools (F12), inspect the problematic element, and go to the Computed tab. You'll see a visual box model diagram with exact pixel values for content, padding, border, and margin. This immediately shows you where the extra space is coming from — most often it's padding or border being added on top of a content-box width.
No. Margin collapse only affects vertical (top and bottom) margins between block-level siblings. Left and right margins never collapse. Also, margin collapse is disabled inside flex and grid containers, and when an element has its own new block formatting context (e.g., via overflow: hidden or floating).
20+ years shipping production JavaScript and front-end systems at scale. Written from production experience, not tutorials.
That's HTML & CSS. Mark it forged?
6 min read · try the examples if you haven't