CSS Basics and the Box Model Explained — Spacing, Sizing and Layout from Scratch
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 */ }
• All <p> text renders dark grey at 16px with comfortable line spacing.
• Any element with class="highlight-box" gets a yellow background and bold text.
• The element with id="page-title" appears large, navy, and centred.
• All <h2> and <h3> tags display a light grey underline.
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) */
• A white card, 300px wide, centred on the page.
• 20px of breathing room above and below the text, 24px on the sides (padding).
• A subtle 2px grey frame with rounded corners (border).
• 24px of gap below the card before the next element (margin).
• Because of border-box, the card stays exactly 300px — border doesn't bloat it.
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; }
• The notification banner has 16px top/bottom and 20px left/right of internal
breathing room — the blue background fills that space.
• 20px of empty (no background) space appears below the banner.
• The gap between .first-paragraph and .second-paragraph is exactly 40px,
not 64px — margin collapse in action.
• The button is comfortably sized from padding, with 12px of air to its right.
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>
• A white 320px card centred on a soft grey page.
• A solid blue strip across the top, with a green circle (avatar placeholder)
half-overlapping the strip using negative margin.
• Name in bold navy, job title in small blue caps, bio in readable grey text.
• A full-width blue Follow button at the bottom that darkens on hover.
• The card has a soft drop shadow, appearing to float above the page.
• Everything fits exactly — border-box prevents any dimension surprises.
| 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 |
🎯 Key Takeaways
- Every HTML element is a box made of four layers: content → padding → border → margin. Knowing which layer you're working with solves most layout bugs instantly.
- Always start your CSS with * { box-sizing: border-box; }. Without it, padding and border add to your declared width — creating mystery pixels that break layouts.
- Padding creates space inside an element (the background fills it); margin creates space outside (transparent, never coloured). Swapping them gives visually wrong results even when the spacing amount looks right.
- Vertical margins between block elements collapse to the larger value, not the sum. This doesn't happen in flex or grid containers, and never affects horizontal margins.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Forgetting box-sizing: border-box — Symptom: You set width: 300px and add padding: 20px, but the element renders at 340px, overflowing its container or breaking the layout. Fix: Add * { box-sizing: border-box; } at the very top of your stylesheet before writing any other CSS. This should be in every single project you ever create.
- ✕Mistake 2: Using margin to push content away from an element's own border — Symptom: You want space between text and the edge of a coloured box, so you add margin to the text element. The background colour doesn't extend into that gap, leaving a blank white strip instead of the intended padding. Fix: Use padding on the outer container element, not margin on the inner content. Padding lives inside the background; margin lives outside it.
- ✕Mistake 3: Being surprised by margin collapse — Symptom: You have two stacked divs, one with margin-bottom: 40px and one with margin-top: 30px. You expect 70px of space, but you measure only 40px. Fix: Remember that vertical margins between block siblings collapse to the larger value, not the sum. To intentionally add 70px of space, use padding on the parent element or apply the space only to one element (e.g., only use margin-bottom on the first div, leave the second with no top margin).
Interview Questions on This Topic
- QCan 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?
- QWhat 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.
- QIf 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
What is the CSS box model in simple terms?
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.
What does box-sizing: border-box actually do?
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.
When should I use padding vs margin?
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.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.