Back to Blog

Basic CSS Crash Course: Building a Styled Page from a Wireframe

|

HTML defines a page's structure and content. CSS styles that structure. The fastest way to see how they work together is to build something end to end: a wireframe, an HTML skeleton, and then CSS that turns it into a real styled page.

This is the written version of my CSS crash course video. It's embedded near the top.

Key Takeaways
  • Plan a layout before writing CSS by labeling elements the way you'll reference them: # for an id, . for a class.
  • Center a page's content by giving a wrapping container a max-width and margin: 0 auto.
  • A comma-separated selector list (.header, .nav, .footer { }) applies the same rules to multiple elements at once.
  • Turning a list into a horizontal nav takes three rules: list-style: none, reset margin and padding, and display: inline on the list items.
  • CSS rules loaded later in the file win when two rules target the same property on the same element. Order matters.

Planning with a wireframe

Before touching CSS, it helps to label a rough layout the same way you'll reference it in code. An id (used for one specific, non-repeating element) gets a #; a class (used for anything you might apply to more than one element, or want to group with others) gets a .. For a simple page with a container, header, nav menu, content area, and footer, that's:

text
#container
.header
.menu
.content
.footer

#container gets an id because there's exactly one of it, wrapping everything else. The rest get classes because a class is the more flexible default, even for elements you only use once.

Building the HTML skeleton

Structure comes first. Nothing here is styled yet, just labeled with the ids and classes from the wireframe:

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Learn CSS</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="container">
    <header class="header">
      <h1>Welcome to My Site</h1>
    </header>
    <nav class="menu">
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
    </nav>
    <main class="content">
      <p>Page content goes here.</p>
    </main>
    <footer class="footer">
      <p>&copy; 2026 My Site</p>
    </footer>
  </div>
</body>
</html>

&copy; renders a copyright symbol. <link rel="stylesheet" href="style.css"> is what connects this file to the CSS you're about to write; rel describes the relationship (a stylesheet), href is the path to the file, and <link> is self-closing, like <meta>.

Centering the page with a container

The #container div exists purely to constrain width and center everything inside it. max-width caps how wide it gets on a large screen, and margin: 0 auto centers it: 0 for top and bottom margin, auto for left and right, which splits the remaining horizontal space evenly.

css
#container {
  max-width: 1200px;
  margin: 0 auto;
}

Below 1200px of browser width you won't see a difference yet; the container just matches the screen. Widen the browser past that and the container stops growing and centers itself in the extra space.

Styling shared elements together

The header, nav menu, and footer in this layout share several properties: a border, spacing, and centered text. Instead of repeating the same rules three times, list the selectors together separated by commas:

css
.header, .menu, .footer {
  border: 2px solid #333;
  margin-bottom: 20px;
  padding: 20px;
  text-align: center;
}

.footer {
  margin-bottom: 0;
}

border: 2px solid #333 is shorthand for width, style, and color in one line. Any rule you write after that grouped block, targeting one of those same classes individually, still applies on top of it. Here, .footer gets everything from the group, then overrides just its bottom margin to zero since it's the last element on the page.

Turning a list into a horizontal nav menu

An <ul> renders as a bulleted, vertically stacked list by default. Turning it into a horizontal menu takes three changes: drop the bullets, remove the browser's default spacing, and put the list items side by side.

css
.menu ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.menu li {
  display: inline;
}

list-style: none removes the bullets. Resetting margin and padding on the <ul> clears space browsers add automatically. display: inline on each <li> is what actually lines them up horizontally instead of stacking them.

A small, distinctive touch you can add on top of that: a separator between menu items using a pseudo-element instead of extra markup.

css
.menu li::after {
  content: "|";
  margin-left: 10px;
  color: white;
}

.menu li:last-child::after {
  content: "";
  margin-left: 0;
}

::after inserts generated content right after each list item without adding another HTML element for it. The :last-child rule then clears that content and its margin specifically on the final item, so the menu doesn't end with a trailing separator.

Adding a custom font

Google Fonts is the fastest way to add a real typeface. Pick a font on the site, select the weights you'll actually use, and it gives you a <link> snippet to paste into your <head>, right alongside your existing stylesheet link:

html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">

Then reference it by name in CSS:

css
body {
  font-family: 'Roboto', sans-serif;
}

The second value, sans-serif, is a fallback: if Roboto fails to load for any reason, the browser falls back to its default sans-serif font instead of an unstyled serif font.

Rule order and precedence

One easy mistake once a stylesheet grows past a few rules: setting a property on an element early in the file, then setting it again later without realizing the first one already applied. When two rules target the same property on the same element with equal specificity, the one that appears later in the file wins. If a change you make doesn't seem to take effect, check whether a rule further down the file is quietly overriding it. See MDN's guide to the cascade for how this interacts with selector specificity.

Where to go next

CSS Colors covers named colors, hex codes, and RGB in more depth than this walkthrough needed. CSS Element, ID, and Class Selectors and Inline, Internal, and External Style Sheets round out the fundamentals this crash course builds on.

FAQ

What's the difference between an id and a class in CSS?

An id (#name) is meant for one specific element on a page and is referenced with a hashtag. A class (.name) can apply to multiple elements and is referenced with a dot. When in doubt, use a class; it's the more flexible default even for something you'll only use once.

How do I center a page's content?

Wrap it in a container element, give that container a max-width, and set margin: 0 auto. The auto value on the left and right margins splits the remaining space evenly, centering the container.

How do I turn a bulleted list into a horizontal menu?

Set list-style: none to remove the bullets, reset margin and padding to zero on the list, and set display: inline (or display: flex on the list itself, for more layout control) on the list items.

Why isn't my CSS change showing up?

Check whether a rule later in the stylesheet is targeting the same property on the same element with equal or higher specificity. Later rules win ties, so a rule further down the file can silently override an earlier one.

Do I need Google Fonts to add a custom font?

No, but it's the simplest option for most projects: pick a font, copy the <link> snippet into your <head>, and reference the font name in font-family. You can also self-host font files if you'd rather not depend on an external request.

Share this article:

Related Posts