Day 13: CSS Fundamentals & The Box Model
You’ve built a clean, semantic, validated HTML page. You’ve embedded media, wired up forms, and ensured it’s accessible. But let’s be honest: raw HTML is pretty boring to look at. It’s the skeleton; now we need to dress it up.
CSS (Cascading Style Sheets) has a reputation for being “magic” or “arbitrary” because it doesn’t follow the rigid logic you’re used to in HTML. But it’s not magic. It’s applied visual math with strict rules. Once you understand those rules, CSS stops being a guessing game and becomes a precise tool for design.
In this post, we’re going to take your Day 12 HTML project and turn it into a visually polished page. We’ll link stylesheets, learn how to target elements, master the “Cascade” (the C in CSS), and tackle the Box Model—the single most important concept in layout. We’re keeping this focused on the foundation. Flexbox, Grid, and animations come later. Today, we build the bedrock.
🎯 What You’ll Learn Today
By the end of this post, you will:
- Link an external stylesheet and understand how browsers apply rules top-to-bottom
- Write valid CSS syntax and target elements using element, class, and ID selectors
- Predict and resolve specificity conflicts using the browser’s DevTools
- Visualize the CSS Box Model (content → padding → border → margin) and switch to
box-sizing: border-box - Use
removerpxfor scalable, accessible typography - Verify styles and computed dimensions using DevTools
Phase 1: Linking & Syntax (The Baseline)
There are three ways to add CSS: inline (style="..."), embedded (<style> in the head), or external (<link>). In professional development, external is the only standard. It separates structure from style, allows caching (faster loads), and keeps your code maintainable.
Let’s create your stylesheet. In your html-project folder (from Day 12), create a new file named style.css. Then, inside the <head> of your index.html, add this line:
<link rel="stylesheet" href="style.css">
Code language: HTML, XML (xml)
Syntax Basics: A CSS rule consists of a selector (who you’re targeting) and a declaration block (what you’re changing).
selector {
property: value;
}
Code language: CSS (css)
🔹 Micro-Exercise 1: Connect & Experiment Open style.css and add this baseline rule:
body {
background-color: #f8f9fa;
font-family: system-ui, -apple-system, sans-serif;
color: #212529;
}
Code language: CSS (css)
Save and refresh index.html. You should see the background shift to a soft gray. Now, let’s experiment directly in the code.
body {
background-color: #f8f9fa; /* 💡 Experiment: Change this to #e9ecef or #000000. Refresh. See how the mood shifts? */
/* ... keep other properties ... */
}
Code language: CSS (css)
Open DevTools (F12), go to the Elements tab, click <body>, and look at the Styles pane. You’ll see your rule listed as style.css:1. This is your command center. If a rule isn’t here, the browser didn’t load it.
Phase 2: Selectors & The Cascade (Targeting & Conflicts)
To style specific parts of your HTML, you need selectors. The three you’ll use 90% of the time are:
- Element:
h1,p(affects all instances of that tag) - Class:
.post,.btn(reusable; the industry standard) - ID:
#header(unique per page; high “power” or specificity)
The browser applies rules top-to-bottom. If two rules conflict, the one with higher Specificity wins. The hierarchy is: #id > .class > element.
🔹 Micro-Exercise 2: Create Intentional Conflict Add this HTML inside your <main> tag (if it’s not already there):
<article class="post">
<h2>Why CSS Works Differently</h2>
<p class="intro">CSS isn't magic. It's applied math.</p>
</article>
Code language: HTML, XML (xml)
Now, add these rules to style.css:
.post {
color: #0d6efd; /* Blue text */
border: 1px solid #ddd;
padding: 1.5rem;
}
.intro {
color: #212529; /* Dark text */
font-weight: 500;
}
Code language: CSS (css)
Refresh. The paragraph is dark gray. But what if we wanted to force it blue using a more powerful selector? Uncomment the line below and predict what will happen:
/* ⚠️ Hint: Which rule wins? Check DevTools → Styles pane.
Look for the rule that gets "crossed out" (strikethrough).
That's the browser rejecting it in favor of the winner. */
/* #main .intro { color: #0d6efd; } */
Code language: JSON / JSON with Comments (json)
Observation: You’ll see #main .intro overrides .intro. That’s specificity in action. If two rules have equal specificity (like .post vs .intro), the last one written wins. This is the “Cascade.”
Phase 3: The Box Model (The Invisible Math)
This is where 80% of beginner frustration happens. Every single HTML element is a rectangular box. Even circles are square boxes with rounded corners.
From the inside out, a box consists of:1. Content: The text or image. 2. Padding: Transparent space inside the border. 3. Border: The visible line around the padding. 4. Margin: Transparent space outside the border, pushing neighbors away.
Here’s the trap: by default, CSS uses content-box sizing. This means if you set width: 300px, that width applies only to the content. Padding and border are added on top.
🔹 Micro-Exercise 3: The “Break & Investigate” Pattern Update your .post rule in style.css:
.post {
width: 300px;
padding: 30px;
border: 5px solid #333;
margin: 20px auto; /* 'auto' centers the block */
background: white;
}
Code language: CSS (css)
Refresh. It looks like a card. But check the size.
/* 🔍 Hint: In DevTools, click the .post element. Go to the 'Computed' tab.
Look at the box diagram at the bottom right.
Why does it say the total width is 370px when we wrote width: 300px?
Where did the extra 70px come from? */
Code language: JSON / JSON with Comments (json)
The Answer: 300px (content) + 60px (30px left/right padding) + 10px (5px left/right border) = 370px. This breaks layouts constantly.
The Fix: Change width to include the padding and border.
.post {
box-sizing: border-box; /* 🎉 The fix! */
/* ... rest of your code ... */
}
Code language: CSS (css)
Now check the Computed tab again. The width is exactly 300px. The padding and border are squeezed inside the box. Professional tip: Almost every project starts with *, *::before, *::after { box-sizing: border-box; } to make this the default for everything.
Phase 4: Units & Accessibility (px vs rem)
When defining sizes, you have choices. The two most common are px (pixels) and rem (root em).
px: Fixed absolute unit. 16px is always 16px.rem: Relative to the root (<html>) font size. Default is usually 16px.
Why does this matter? Accessibility. Users can change their browser’s default font size for readability. px ignores this preference. rem respects it.
🔹 Micro-Exercise 4: Scale Responsibly Add these rules to style.css:
html { font-size: 100%; } /* Resets to browser default */
h2 { font-size: 1.5rem; } /* 1.5 * 16px = 24px */p { font-size: 1rem; line-height: 1.6; } /* 16px with relaxed spacing */
Code language: CSS (css)
Now, try this experiment:
/* 🔍 Hint: In Chrome, go to Settings (⋮) → Appearance → Font Size → Very Large (24px).
Refresh your page. Watch how 'rem' scales up proportionally.
Change '1.5rem' in h2 to '24px' and refresh again.
Notice how the pixel-based heading stays small while the page gets huge? */
Code language: JSON / JSON with Comments (json)
This is why modern CSS uses rem for almost all typography and spacing. It ensures your site is readable for everyone.
Beginner Pitfalls & Quick Fixes
- Missing closing braces
}: Silently breaks every rule after it. → Fix: Use a formatter (like Prettier) or watch DevTools for “dropped” properties. - Specificity Wars: Using
#idfor styling causes conflicts later. → Fix: Use.classfor styling. Save#idfor JavaScript hooks. - Inline Styles:
<h1 style="color:red">is impossible to override with external CSS. → Fix: Never use in production. - Margin Collapse: Vertical margins of adjacent elements merge (the larger one wins). → Fix: Use
paddingon the parent ordisplay: flow-root(we’ll cover this in Layout Week). - Debug Tip: In DevTools → Styles pane, if you see a property crossed out, hover over it to see which rule is overriding it.
Synthesis Exercise: Build a Styled Card Component
Let’s combine everything into a clean, professional component. Keep style.css open and apply this global reset at the very top:
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
Code language: CSS (css)
Now, refine your .post card:
.post {
max-width: 700px; /* Prevents it from getting too wide on large screens */
margin: 2rem auto;
padding: 2rem;
background: white;
border-radius: 8px; /* Rounds the corners */
box-shadow: 0 4px 6px rgba(0,0,0,0.1); /* Adds subtle depth */
border: 1px solid #e2e8f0;
}
.post:hover {
transform: translateY(-2px);
box-shadow: 0 8px 12px rgba(0,0,0,0.15);
}
/* ⚠️ Hint: Try changing translateY(-2px) to translateY(-10px).
Does it feel too floaty? CSS is iterative. Dial it back until it feels "right." */
Code language: CSS (css)
Final Verification Checklist:
- Open DevTools → Elements → select
.post. - Check Styles: Are all your rules active?3. Check Computed: Is the box model width correct? (e.g., if
max-widthis 700px, computed should be 700px). - Accessibility: Change browser font size to “Very Large”. Does the text scale? Do the boxes break?
Key Takeaways
- External CSS is the standard. The browser reads rules top-to-bottom.
- Specificity Hierarchy:
#idbeats.classbeatselement. Equal specificity = last one wins. - Box Model: Content + Padding + Border + Margin. Always use
box-sizing: border-boxto make math predictable. - Units: Prefer
remfor typography to respect user accessibility settings. - DevTools: The Styles pane shows you exactly what’s active, what’s overridden, and why.
What’s Next
In the next post, we’ll dive into Typography, Colors & Backgrounds. You’ll learn how to import custom fonts, manage color systems effectively, create gradients, and ensure your text passes contrast checks for accessibility.
Preview question: If you want to apply a gradient background that fades from blue to white, what CSS property and function would you use? Jot down your guess. We’ll cover it next.
← Day 12: HTML Project — Build Semantic Static Webpage | Day 13 | Day 14: Typography, Colors & Backgrounds →





Leave a Reply