CSS Essentials
SAP Implementation Consulting & ERP - Startupistan Germany · Block I · study notes for revision.
What CSS actually is
Section titled “What CSS actually is”HTML builds the structure of a page - what each thing is. On its own it looks plain and unstyled, and that is HTML doing its one job correctly, not a sign something broke. CSS - Cascading Style Sheets - is the second language: it describes how that structure looks. Colours, fonts, sizes, spacing, layout - all of it lives in CSS.
Break the name in two:
- Style Sheets - files full of styling rules, kept separate from the content they style.
- Cascading - the way CSS settles arguments. Several rules can target the same element at once, and a fixed order decides which one wins.
One thing to fix early: CSS is not a programming language. There are no loops, no decisions, no logic - just declarations that say “this should look like that,” which the browser then applies. That is exactly why it is approachable from day one.
Three ways to add CSS
Section titled “Three ways to add CSS”CSS can reach a page by three routes. I use one of them for real work, but I need to recognise all three because I’ll meet them in the wild.
| Route | How it attaches | Scope | Use it for |
|---|---|---|---|
| Inline | style attribute on one element | That one element | HTML emails, quick tests, tool-generated markup |
| Internal | <style> block inside <head> | That one page | Genuine single-file pages, small demos |
| External | separate .css file linked from <head> | Every page that links it | Everything real - the default |
The external route connects like this, with a link element in the head - rel names the relationship (a stylesheet), href holds the address:
<link rel="stylesheet" href="styles.css">Why external wins, in three concrete reasons:
- One file styles every page. Change a colour once and it changes everywhere. With internal styles, three pages means three copies quietly drifting apart.
- Content files stay content. The HTML stays readable for what it is.
- Browsers cache it. A returning visitor already has the stylesheet and doesn’t download it again, so pages load faster.
The anatomy of a ruleset
Section titled “The anatomy of a ruleset”Everything in a stylesheet is built from one repeating shape. Its four parts have exact names, because documentation, DevTools, and every bug hunt use these words.
body { /* selector - which elements this targets */ background-color: #faf5ee; /* declaration: property + value, ends in ; */ color: #2f2a25; /* property = what aspect · value = the setting */} /* the braces { } hold the declaration block */- The selector (
body) says which elements the rule applies to. - The declaration block is everything between the braces.
- Each declaration is one
property: value;pair, ended by a semicolon. - The property names what aspect to style; the value sets it.
A selector plus its declaration block is a ruleset. A stylesheet is just rulesets stacked top to bottom.
The two silent breakages. CSS never reports errors to the page - it skips what it can’t parse and moves on. Silence is not correctness.
- Missing semicolon - the parser runs the broken line into the next declaration and discards both. Symptom: one styling works, the next one mysteriously doesn’t. First thing to check: the semicolon on the line above.
- Missing closing brace - breaks every ruleset after it in the file. Symptom: everything below a certain point dies at once. The editor’s bracket colouring flags it instantly, if I look.
Selectors - the reference table
Section titled “Selectors - the reference table”The selector is where a ruleset takes aim. These five cover nearly everything, and one of them becomes the workhorse.
| Selector | Written as | Matches | Example |
|---|---|---|---|
| Element | bare name | every element of that kind | h1 { color: #8a5a2e; } |
| Class | leading dot | every element carrying that class | .tagline { color: #6b6257; } |
| Id | leading hash | the one element with that id (unique per page) | #site-logo { ... } |
| Descendant | two selectors, a space between | elements inside another element | nav a { ... } (links inside the nav) |
| Pseudo-class | colon + state | an element in a given state | a:hover { color: #8a5a2e; } |
Class is the workhorse. Any number of elements can share a class, and one element can carry several. I decide exactly which elements belong to a styling group, whatever kind they are. An id targets exactly one element forever - the rare, specific tool, wrong for anything that might ever have a sibling.
Two combining tricks earn their keep:
- Grouping with commas applies one block to several selectors -
h1, h2 { color: #8a5a2e; }reads “for every h1 and every h2.” - Descendant (a space) reaches inside -
nav astyles only links inside the nav, leaving a link in a paragraph untouched.
Colour
Section titled “Colour”CSS accepts a colour in several notations. Three matter now, one gets a mention:
| Notation | Looks like | Note |
|---|---|---|
| Named | green, white | ~140 names; handy in experiments, too coarse for real palettes |
| Hex | #faf5ee | The workhorse. #RRGGBB - two hex digits each for red, green, blue, 00-FF. Every brand palette arrives this way |
| rgb() | rgb(6, 48, 42) | same three channels in decimal |
| hsl() | hsl(174, 78%, 11%) | hue, saturation, lightness; designers like it for reasoning about colour - recognise it |
Two properties do the colouring: color sets the text colour, background-color sets the fill behind an element. Set both on body and the text colour inherits down to every paragraph, list, and heading until a more specific rule overrides it.
body { background-color: #faf5ee; /* warm cream */ color: #2f2a25; /* dark warm brown, inherited everywhere */}DevTools - the microscope
Section titled “DevTools - the microscope”Inspect & experiment Because CSS fails silently, the browser’s inspector is a beginner’s best friend, not an expert-only tool. Right-click any element on any page and choose Inspect. Chrome opens DevTools with the Elements panel (the live element tree) and the Styles pane beside it - showing every ruleset that applies, which file it came from, and its line number.
What it gives me:
- Reading the cascade - rules are listed most-specific first; struck-through declarations lost the cascade, so “why isn’t my style applying?” becomes a reading exercise instead of a mystery.
- Live editing - click any value and type a new one; the page updates instantly. Click a colour swatch and the picker even shows the contrast ratio against the background, with the 4.5:1 line marked.
- Three diagnoses in one pane - a completely unstyled page means the stylesheet isn’t linked (usually a typo in the
href); a ruleset that never appears means the selector matches nothing (a class typo); a warning icon marks a declaration a missing semicolon ate.
Typography
Section titled “Typography”Most of the web is text, which makes typography the highest-leverage design skill here. It starts with two words people blur and professionals don’t:
- A typeface is the design - the whole family of letterforms with a name (Playfair Display, Lato).
- A font is one concrete style of that typeface - one weight, one posture (Playfair Display Bold; Lato Regular Italic).
The typeface is the family; each font is one member. CSS agrees - the property is font-family: I name the family, the browser picks the member each situation needs.
Two rules carry me far: legibility first for body text (it must disappear into effortless reading), character for the headings and brand (read in single lines, they can afford a distinctive voice); and two typefaces maximum - one with character for display, one calm workhorse for everything else. More than two reads as chaos.
Loading a web font
Section titled “Loading a web font”Visitors don’t have my chosen typeface installed, and they don’t need to - the page can bring its own web fonts along. This course loads them from Google Fonts (free, open-license, copy-paste integration; alternatives worth knowing exist - Adobe Fonts, or self-hosting the files). Pick the typeface, select the weights needed (e.g. 400 regular and 700 bold), and paste the link elements into every page’s head, above my own stylesheet’s link:
<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=Lato:wght@400;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">Then name the family in CSS, always ending in a generic family as a safety net:
body { font-family: "Lato", sans-serif; /* quote multi-word names; end with serif / sans-serif / monospace */}A type hierarchy
Section titled “A type hierarchy”Readable pages aren’t luck - they’re a hierarchy: sizes, weights, and spacing chosen so a glance already says what’s a title, a section, and plain text. Five properties build one:
| Property | Sets | Good practice |
|---|---|---|
font-size | how large text renders | pick from a small scale (e.g. body 1.6rem, h2 2.4rem, h1 3.6rem), not ad-hoc values |
font-weight | stroke heaviness | 400 (normal) and 700 (bold) - match the weights loaded from Google Fonts |
font-style | upright or italic | the “costume” side of emphasis - looks only, no meaning |
line-height | space between lines | write it unitless (1.6) so it scales with any font size; 1.5-1.6 for body |
text-align | left · center · right | long text stays left; center is only for short display lines |
Sizing units
Section titled “Sizing units”The unit I choose for text is quietly an accessibility decision.
| Unit | Type | Relative to | Reach for it when |
|---|---|---|---|
px | absolute | nothing - fixed | borders, tiny fixed details; avoid for text size |
rem | relative | the root (html) font size | the default for text & spacing - no compounding, scales with the visitor’s setting |
em | relative | the current element’s font size | rarely - it compounds and gets hard to control |
% | relative | the parent’s value | fluid widths, and the 62.5% root trick |
vw / vh | relative | 1% of viewport width / height | full-screen heroes, viewport-sized blocks |
Why rem is the accessible choice: every browser lets the user set a preferred default font size - a low-vision visitor might set 20px. Sizes in rem scale with that root, so the whole site respects the choice. Sizes in px ignore it flatly.
The box model
Section titled “The box model”Every element the browser renders is a rectangle of four layers, from the inside out. This is the single most important mental model for spacing anything.
.card { padding: 1.6rem; /* space inside the box */ border: 1px solid #e3d9c9; /* the drawn edge */ margin: 2rem; /* space outside, between neighbours */}One value sets all four sides; two values set vertical then horizontal (padding: 1.2rem 2rem; = top/bottom then left/right).
box-sizing: the sane default
Section titled “box-sizing: the sane default”Before writing a single width, one question needs a fixed answer: when I say width: 300px, what exactly is 300px wide?
content-box(the browser default) - width measures the content only. Padding and border are added on top, so a 300px card with 20px padding and a 2px border actually renders 344px wide. Every padding change resizes the element, and layouts need arithmetic forever.border-box- width measures the visible box (content + padding + border together). The same card renders exactly 300px; the content shrinks to make room inside. What I say is what I get.
The professional fix, one rule at the very top of the stylesheet using * (the universal selector, matching every element):
* { box-sizing: border-box; /* width now means the visible box, everywhere - no arithmetic */}Sizing companions: width sets it, max-width caps it (the box stays fluid but never grows past the cap - the workhorse), and height mostly stays unset on text, because content should decide its own height. The classic centred container:
.container { max-width: 96rem; /* cap the line length at a readable measure */ margin: 0 auto; /* auto left+right splits leftover space equally = centred */ padding: 0 2rem; /* keep content off the screen edges on narrow windows */}The display property
Section titled “The display property”display sets which layout behaviour a box uses. The defaults I already know are its values:
| Value | Behaviour |
|---|---|
block | own line, full available width - headings, paragraphs, lists, div |
inline | flows within text, takes only its own space, ignores width/height and vertical padding - a span can’t be sized like a box |
inline-block | the middle ground - flows in a line and accepts width, height, padding |
none | removed from the page entirely - takes no space at all |
flex | turns the element into a flex container - the door to layout |
Flexbox - building a layout
Section titled “Flexbox - building a layout”Flexbox arranges boxes along a line. Set display: flex on a container and its direct children become flex items that obey. Items line up along the main axis; the direction crossing it is the cross axis. Almost everything is set on the container - the items just follow.
-
Make the container.
display: flexon the parent. Its direct children are now flex items. -
Set the main axis with
flex-direction-row(default, horizontal) orcolumn(vertical). Every other property follows this choice. -
Place along the main axis with
justify-content-flex-start(default),center, orspace-between(first item at one end, last at the other). -
Align on the cross axis with
align-items-center(the constant reach-for),flex-start, orstretch(default, equal heights). -
Space and wrap with
gap(fixed space between items - no margin tricks) andflex-wrap: wrap(let a crowded row break onto a second line).
Here’s a full, copy-pasteable example - a header bar (brand pushed left, links pushed right) plus a wrapping row of cards:
<header class="header-bar"> <span class="brand">Café Aroma</span> <nav> <a href="#">Menu</a> <a href="#">About</a> <a href="#">Visit</a> </nav></header>
<section class="card-row"> <article class="card"> <h3>Morning Bun</h3> <p class="price">3.50</p> </article> <article class="card"> <h3>Rye Loaf</h3> <p class="price">4.20</p> </article> <article class="card"> <h3>Almond Tart</h3> <p class="price">3.90</p> </article></section>* { box-sizing: border-box; }
/* header: two ends pushed apart, everything on one centreline */.header-bar { display: flex; justify-content: space-between; /* brand left, nav right */ align-items: center; /* same visual centreline */ padding: 1.2rem 2rem; background-color: #2f2a25; color: #faf5ee;}
/* the nav is its own flex container for evenly spaced links */nav { display: flex; gap: 2.4rem;}nav a { color: #faf5ee; text-decoration: none; }
/* card row: wraps to a new line when space runs out */.card-row { display: flex; flex-wrap: wrap; gap: 2.4rem;}
.card { background-color: #ffffff; border: 1px solid #e3d9c9; padding: 1.6rem; max-width: 28rem;}Revision summary
Section titled “Revision summary”| Must-know | One-line recall |
|---|---|
| CSS | Cascading Style Sheets - describes how HTML looks; not a programming language |
| Three ways to add it | inline, internal, external - external wins (one file, clean content, cached) |
| Ruleset | selector { property: value; } - a missing ; or } fails silently |
| Selectors | element / class (workhorse) / id / descendant (space) / pseudo-class; name classes by role |
| Colour | hex #RRGGBB is the workhorse; color + background-color; every pairing ≥ 4.5:1 contrast |
| Typeface vs font | typeface = the family; font = one weight/style of it → font-family, ending in a generic family |
| Web fonts | load from Google Fonts into every page’s head; fallback list is the safety net |
| Type hierarchy | pick sizes from a scale; unitless line-height ~1.6; long text stays left-aligned |
| Units | rem for text/spacing (accessible, scales); px fixed; the 62.5% root trick makes 1rem = 10px |
| Box model | content → padding → border → margin; background stops at the border, margin is transparent |
| box-sizing | * { box-sizing: border-box; } at the top so width = the visible box |
| display | block / inline / inline-block / none / flex (governs the children) |
| Flexbox | display:flex on the container; flex-direction · justify-content · align-items · gap · flex-wrap |
| DevTools | right-click → Inspect; read the cascade, experiment live, then copy winners into the stylesheet |