Styles and lays out HTML. Modern CSS (Grid, Flexbox, custom properties) handles most layouts without a preprocessor or framework.
Selectors & specificity
/* type, class, id, specificity increases left to right */
p { color: #222; }
.card { padding: 16px; }
#header { position: sticky; }
/* combinators */
.card > h2 { margin-top: 0; } /* direct child */
.card p + p { margin-top: 8px; } /* adjacent sibling */
nav a:hover { text-decoration: underline; }
Specificity order (low → high): type selectors → classes/attributes/pseudo-classes → IDs → inline styles → !important. Prefer classes over IDs for styling, and avoid !important except as an escape hatch against third-party CSS.
Box model
.box {
box-sizing: border-box; /* padding/border included in width, set this globally */
width: 300px;
padding: 16px;
border: 1px solid #ccc;
margin: 8px;
}
*, *::before, *::after { box-sizing: border-box; }
Flexbox (one-dimensional layout)
.row {
display: flex;
justify-content: space-between; /* main axis */
align-items: center; /* cross axis */
gap: 12px;
}
.row > .grow { flex: 1; }
Grid (two-dimensional layout)
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.grid .featured { grid-column: span 2; }
Custom properties (CSS variables)
:root {
--brand: #5865f2;
--radius: 8px;
}
.button {
background: var(--brand);
border-radius: var(--radius);
}
Unlike Sass variables, these are live in the DOM, you can override them per-component or with JS (el.style.setProperty("--brand", "#ff0000")), and they respect the cascade/inheritance.
Responsive design
.container { padding: 16px; }
@media (min-width: 768px) {
.container { padding: 32px; }
}
Mobile-first (min-width queries, base styles for small screens) is the more common modern approach over max-width desktop-first queries.
Popular tools
| Purpose | Common choice |
|---|---|
| Utility framework | Tailwind CSS |
| Preprocessor | Sass/SCSS (less necessary now that CSS has nesting & variables natively) |
| Component styling in JS frameworks | CSS Modules, styled-components |
Common gotchas
z-indexonly works on positioned elements (positionother thanstatic).- Margins between two block elements can collapse (the larger one wins instead of both adding), a common source of "why is there extra space" bugs.
height: 100%on a child does nothing unless the parent has an explicit height set somewhere up the chain.
See also: React for how component-scoped styling typically layers on top of these fundamentals.