CSS3 Cheatsheet - CSS3 Properties & Layout Reference
Most CSS pain is not about forgetting property names. It is about not knowing which declaration won the cascade, why a computed width disagrees with the design file, and whether a layout problem belongs to Flexbox or Grid. So this sheet starts with selector specificity and the box model, including border-box and margin collapsing, then draws a firm line between the two layout systems: one axis means Flex, simultaneous row and column control means Grid, and anything out of normal flow means positioning. Visual and motion sections cover gradients, shadows, transitions and keyframes before the responsive breakpoints land at the end. What matters more than any single rule is the reasoning behind the choice, for example knowing that justify-content works on the main axis while align-items works on the cross axis, and reaching for fr and minmax rather than hard-coded percentages when sizing Grid tracks. Custom properties extend the same logic to runtime theming, so a colour or spacing decision can live in one token rather than being repeated per selector.
Typical Use Case
For web developers writing styles by hand or working without a framework. Eight lines organise the sheet: selectors, the box model, Flex, Grid, positioning, backgrounds and gradients, animation, and responsive design. Three items deserve priority — border-box so width includes padding and border, Flex for one dimension against Grid for two, and mobile-first media queries using min-width to grow toward larger screens. When a layout misbehaves — an element that will not centre, absolute positioning pinned to the top-left, flex children that refuse to wrap — the cause is almost always in those three. Use clamp for fluid type, rem for spacing, and transform for motion.
Selectors 8
.class#iddiv pdiv > pa:hover::before / ::after[type="text"]nth-child(2n)Box Model 6
width / heightpaddingbordermarginbox-sizing: border-boxborder-radiusLayout 8
display: blockdisplay: inline-blockdisplay: flexdisplay: griddisplay: noneposition: relative / absolute / fixedfloat: left / rightz-indexColors & Background 7
colorbackgroundbackground-image: url()background-size: coveropacitybox-shadowlinear-gradient()Text 6
font-sizefont-weighttext-alignline-heightletter-spacingwhite-space: nowrapTransitions & Animations 6
transition: all 0.3stransform: translateX(10px)transform: scale(1.2)transform: rotate(45deg)@keyframes name { 0% {} 100% {} }animation: name 1s infiniteResponsive 6
@media (max-width: 768px) { }max-width: 100%min-width: 0vw / vh / vmin / vmaxrem / emclamp(1rem, 2vw, 2rem)Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
.class / #id / element | Class / ID / element selectors | .card { padding: 10px; } |
parent > child | Direct child selector | nav > ul { margin: 0; } |
ancestor descendant | Descendant selector | div p { color: #333; } |
element + sibling / element ~ sibling | Adjacent sibling / general sibling selector | h2 + p { margin-top: 0; } |
[attr] / [attr="value"] | Attribute selector | input[type="text"] { width: 100%; } |
:hover / :focus / :active | Hover / focus / active pseudo-classes | a:hover { color: blue; } |
::before / ::after | Pseudo-elements that insert content or decoration | p::before { content: "· "; } |
width / height | The content width and height of the box | width: 100px; height: 100px; |
margin / padding | Margin / padding | margin: 10px; padding: 10px; |
border | Border shorthand (width style color) | border: 1px solid #000; |
box-sizing: border-box | Width and height include the border and padding | * { box-sizing: border-box; } |
display: block / inline / inline-block | Three common display types | .btn { display: inline-block; } |
display: none | Remove the element from the flow entirely. | .hidden { display: none; } |
visibility: hidden | Invisible, but still holding its place in the layout. | .mask { visibility: hidden; } |
opacity: 0.5 | Opacity of the element and everything inside it. | .faded { opacity: 0.5; } |
display: flex | Switch the element into Flex layout. | .row { display: flex; } |
flex-direction: row / column | Direction of the main axis. | flex-direction: column; |
justify-content | Main-axis alignment: flex-start, center, space-between. | justify-content: center; |
align-items | Cross-axis alignment: stretch, center, flex-start. | align-items: center; |
flex: 1 | Grow to absorb whatever space is left over. | .grow { flex: 1; } |
flex-wrap: wrap | Break onto a new line once the row runs out of room. | flex-wrap: wrap; |
gap: 10px | Spacing between items. | gap: 10px; |
display: grid | Switch the element into Grid layout. | .grid { display: grid; } |
grid-template-columns | Define the column tracks. | grid-template-columns: 1fr 1fr 1fr; |
grid-template-rows | Define the row tracks. | grid-template-rows: 100px auto; |
grid-gap: 10px | Spacing between the grid tracks. | grid-gap: 10px; |
grid-column: 1 / 3 | Span the item across columns. | grid-column: 1 / 3; |
grid-row: 1 / 3 | Span the item across rows. | grid-row: 1 / 3; |
grid-template-areas | Lay regions out by name. | grid-template-areas: "header" "main" "footer"; |
position: relative | Position against the element own box, and act as the reference for any absolute descendants. | .wrap { position: relative; } |
position: absolute | Position against the nearest positioned ancestor. | .badge { position: absolute; } |
position: fixed | Fixed to the viewport, so scrolling does not move it. | .bar { position: fixed; } |
position: sticky | Sticks in place once the scroll passes a threshold. | .nav { position: sticky; } |
top/right/bottom/left | Offsets applied to a positioned element. | top: 0; left: 0; |
z-index: 100 | Stacking order. | z-index: 100; |
background-image: url() | Background image. | background-image: url("bg.jpg"); |
background-size: cover / contain | Scale the image to fill the box, or to fit inside it. | background-size: cover; |
linear-gradient() | A linear gradient. | linear-gradient(to right, #000, #fff); |
radial-gradient() | A radial gradient. | radial-gradient(circle, #000, #fff); |
transition: all 0.3s ease | Animate property changes over time. | transition: all 0.3s ease; |
transform: translateX / scale / rotate | Move, scale or rotate, none of which triggers reflow. | transform: scale(1.5); |
@keyframes / animation | Define keyframes and play them on a loop. | animation: name 1s infinite; |
@media (max-width: 768px) | A media query breakpoint. | @media (max-width: 768px) { .nav { display: none; } } |
vw / vh / vmin / vmax | Viewport units: width, height, shortest side, longest side. | width: 100vw; |
rem / em | Units relative to the root font size, or to the parent font size. | font-size: 1.25rem; |
clamp(min, preferred, max) | A responsive value that scales within the given range. | font-size: clamp(1rem, 2vw, 2rem); |
Common pitfalls
SymptomAn element with width: 200px actually takes up 200 + padding*2 + border*2, wider than expected
CauseThe default box-sizing is content-box, so width covers only the content area and the border and padding add on top.
FixSet * { box-sizing: border-box; } globally so width and height include the border and padding.
SymptomAn absolutely positioned element sticks to the top-left corner of the page or ends up far from where it belongs
Causeabsolute is positioned relative to the nearest non-static ancestor; when all ancestors are static it falls back to the initial containing block, a completely different coordinate system.
FixAdd position: relative to the parent you intend as the container, then set the top/left offsets.
SymptomThe element still occupies space after being hidden, so the next element is pushed down
Causedisplay: none removes the element entirely, while visibility: hidden only makes it invisible; their space-occupying behavior differs.
FixUse display: none to remove it entirely (including its space); use visibility: hidden to keep the space and hide only visibility.
SymptomA flex layout sets justify-content: center but does not center
CauseCross-axis alignment is controlled by align-items, and if a child width fills the main axis, centering is visually invisible.
FixUse justify-content for the main axis and align-items for the cross axis, setting the two axes separately; make sure no child has a fixed width filling the main axis.
SymptomFor responsive work, large-screen styles do not apply on large screens while small-screen ones do
CauseYou used max-width queries but wrote desktop-first, the opposite of mobile-first logic; the base styles get overridden by narrow screens.
FixSwitch to mobile-first: write base styles for small screens, then extend to larger screens with @media (min-width: ...).
SymptomGradient text color fails, while a background gradient works fine
Causebackground-image: linear-gradient() applies to the element background and needs -webkit-background-clip: text to show as a text gradient.
FixCombine them: linear-gradient(...) plus -webkit-background-clip: text; and color: transparent;.
SymptomThe page stutters and drops frames during the animation
CauseThe transition targets properties like width, height, margin that trigger reflow, recalculating layout every frame.
FixAnimate with transform: translateX / scale / rotate and opacity instead, which the compositor can handle.
SymptomThe parent sets flex-wrap: wrap, yet the children stay on one line and the content spills out.
CauseA flex item defaults to min-width: auto, so its content can impose a minimum wider than the wrap decision allows, and the row overflows rather than breaking.
FixSet min-width: 0 on the items that need to shrink, alongside an overflow rule, so wrapping is judged against the width that is actually available.
Troubleshooting
1Unify the box-model baseline first
* { box-sizing: border-box; }After setting border-box as the global baseline, every width and height includes the border and padding. Measure the same element actual width before and after; if the difference equals the padding plus border, the earlier offset was caused by content-box.
2Reproduce a one-dimensional layout with Flex
display: flex; justify-content: space-between; align-items: center; gap: 10px;justify-content governs the main axis, align-items the cross axis, and gap the spacing; set per axis, they let side-by-side columns and vertical centering hold at once. If the spacing is off, first check for leftover child margins.
3Reproduce a two-dimensional layout with Grid
display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 10px;For three equal columns, repeating 1fr three times is the most robust; row height can be left to content (auto). To make an element span the full row, add grid-column: 1 / 3; to switch to named areas, use grid-template-areas for a full-page layout.
4Three-step confirmation when a positioned element is off
.wrap { position: relative; } .badge { position: absolute; top: 0; left: 0; z-index: 100; }First add relative to the reference container, then set the offset, and finally tune z-index. If removing relative happens to fix the position, the reference was wrong: absolute only honors the nearest positioned ancestor, while fixed uses the viewport.
5Responsive breakpoint self-check
@media (max-width: 768px) { .nav { display: none; } }First use a narrow-screen query to confirm that small-screen styles actually apply, then decide whether to switch to min-width for extending to large screens. Meanwhile use clamp(1rem, 2vw, 2rem) for continuous font scaling, less hassle than a pile of breakpoints.
6Check the animation is not costing you frames
.box { transition: transform 0.3s ease; } .box:hover { transform: translateX(10px); }When both the transition and the hover rule act on transform, the animation runs on the compositor with no reflow and stays smooth. Swap in transition: all or animate width instead and the frame rate drops, so compare against the transform version first to confirm that reflow is the bottleneck.
Command Examples
box-sizing decides whether width includes padding
* {
box-sizing: border-box;
}
.card {
width: 100%;
padding: 20px;
border: 1px solid #000;
}Under the default content-box, 100% width plus padding overflows the container by 40px. A global border-box makes width the final occupied size, and the class of "I set 100% and it still breaks the layout" bugs disappears at once.
Centring on both axes with flexbox
.parent {
display: flex;
justify-content: center;
align-items: center;
}justify-content handles the main axis (horizontal) and align-items the cross axis (vertical); the division never changes. align-items defaults to stretch, so switching it to centre often collapses or stretches children, producing the classic "it got distorted once centred" effect.
Laying out a page with named grid areas
.layout {
display: grid;
grid-template-areas:
"header"
"main"
"footer";
}
.header { grid-area: header; }
.main { grid-area: main; }
.footer { grid-area: footer; }Spaces inside the quotes are columns and newlines are rows, so "header main footer" means three columns in one row. Restructuring the layout means editing the areas string rather than recomputing grid-row and grid-column numbers one by one.
Fluid type with clamp
h1 {
font-size: clamp(1rem, 2vw, 2rem);
}clamp(min, preferred, max) interpolates linearly between 375px and 1000px of viewport width, which beats a pile of media queries. Making the middle term a large multiple of vw (such as 5vw) overflows the container on small screens.
A sticky header with a z-index
.header {
position: sticky;
top: 0;
z-index: 100;
background: #fff;
}sticky needs a top or bottom reference, and an ancestor with overflow: hidden makes it stop sticking early inside that container. z-index is only compared between positioned elements, so writing it without a position has no effect.
Common Pitfalls
- display: none removes the element and its subtree from layout, while visibility: hidden only makes it invisible but still occupies space; fading out with display collapses layout and lets clicks pass through to the layer below.
- Without box-sizing: border-box, width and height exclude padding and border, so any percentage width plus padding overflows the parent — the usual root cause of misplaced layouts.
- position: absolute resolves against the nearest positioned ancestor, not the viewport; remove that ancestor position and the element relocates to the initial containing block.
- opacity creates a new stacking context: an ancestor with opacity and z-index: 999 can no longer be out-stacked by a child with a larger z-index.
- vh includes the mobile browser address bar, so 100vh leaves the bottom of the page hidden behind it and produces an unscrollable strip of blank space.
- transform and filter create containing blocks, which makes a nested position: fixed behave as absolute; animating an overlay makes it drift with the scroller.
Tips
- box-sizing: border-box makes width/height include border and padding — more intuitive.
- Flex fits one-dimensional layouts (row or column); Grid fits two-dimensional (rows and columns together).
- Mobile-first: write small-screen styles first, then extend with @media (min-width).
FAQ
Why does a child with position: absolute end up in the wrong place?
Absolute positioning resolves against the nearest positioned ancestor, not the parent element itself. If the parent is position: static (the default), absolute falls back to the viewport, which is why the offset appears to do nothing. Give the intended container position: relative, offset the child with top/right/bottom/left, then use z-index: 100 to order it against siblings. fixed also resolves against the viewport, and sticky needs a scrolling ancestor — do not mix those reference frames up.
Does the choice between display: none and visibility: hidden change the layout?
Yes — that is the whole difference. display: none removes the element from the render tree so it occupies no layout space and later elements shift up; visibility: hidden only stops painting while the box keeps its place in the flow; opacity: 0 likewise keeps the space. Only display: none actually takes the element out, so when you toggle visibility conditionally and must not cause reflow, visibility: hidden or opacity: 0 is the safer choice.
When should I reach for Flex and when for Grid?
Pick by dimensionality. One-dimensional — a single row or column — is display: flex: flex-direction sets the main axis, justify-content aligns along it, align-items across it, flex-wrap allows wrapping, gap supplies spacing and flex: 1 shares out the remaining room. Two-dimensional is display: grid: grid-template-columns / rows define the skeleton, grid-column: 1 / 3 spans columns, and grid-template-areas lays out named regions. Do not use Grid for a one-axis job, and do not nest Flex containers to fake a grid.
How do I keep responsive CSS from turning into a pile of media queries?
Go mobile-first: write the small-screen styles as the default first, then extend upward with @media (min-width: 768px) { } instead of stacking max-width overrides. Use max-width: 100% on images and containers so nothing overflows, and min-width: 0 on flex children so they can actually shrink. Let type scale on its own with clamp(1rem, 2vw, 2rem), and choose units deliberately — vw/vh for the viewport, rem against the root, em against the parent.
What exactly does box-sizing: border-box change, and why set it globally?
Under the default content-box, width: 100px describes the content only, so once padding and border are added the element occupies more than 100px — which is why layouts overflow their containers. With box-sizing: border-box the declared width already includes padding and border, so the value matches the real footprint and works predictably with max-width: 100%. Set it once globally on the * selector instead of adjusting each box by hand.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us