CSS #
Selectors, specificity, the box model, and modern layout.
Selectors #
.class #id element *
a, b group (both a and b)
a b descendant
a > b direct child
a + b a ~ b adjacent / general sibling
[type="text"] attribute
:hover :focus :nth-child(2n) :not(.x) pseudo-classes
::before ::after ::selection pseudo-elements
Specificity & cascade #
/* inline(1000) > id(100) > class/attr/pseudo(10) > element(1) */
#nav .item a -> 0,1,1,1
.btn.primary -> 0,0,2,0
!important wins, but use sparingly
later rule breaks a tie; inheritance is weakest
Box model #
* { box-sizing: border-box; } /* width includes padding + border */
margin: 0 auto; /* center a block */
padding: 1rem 2rem; /* y x */
gap: 1rem; /* spacing in flex / grid */
Units & custom properties #
:root { --brand: #56e1d8; }
color: var(--brand);
font-size: clamp(1rem, 2.5vw, 1.5rem); /* fluid */
width: min(100%, 60ch);
/* rem=root em=parent % vh/vw fr(grid) ch */
Flexbox #
.row {
display: flex;
justify-content: space-between; /* main axis */
align-items: center; /* cross axis */
flex-wrap: wrap;
gap: 1rem;
}
.item { flex: 1 1 200px; } /* grow shrink basis */
Grid #
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
.feature { grid-column: span 2; }
Positioning #
position: relative | absolute | fixed | sticky;
inset: 0; /* top/right/bottom/left at once */
z-index: 10;
Transitions & responsive #
transition: transform .2s ease, opacity .2s ease;
transform: translateY(-3px) scale(1.02);
@media (max-width: 640px) { .row { flex-direction: column; } }
@media (prefers-reduced-motion: reduce) { * { transition: none; } }
Modern selectors & nesting #
.card:has(img) { padding: 0; } /* style a parent by its contents */
:is(h1, h2, h3) { line-height: 1.2; } /* shorter grouping */
li:not(:last-child) { margin-bottom: .5rem; }
input:focus-visible { outline: 2px solid; } /* keyboard focus only */
.menu {
& > li { color: var(--brand); } /* native nesting; & is the parent */
}
Container queries & ratio #
.panel { container-type: inline-size; container-name: side; }
@container side (width <= 600px) {
.card { font-size: 2em; } /* respond to the container, not the viewport */
}
.media { aspect-ratio: 16 / 9; } /* hold shape without padding hacks */
Animations #
@keyframes pulse {
from { opacity: 1; }
to { opacity: .4; }
}
.dot { animation: pulse 1s ease-in-out infinite alternate; }