CSS for Beginners: Make Your Website Actually Look Good
Learn CSS from zero -- selectors, the box model, Flexbox, media queries, and style a complete profile page. Practical guide, no fluff.
You've built an HTML page. It has structure, content, headings, links, images -- everything in the right place. But it looks like it's from 1996. Plain black text on a white background, default fonts, zero personality.
That's where CSS comes in. CSS (Cascading Style Sheets) controls how your HTML looks: colors, fonts, spacing, layout, animations, responsive behavior on different screen sizes. It's the difference between a page that looks like a homework assignment and one that looks like it was designed by a professional.
CSS has a reputation for being frustrating. Elements don't go where you expect, things break on mobile, centering something vertically feels impossible. Most of that frustration comes from not understanding a few core concepts. Once the box model and Flexbox click, CSS goes from maddening to satisfying.
This guide covers everything you need to go from unstyled HTML to a polished, responsive page.
How CSS Works
CSS rules follow a simple pattern:
selector {
property: value;
property: value;
}
A selector targets HTML elements. Properties are what you want to change. Values are what you're changing them to.
h1 {
color: navy;
font-size: 2.5rem;
}
This makes all elements navy blue with a font size of 2.5rem.
Three Ways to Add CSS
1. External Stylesheet (Best Practice)
Create a file called styles.css and link it in your HTML :
<head>
<link rel="stylesheet" href="styles.css" />
</head>
This is how you should do it in real projects. It keeps your HTML and CSS separate and lets multiple pages share the same styles.
2. Internal Style Tag
Put CSS directly in your HTML file inside a tag:
<head>
<style>
h1 { color: navy; }
</style>
</head>
Fine for quick experiments, but doesn't scale.
3. Inline Styles
Apply styles directly to an element:
<h1 style="color: navy; font-size: 2.5rem;">Hello</h1>
Avoid this in general. It mixes content with presentation and can't be reused.
Selectors
Selectors determine which elements your styles apply to.
Element Selector
Targets all elements of a type:
p {
color: #333;
line-height: 1.6;
}
This styles every on the page.
Class Selector
Targets elements with a specific class attribute:
.highlight {
background-color: yellow;
padding: 0.25rem;
}
<p class="highlight">This paragraph is highlighted.</p>
<p>This one is not.</p>
Classes are reusable -- you can apply the same class to as many elements as you want. This is the selector you'll use most.
ID Selector
Targets a single element with a specific ID:
#main-title {
font-size: 3rem;
}
<h1 id="main-title">Welcome</h1>
IDs should be unique per page. Prefer classes over IDs for styling -- IDs have higher specificity, which makes them harder to override later.
Compound Selectors
Combine selectors for more precise targeting:
/ Elements with class inside another element /
nav a {
color: white;
text-decoration: none;
}
/ Element with a specific class /
p.intro {
font-size: 1.25rem;
}
/ Multiple classes on the same element /
.btn.primary {
background: blue;
}
/ Multiple selectors, same styles /
h1, h2, h3 {
font-family: Georgia, serif;
}
Properties You'll Use Daily
Colors and Backgrounds
.card {
color: #333; / text color /
background-color: #f8f9fa; / background /
background: linear-gradient(to right, #667eea, #764ba2); / gradient /
}
Color values: named colors (red, navy), hex (#ff0000), RGB (rgb(255, 0, 0)), HSL (hsl(0, 100%, 50%)). Hex is the most common in practice.
Typography
body {
font-family: system-ui, -apple-system, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #1a1a1a;
}
h1 {
font-size: 2.5rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.subtitle {
font-style: italic;
text-transform: uppercase;
text-align: center;
}
Use rem for font sizes. 1rem equals the root font size (usually 16px). It scales properly and respects user preferences.
Spacing: Margin and Padding
.card {
margin: 1rem; / space outside the element /
padding: 1.5rem; / space inside the element /
}
You can set each side individually:
.card {
margin-top: 1rem;
margin-right: 2rem;
margin-bottom: 1rem;
margin-left: 2rem;
/ Shorthand: top right bottom left (clockwise) /
margin: 1rem 2rem 1rem 2rem;
/ Shorthand: vertical horizontal /
margin: 1rem 2rem;
/ All sides equal /
margin: 1rem;
}
margin: 0 auto; centers a block element horizontally (if it has a defined width).
Borders
.card {
border: 1px solid #e5e7eb;
border-radius: 8px; / rounded corners /
}
.avatar {
border: 3px solid #2563eb;
border-radius: 50%; / makes it circular /
}
The Box Model
This is the single most important concept in CSS. Every element is a rectangular box with four layers:
+---------------------------+
| margin |
| +---------------------+ |
| | border | |
| | +---------------+ | |
| | | padding | | |
| | | +---------+ | | |
| | | | content | | | |
| | | +---------+ | | |
| | +---------------+ | |
| +---------------------+ |
+---------------------------+
- Content -- the actual text, image, or child elements
- Padding -- space between the content and the border
- Border -- the edge of the element
- Margin -- space between this element and neighboring elements
width and height only set the content size. Padding and border are added on top, making the element larger than you specified. This is confusing and usually not what you want.
Fix it globally with:
, ::before, *::after {
box-sizing: border-box;
}
With border-box, width and height include padding and border. A 300px-wide element is 300px total, no matter how much padding you add. Put this at the top of every stylesheet.
Display Property
Controls how an element behaves in the layout:
/ Block: takes full width, starts on new line /
div, p, h1, section { display: block; }
/ Inline: flows with text, no width/height control /
span, a, strong, em { display: inline; }
/ Inline-block: flows with text BUT respects width/height /
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #e5e7eb;
border-radius: 12px;
}
/ None: completely hidden, takes up no space /
.hidden { display: none; }
The key differences:
| Behavior | Block | Inline | Inline-block |
|---|---|---|---|
| New line? | Yes | No | No |
| Width/height? | Yes | No | Yes |
| Margin/padding? | All sides | Left/right only | All sides |
Positioning
The position property controls how an element is placed:
Static (Default)
Elements flow normally in the document. Top, right, bottom, left properties have no effect.
Relative
Positioned relative to its normal position:
.nudged {
position: relative;
top: 10px; / moved 10px down from where it would normally be /
left: 20px; / moved 20px right /
}
The element still occupies its original space in the flow.
Absolute
Positioned relative to its nearest positioned ancestor (an ancestor with position: relative, absolute, or fixed):
.parent {
position: relative; / establishes the positioning context /
}
.badge {
position: absolute;
top: 10px;
right: 10px; / 10px from the top-right of .parent /
}
Absolute elements are removed from the normal flow -- they don't take up space and other elements act like they don't exist.
Fixed
Positioned relative to the browser window. Stays in place when the user scrolls:
.sticky-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 100;
}
Common use cases: fixed navigation bars, floating action buttons, cookie banners.
Flexbox: Modern Layout
Flexbox is how you do layout in modern CSS. It handles alignment, spacing, and distribution of elements along a single axis.
.container {
display: flex;
}
That single line changes everything. The container's children become flex items and line up in a row by default.
Direction
.container {
display: flex;
flex-direction: row; / horizontal (default) /
/ flex-direction: column; / / vertical /
}
Alignment
.container {
display: flex;
justify-content: center; / align along main axis /
align-items: center; / align along cross axis /
gap: 1rem; / space between items /
}
justify-content values: flex-start, flex-end, center, space-between, space-around, space-evenly.
align-items values: flex-start, flex-end, center, stretch, baseline.
Centering (The Famous Problem)
Centering something both horizontally and vertically used to be notoriously difficult. With Flexbox, it's three lines:
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; / full viewport height /
}
Done.
Flex Items
Control how individual items grow and shrink:
.sidebar {
flex: 0 0 250px; / don't grow, don't shrink, 250px wide /
}
.content {
flex: 1; / take up all remaining space /
}
Wrapping
By default, flex items stay on one line and shrink. Allow wrapping:
.grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.grid-item {
flex: 1 1 300px; / grow, shrink, base width 300px /
}
This creates a responsive grid without media queries. Items are 300px wide but grow to fill space, and wrap to the next line when there isn't room.
Media Queries: Responsive Design
Media queries let you apply different styles based on screen size:
/ Base styles (mobile first) /
.container {
padding: 1rem;
}
.nav-links {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/ Tablet and up /
@media (min-width: 768px) {
.container {
padding: 2rem;
max-width: 768px;
margin: 0 auto;
}
.nav-links {
flex-direction: row;
gap: 1.5rem;
}
}
/ Desktop /
@media (min-width: 1024px) {
.container {
max-width: 1024px;
}
}
The approach here is mobile-first: write base styles for small screens, then use min-width queries to add complexity for larger screens. This is the industry standard.
Common breakpoints:
- 768px -- tablets
- 1024px -- small laptops/desktops
- 1280px -- large desktops
Build: Styling the Profile Page
Remember the HTML profile page from the HTML tutorial? Let's make it look professional. Create profile-styles.css:
/ Reset and base /
, ::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #1a1a2e;
background-color: #f0f2f5;
}
/ Layout container /
main {
max-width: 720px;
margin: 0 auto;
padding: 1rem;
}
/ Navigation /
header {
background: #1a1a2e;
padding: 1rem 2rem;
position: sticky;
top: 0;
z-index: 10;
}
nav {
max-width: 720px;
margin: 0 auto;
display: flex;
gap: 1.5rem;
justify-content: center;
}
nav a {
color: #e0e0e0;
text-decoration: none;
font-weight: 500;
padding: 0.25rem 0;
border-bottom: 2px solid transparent;
transition: color 0.2s, border-color 0.2s;
}
nav a:hover {
color: #ffffff;
border-bottom-color: #667eea;
}
/ Sections /
section {
background: #ffffff;
border-radius: 12px;
padding: 2rem;
margin: 1.5rem 0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
/ About section /
#about {
text-align: center;
}
#about h1 {
font-size: 2.25rem;
color: #1a1a2e;
margin-bottom: 0.25rem;
}
#about img {
border-radius: 50%;
margin: 1rem 0;
border: 4px solid #667eea;
}
#about p {
max-width: 500px;
margin: 0.5rem auto;
color: #4a4a6a;
}
/ Headings /
h2 {
font-size: 1.5rem;
color: #1a1a2e;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid #667eea;
display: inline-block;
}
/ Skills table /
table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
}
thead {
background: #1a1a2e;
color: white;
}
th, td {
padding: 0.75rem 1rem;
text-align: left;
}
th {
font-weight: 600;
}
tbody tr {
border-bottom: 1px solid #e5e7eb;
}
tbody tr:hover {
background: #f8f9fa;
}
/ Projects /
article {
padding: 1rem 0;
border-bottom: 1px solid #e5e7eb;
}
article:last-child {
border-bottom: none;
}
article h3 {
font-size: 1.15rem;
color: #1a1a2e;
margin-bottom: 0.25rem;
}
article p {
color: #4a4a6a;
margin-bottom: 0.5rem;
}
article a {
color: #667eea;
text-decoration: none;
font-weight: 500;
}
article a:hover {
text-decoration: underline;
}
/ Contact form /
form div {
margin-bottom: 1rem;
}
label {
display: block;
font-weight: 600;
margin-bottom: 0.35rem;
color: #1a1a2e;
}
input[type="text"],
input[type="email"],
select,
textarea {
width: 100%;
padding: 0.65rem 0.85rem;
font-size: 1rem;
border: 1px solid #d1d5db;
border-radius: 6px;
font-family: inherit;
transition: border-color 0.2s;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);
}
button[type="submit"] {
background: #667eea;
color: white;
border: none;
padding: 0.75rem 2rem;
font-size: 1rem;
font-weight: 600;
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
}
button[type="submit"]:hover {
background: #5a6fd6;
}
/ Footer /
footer {
text-align: center;
padding: 2rem;
color: #6b7280;
font-size: 0.9rem;
}
footer a {
color: #667eea;
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
/ Remove default hr since sections handle spacing /
hr {
display: none;
}
/ Responsive /
@media (min-width: 768px) {
main {
padding: 2rem;
}
section {
padding: 2.5rem;
}
nav {
justify-content: flex-end;
}
}
Link it in the profile page's :
<link rel="stylesheet" href="profile-styles.css" />
Open the page now. Same HTML, completely different experience. The content is centered, the navigation is styled, the form looks professional, and the whole thing has a cohesive color scheme.
What This Stylesheet Demonstrates
- Reset --
box-sizing: border-boxand zeroed margins for consistent behavior - Element selectors -- styling
body,table,th,td - Class and ID selectors -- targeting specific sections like
#about - The box model --
padding,margin,borderused throughout - Display --
inline-blockfor the heading underline,flexfor navigation - Positioning --
stickyfor the navigation bar - Flexbox -- centering nav links, controlling layout direction
- Media queries -- adjusting padding and nav alignment on wider screens
- Transitions -- smooth hover effects on links and form inputs
- Pseudo-selectors --
:hover,:focus,:last-child
Common Mistakes Beginners Make
Not usingbox-sizing: border-box. Without it, a 300px element with 20px padding is actually 340px wide. This breaks layouts in subtle ways. Always set it globally.
Fighting specificity instead of understanding it. If a style isn't applying, don't throw !important at it. Understand why another rule is winning. ID selectors beat class selectors, which beat element selectors. More specific selectors win. Later rules win when specificity is equal.
Using pixels for everything. Use rem for font sizes (respects user preferences), % or vw/vh for responsive widths, and px only for small fixed values like borders.
Not testing on mobile. Open your browser's DevTools (F12), click the device toggle icon, and check how your page looks on different screen sizes. Do this early and often, not as an afterthought.
Overcomplicating layouts. Before reaching for complex CSS, ask: can Flexbox handle this? For one-dimensional layouts (a row or column of items), Flexbox is almost always the right tool. You only need CSS Grid for two-dimensional layouts (rows and columns simultaneously).
What's Next
You've got the CSS foundation to style any page. Here's where to keep going:
- CSS Grid -- two-dimensional layouts for more complex page structures
- CSS custom properties (variables) -- define colors and values once, reuse them everywhere
- Animations --
@keyframes,transition,transformfor motion and visual polish - A CSS framework -- Tailwind CSS is the current standard for utility-first styling
- Browser DevTools -- learn to inspect elements, live-edit styles, and debug layout issues
For more CSS, JavaScript, and web development guides, check out CodeUp.