Every CSS concept in one page โ selectors to animations, flexbox to custom properties. Each section links to a deeper lesson where available.
/* selector { property: value; } */
h1 { color: navy; font-size: 2rem; }<link rel="stylesheet" href="style.css"> โ cacheable, reusable.<style>โฆ</style> in the head โ fine for single pages.style="color:red" โ avoid; impossible to maintain, highest specificity.p /* element */ .card /* class โ reusable, your main tool */ #header /* id โ unique, avoid for styling */ * /* universal */ h1, h2 /* group */ div p /* descendant โ any depth */ div > p /* direct child only */ h2 + p /* adjacent sibling โ the p right after h2 */ h2 ~ p /* all following siblings */ [type="email"] /* attribute equals */ [href^="https"] /* starts with */ [href$=".pdf"] /* ends with */ [class*="btn"] /* contains */ li:first-child li:last-child li:nth-child(2n) /* even */ li:nth-child(odd) p:not(.intro) input:checked div:has(> img) /* parent selector! โ modern browsers */ li:is(.a, .b) /* matches either, shorter to write */
Deeper lesson: Selectors
When two rules conflict, the browser scores them. Memorize the hierarchy:
| Weight | What | Example |
|---|---|---|
| 1000 | Inline style | style="โฆ" |
| 100 | ID | #header |
| 10 | Class, attribute, pseudo-class | .card [type] :hover |
| 1 | Element, pseudo-element | p ::before |
!important beats everything โ treat it as a code smell, not a tool.inherit.Interview favourite: "Which wins: #nav a or .nav .link.active?" โ #nav a = 101, the class chain = 30. The ID wins. This is why frameworks avoid IDs entirely.
| Unit | Relative to | Use for |
|---|---|---|
px | Fixed | Borders, shadows, small fixed details |
rem | Root font-size (16px default) | Font sizes, spacing โ your default |
em | Parent font-size | Padding that scales with the element's own text |
% | Parent size | Fluid widths |
vw / vh | Viewport width/height | Full-screen sections, hero heights |
ch | Width of "0" character | Readable line lengths: max-width: 65ch |
fr | Grid free space | Grid column sizing |
Why rem over px for text: users who increase their browser font size (accessibility) get scaled text with rem, but not with px.
color: #6d6ffb; /* hex */ color: rgb(109 111 251); /* rgb โ modern space syntax */ color: rgb(109 111 251 / 0.5); /* with 50% alpha */ color: hsl(239 95% 71%); /* hue saturation lightness โ easiest to tweak */ background: linear-gradient(135deg, #6d6ffb, #8b5cf6); background: radial-gradient(circle at top, #1c2333, #0a0a10); background: conic-gradient(from 0deg, red, yellow, red); /* pie charts! */
Deeper lesson: Colors ยท Backgrounds
/* every element = content + padding + border + margin */ .box { width: 300px; padding: 16px; /* inside the border */ border: 2px solid; /* the edge */ margin: 24px; /* outside โ pushes neighbours away */ } /* THE most important rule in CSS โ put it in every project: */ *, *::before, *::after { box-sizing: border-box; } /* now width:300px INCLUDES padding and border */ margin: 10px 20px; /* vertical | horizontal */ margin: 5px 10px 15px 20px;/* top right bottom left (clockwise) */ margin-inline: auto; /* center a block element */
Margin collapse: vertical margins of stacked elements merge into the larger one โ the classic "why is my spacing wrong" bug. Deeper lesson: Box Model ยท Margin & Padding
body {
font-family: 'Inter', system-ui, sans-serif; /* always give fallbacks */
font-size: 1rem;
font-weight: 400; /* 100โ900; 400 normal, 700 bold */
line-height: 1.7; /* unitless = multiplier โ best practice */
letter-spacing: -0.01em;
}
h1 { text-transform: uppercase; text-align: center; }
a { text-decoration: underline; text-underline-offset: 3px; }
p { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } /* truncate */
/* multi-line clamp */
.excerpt { display: -webkit-box; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; overflow: hidden; }Load Google Fonts with <link> plus font-display: swap to avoid invisible text. Deeper lesson: Typography
| Value | Behaviour |
|---|---|
block | Full width, new line |
inline | Flows in text; width/height ignored |
inline-block | Flows in text but accepts width/height |
flex / grid | Turns children into flex/grid items |
none | Removed entirely (no space kept) |
visibility: hidden hides but keeps the space; opacity: 0 keeps space and stays clickable โ a classic interview distinction. Deeper lesson: Display
position: static; /* default โ in normal flow */ position: relative; /* nudged from its spot; becomes anchor for children */ position: absolute; /* removed from flow; positioned vs nearest non-static parent */ position: fixed; /* pinned to the viewport โ navbars, chat buttons */ position: sticky; /* scrolls until it hits top: 0, then sticks */ .tooltip { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); z-index: 10; /* stacking order โ needs a position set */ }
Stacking contexts: z-index only competes within the same context. A child with z-index 9999 can still sit under an outside element if its parent created a lower context (transform, opacity<1, and filter all create one) โ the #1 "why is my modal behind things" bug. Deeper lesson: Position
.container {
display: flex;
flex-direction: row; /* row | column */
justify-content: space-between; /* main axis: start|center|end|space-between|around|evenly */
align-items: center; /* cross axis: stretch|start|center|end|baseline */
flex-wrap: wrap;
gap: 16px; /* spacing between items โ use this, not margins */
}
.item {
flex: 1; /* grow to share space equally */
flex: 0 0 200px; /* grow shrink basis โ fixed 200px */
align-self: flex-end; /* override for one item */
order: -1; /* visual reorder */
}
/* the centering everyone googles: */
.center { display: flex; justify-content: center; align-items: center; }Deeper lesson: Flexbox
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
grid-template-columns: 250px 1fr; /* sidebar + fluid main */
grid-template-rows: auto 1fr auto; /* header / content / footer */
gap: 20px;
}
/* THE responsive card grid โ no media queries needed: */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.item { grid-column: 1 / 3; } /* span columns 1โ2 */
.item { grid-column: span 2; } /* same thing */
/* named areas โ layout you can read: */
.page {
grid-template-areas: "header header" "sidebar main" "footer footer";
}
header { grid-area: header; }Flexbox vs Grid: Flexbox for one direction (navbar, button row); Grid for two dimensions (page layout, card galleries). They nest happily. Deeper lesson: Grid
/* Mobile-first: base styles = mobile, then enhance upward */ .container { padding: 16px; } @media (min-width: 640px) { .container { padding: 24px; } } @media (min-width: 1024px) { .container { max-width: 1200px; margin-inline: auto; } } @media (prefers-color-scheme: dark) { /* dark mode */ } @media (prefers-reduced-motion: reduce) { * { animation: none; } } @media print { nav, footer { display: none; } } /* Container queries โ respond to the PARENT's width (modern) */ .card-wrap { container-type: inline-size; } @container (min-width: 400px) { .card { flex-direction: row; } }
Common breakpoints: 640px (large phone), 768px (tablet), 1024px (laptop), 1280px (desktop). Deeper lessons: Media Queries ยท Responsive Design
/* pseudo-CLASSES (:) โ element states */ a:hover, a:focus-visible { color: royalblue; } input:focus { border-color: royalblue; } input:disabled, input:invalid, input:checked { โฆ } li:first-child, li:last-child, li:nth-child(2n) { โฆ } /* pseudo-ELEMENTS (::) โ generated content */ .quote::before { content: '"'; } p::first-line { font-weight: 700; } ::selection { background: gold; } input::placeholder { color: gray; } /* decorative shapes without extra HTML: */ .badge::after { content: ''; position: absolute; top: -4px; right: -4px; width: 10px; height: 10px; border-radius: 50%; background: red; }
Deeper lesson: Pseudo-classes & elements
.btn {
transition: transform 0.2s ease, box-shadow 0.2s ease;
/* property | duration | timing-function | delay */
}
.btn:hover { transform: translateY(-2px) scale(1.02); }
transform: translate(10px, 20px); /* move โ GPU-accelerated, smooth */
transform: rotate(45deg);
transform: scale(1.5);
transform: skew(10deg);
transform: translateX(-50%); /* half of OWN width โ centering trick */Performance rule: animate only transform and opacity โ they skip layout recalculation. Animating width/top/margin causes jank.
@keyframes float {
0% { transform: translateY(0); }
50% { transform: translateY(-12px); }
100% { transform: translateY(0); }
}
.card {
animation: float 3s ease-in-out infinite;
/* name | duration | timing | iteration-count */
animation-delay: 0.5s;
animation-fill-mode: forwards; /* keep the final state */
animation-play-state: paused; /* control from JS/hover */
}Deeper lesson: Animations
box-shadow: 0 4px 16px rgba(0,0,0,0.25); /* x y blur color */ box-shadow: inset 0 1px 0 rgba(255,255,255,.1);/* inner highlight */ box-shadow: 0 0 0 3px royalblue; /* focus ring */ text-shadow: 0 2px 8px rgba(0,0,0,0.4); filter: blur(4px) brightness(1.2) grayscale(50%) drop-shadow(0 2px 4px #000); backdrop-filter: blur(16px); /* frosted glass โ blurs what's BEHIND */ border-radius: 12px; /* 50% = circle */ opacity: 0.8; clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%); /* angled sections */
Deeper lesson: Borders & Shadows
:root {
--brand: #6d6ffb;
--space: 16px;
}
.btn {
background: var(--brand);
padding: var(--space) calc(var(--space) * 2);
}
.dark-theme { --brand: #8b5cf6; } /* theme switch = swap variables */
/* modern math functions */
width: min(90%, 1200px); /* whichever is SMALLER */
width: max(300px, 50%); /* whichever is LARGER */
font-size: clamp(1rem, 2.5vw, 1.5rem); /* min | preferred | max โ fluid type */
height: calc(100vh - 64px); /* mix units freely */
aspect-ratio: 16 / 9; /* responsive video boxes */This entire site is themed with variables โ inspect it with DevTools and see. Deeper lesson: CSS Variables
overflow: visible | hidden | scroll | auto; overflow-x: auto; /* horizontal scroll for tables on mobile */ scroll-behavior: smooth; /* smooth anchor jumps */ scroll-margin-top: 80px; /* anchor lands below your sticky navbar */ overscroll-behavior: contain; /* stop scroll chaining in modals */ /* scroll snapping โ carousels without JS */ .carousel { scroll-snap-type: x mandatory; overflow-x: auto; display: flex; } .slide { scroll-snap-align: center; flex: 0 0 100%; }
/* 1. Automatic โ follow the OS setting */ :root { --bg: #fff; --text: #111; } @media (prefers-color-scheme: dark) { :root { --bg: #0a0a10; --text: #f4f4f6; } } body { background: var(--bg); color: var(--text); } /* 2. Manual toggle โ JS adds a class, CSS swaps variables */ body.dark { --bg: #0a0a10; --text: #f4f4f6; }
// remember the choice btn.onclick = () => { document.body.classList.toggle('dark'); localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light'); };
box-sizing: border-box reset in every project!importantprefers-reduced-motiongap for spacing between items, margins for spacing around blocksPractice everything above in the live Code Playground, then test yourself with the 50 CSS interview questions.