Backgrounds & Borders
background-color/image/position/size/repeat and the background shorthand, linear-gradient() and radial-gradient() syntax, border-radius including elliptical corners, and box-shadow — inset, multiple stacked shadows, and blur/spread.
The Two Foundational Background Layers
Every element can have a background-color, a background-image, or both stacked together — and when both are set, the color renders behind the image, visible only where the image has transparent pixels or fails to load. This makes background-color a genuinely useful fallback, not just a simpler alternative.
.hero {
background-color: #1e293b; /* shows instantly, and if the image fails */
background-image: url("/hero-banner.jpg");
}background-image also accepts more than a single image — a comma-separated list of images (and/or gradients, covered in Part 02) stacks them in the order listed, with the first one on top.
.card {
background-image:
url("/pattern-overlay.png"),
url("/photo-base.jpg");
/* pattern-overlay.png renders ON TOP of photo-base.jpg */
}<img> element, a CSS background image is not part of the document's content — it is purely decorative, invisible to screen readers, and never appears in a right-click "Save Image As" the way a real <img> would. Meaningful, content-carrying images (a product photo, a diagram someone needs to understand the page) belong in <img> with real alt text — reserve background images for purely decorative use, exactly the distinction covered in the Images and Media module.Controlling Exactly Where and How Large a Background Renders
Three properties govern a background image's placement and scale independently of the element's own dimensions.
.a { background-position: center; } /* shorthand for "center center" */
.b { background-position: top right; } /* keyword pairs */
.c { background-position: 20px 40px; } /* offset from top-left corner */
.d { background-position: 50% 50%; } /* percentage of the remaining space, not the element */.hero {
background-size: cover;
/* scales the image to COMPLETELY fill the element, cropping whatever
overflows — the single most common background-size value in real
production CSS, used for full-bleed hero sections and card photos */
}
.logo-bg {
background-size: contain;
/* scales the image to fit ENTIRELY inside the element, preserving
aspect ratio, with empty space left over if the ratios don't match
— used when nothing may ever be cropped, e.g. a logo */
}
.tile {
background-size: 200px 100px; /* explicit width and height */
}
.icon {
background-size: 50% auto; /* one explicit, one auto-scaled to preserve ratio */
}.default { background-repeat: repeat; } /* tiles in both directions — the default */
.no-repeat { background-repeat: no-repeat; } /* shows the image exactly once */
.repeat-x { background-repeat: repeat-x; } /* tiles horizontally only */
.repeat-y { background-repeat: repeat-y; } /* tiles vertically only */
.space { background-repeat: space; } /* repeats with even gaps, never cropping a tile */background-size: cover, the parts of the image that get cropped are determined by background-position. A portrait photo used as a wide banner with cover and the default center center position will crop the top and bottom evenly — often cutting off a person's head. Setting background-position: top instead keeps the top of the image intact and crops from the bottom only. This is a real, constant styling decision, not an edge case.The background shorthand
All of the above (plus a couple more properties not covered here, like background-attachment) can be combined into a single background shorthand declaration. The shorthand accepts most sub-properties in a fairly flexible order, with one strict rule: when both background-size and background-position are present, size must come immediately after position, separated by a forward slash.
.hero {
background: url("/banner.jpg") center / cover no-repeat #1e293b;
/* image position/size repeat color */
}
/* Equivalent to writing all four properties separately: */
.hero-longhand {
background-image: url("/banner.jpg");
background-position: center;
background-size: cover;
background-repeat: no-repeat;
background-color: #1e293b;
}background: red; after an earlier background-image declaration silently wipes out the image — the shorthand does not merge with previously set longhand properties, it replaces the entire set. This is a very common bug when a later stylesheet rule (or a component library's reset) uses the shorthand and unintentionally clobbers an image set elsewhere.linear-gradient() — Direction, Color Stops, and Hard Edges
A gradient is not a separate CSS property — it is a special kind of value usable anywhere a background-image (or border-image, or a few other image-accepting properties) is expected. linear-gradient() blends colors along a straight line.
.a {
background: linear-gradient(#3b82f6, #1e3a8a);
/* no direction given — defaults to "to bottom" */
}.b { background: linear-gradient(to right, #3b82f6, #1e3a8a); }
.c { background: linear-gradient(to bottom right, #3b82f6, #1e3a8a); } /* diagonal, corner to corner */
.d { background: linear-gradient(45deg, #3b82f6, #1e3a8a); } /* precise angle, 0deg = to top */
.e { background: linear-gradient(135deg, #3b82f6, #1e3a8a); }The angle system is worth memorizing precisely, since it is easy to get backwards: 0deg points to the top, and angles increase clockwise from there — 90deg points right, 180deg points down, 270deg points left. This is the opposite rotation direction from standard mathematical angle convention, which is a genuinely common source of confusion.
Multiple color stops, and controlling exactly where each color sits
.rainbow {
background: linear-gradient(
to right,
red 0%,
orange 20%,
yellow 40%,
green 60%,
blue 80%,
violet 100%
);
}
.brand-fade {
background: linear-gradient(
to right,
#f97316 0%,
#f97316 40%, /* solid orange for the first 40% */
transparent 100%
);
}.stripe {
background: linear-gradient(
to right,
#f97316 0%,
#f97316 50%,
#1e293b 50%, /* same position as the stop above = a hard edge, not a blend */
#1e293b 100%
);
/* Two colors meeting at the exact same percentage produces a sharp
line instead of a gradual blend — used constantly for diagonal
"ribbon" banners and hard two-tone backgrounds. */
}background: linear-gradient(to bottom, transparent, rgba(0,0,0,0.7)), url("photo.jpg"); darkens only the bottom portion of the photo, exactly where caption text usually sits.radial-gradient() — Circular and Elliptical Blends
radial-gradient() blends colors outward from a center point instead of along a straight line — by default forming an ellipse that stretches to match the element's own aspect ratio, unless told otherwise.
.a {
background: radial-gradient(#3b82f6, #1e3a8a);
/* an ellipse by default, centered, sized to reach the farthest corner */
}.circle-spotlight {
background: radial-gradient(
circle at top left,
rgba(255,255,255,0.3),
transparent 60%
);
/* "circle" forces a true circle instead of an ellipse.
"at top left" moves the center point away from the default center. */
}
.contained-glow {
background: radial-gradient(
circle closest-side,
#facc15,
transparent
);
/* closest-side stops the gradient exactly at the nearest edge,
rather than stretching to the farthest corner (the default,
farthest-corner) */
}The size keywords — closest-side, farthest-side, closest-corner, farthest-corner (the default) — control exactly how far the gradient extends before reaching its final color, which matters a great deal for spotlight and vignette effects where the falloff distance is the entire point.
radial-gradient() as a subtle spotlight layered above a linear-gradient() base is a common technique for giving an otherwise flat colored section some visual depth without loading any actual image file at all, which keeps the page fast.border-radius — Including the Slash Syntax for Elliptical Corners
border-radius rounds an element's corners. In its simplest form, one value applies the same radius to all four corners; up to four values can target each corner independently, always in the order top-left, top-right, bottom-right, bottom-left (clockwise from the top-left, matching the same order used by margin and padding shorthand).
.a { border-radius: 8px; } /* all four corners */
.b { border-radius: 8px 16px; } /* top-left+bottom-right, top-right+bottom-left */
.c { border-radius: 8px 16px 8px 16px; } /* all four, explicit, clockwise from top-left */
.d { border-radius: 50%; } /* a perfect circle, IF width equals height */
.pill { border-radius: 9999px; } /* larger than half the element = a full pill/capsule shape */Elliptical corners — the slash syntax
A single value per corner always produces a quarter-circle corner. To make a corner an ellipse instead — a different horizontal and vertical radius on the same corner — border-radius supports a second, less commonly seen syntax: two full sets of values separated by a forward slash, where the first set controls each corner's horizontal radius and the second controls each corner's vertical radius.
.blob {
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
/* ^ horizontal radii, one per corner (TL TR BR BL)
^ vertical radii, one per corner (TL TR BR BL) */
}
/* A simpler, common real-world case — an elliptical "speech bubble" tail
or an asymmetric decorative blob shape behind a hero image: */
.organic-shape {
border-radius: 63% 37% 54% 46% / 43% 37% 63% 57%;
}Read the slash syntax as two independent lists rather than trying to reason about it corner by corner in one pass: everything before the slash is exactly the same four-value (or fewer) horizontal-radius shorthand from the simple form; everything after the slash is the equivalent list for vertical radius. Each corner then combines its horizontal value with its vertical value into one ellipse quadrant.
box-shadow — Offset, Blur, Spread, Inset, and Stacking Multiple Shadows
box-shadow accepts up to five values in order: horizontal offset, vertical offset, blur radius (optional), spread radius (optional), and color. Understanding exactly what blur and spread each do independently is the difference between guessing at shadow values and deliberately designing depth.
.card {
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.15);
/* ^ ^ ^ ^ ^
| | | | color (with alpha for a soft edge)
| | | spread radius — grows/shrinks the shadow's SIZE
| | blur radius — softens the shadow's EDGE
| vertical offset — positive = shadow falls downward
horizontal offset — positive = shadow falls rightward */
}.soft-edge {
box-shadow: 0 4px 20px 0 rgba(0,0,0,0.2);
/* blur: 20px, spread: 0 — a large, soft, feathered shadow that
fades out gradually. The shadow's outer boundary is still roughly
the size of the element, just blurred past that edge. */
}
.bigger-shadow {
box-shadow: 0 4px 4px 10px rgba(0,0,0,0.2);
/* spread: 10px, blur: 4px — the shadow's SHAPE itself grows 10px
larger on every side before any blur is applied, then only a
little softening is added. Produces a noticeably bigger, harder-
edged shadow rather than a soft glow. */
}inset — flipping the shadow to render inside the box
.input-field {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
/* the "inset" keyword flips the shadow to render INSIDE the border,
giving the element a pressed-in, recessed appearance — extremely
common on text inputs to visually suggest a "well" the cursor sits in */
}Stacking multiple shadows — comma-separated, first on top
Exactly like background-image, box-shadow accepts a comma-separated list of shadows, all rendered together. Real production design systems use this constantly to build convincing elevation — combining a tight, dark, low-blur shadow close to the element with a much larger, lighter, higher-blur shadow further out, mimicking how real shadows behave under both direct and ambient light.
.elevated-card {
box-shadow:
0px 1px 2px 0px rgba(0, 0, 0, 0.06), /* tight, sharp — close contact shadow */
0px 4px 8px 0px rgba(0, 0, 0, 0.08), /* medium spread — mid-range depth */
0px 12px 24px 0px rgba(0, 0, 0, 0.10); /* wide, soft — ambient falloff */
}
/* A single box-shadow with a big blur value LOOKS similar at a glance,
but reads as noticeably flatter and less "real" than three layered,
progressively larger and softer shadows — this stacked technique is
exactly what design systems like Material Design and most component
libraries use under the hood for their elevation scale. */inset) the border box. A large shadow can visually extend well past its element's edges and get silently clipped if any ancestor has overflow: hidden — a very common and confusing bug where a shadow "disappears" on one or more sides with no CSS error anywhere.A Design Review at an Austin E-Commerce Startup Catches a Cropped Hero Image
A front-end engineer ships the new homepage hero section: a full-width banner photo of a model wearing the season's new jacket line, with the headline and CTA button overlaid on top. It looks perfect on the engineer's laptop. In design QA the next morning, a teammate on a wide ultrawide monitor reports the model's face is completely cropped out of frame — only the jacket and shoulders are visible.
.hero {
height: 480px;
background-image: url("/hero-model.jpg");
background-size: cover;
background-position: center; /* the default center/center */
}What is actually happening
The photo is a tall portrait shot with the model's face in the upper third. On a normal laptop viewport, cover crops a moderate amount evenly from top and bottom around the default centered position, and the face survives inside the crop. On a much wider ultrawide screen, the hero's aspect ratio becomes far more extreme — to fully cover that much wider box at the same 480px height, cover has to crop dramatically more off the top and bottom, and with the position still centered, the face (positioned above center in the source photo) is exactly what gets cut.
.hero {
height: 480px;
background-image: url("/hero-model.jpg");
background-size: cover;
background-position: top center; /* anchor the crop to the top instead */
}
/* A more robust long-term fix the team adopts afterward: combine a
readability gradient with the photo, and rely on background-position
percentages tuned specifically to keep the subject's face in frame
across the widest realistic viewport, verified in QA at 3440px width: */
.hero-v2 {
height: 480px;
background:
linear-gradient(to bottom, rgba(0,0,0,0.15), rgba(0,0,0,0.45)),
url("/hero-model.jpg") top center / cover no-repeat;
}The team also adds a design QA checklist item specifically for any full-bleed background-size: cover photo: verify the crop at the narrowest supported width, the widest realistic width, and confirm background-position was deliberately chosen based on where the photo's actual subject sits — not left at the default center out of habit. This exact bug — a subject cropped out of frame on unusually wide or narrow viewports — is one of the most common visual QA findings for any hero-image- driven marketing page.
Four Misconceptions About Backgrounds and Borders
5 Interview Questions — With Complete Answers
Background & Border Mistakes Beginners Make Constantly
Rendering Bugs You Will Hit — And Exactly Why
🎯 Key Takeaways
- ✓background-color renders behind background-image, making it a genuinely useful fallback for slow or failed image loads — not just a simpler alternative.
- ✓background-size: cover fills the box completely and crops overflow; contain fits the entire image inside the box without cropping, potentially leaving empty space. Choosing the wrong one is a common source of unexpectedly cropped or letterboxed images.
- ✓The background shorthand resets every sub-property it does not mention — a later background: color; can silently wipe out an earlier background-image.
- ✓linear-gradient() angles start at 0deg pointing UP and increase clockwise — 90deg points right, the reverse of standard counter-clockwise math convention.
- ✓border-radius: 50% only produces a true circle on a square element — on any other box it produces an ellipse matching that box's own aspect ratio.
- ✓The border-radius slash syntax (horizontal radii / vertical radii) enables true elliptical corners, mainly used for organic blob shapes and decorative accents.
- ✓box-shadow blur radius softens the edge; spread radius grows the shadow's actual size. Realistic elevation is usually built by stacking several shadows with different offset/blur/spread values, not one large blur.
- ✓box-shadow never affects layout and can be silently clipped by any ancestor with overflow: hidden, auto, or scroll — a shadow "disappearing" on one side with no CSS error is almost always this.
What comes next
Module 23 opens the CSS Layout phase — Flexbox, the complete guide. The main-axis vs cross-axis mental model, justify-content, align-items, flex-wrap, and exactly how flex-grow/shrink/basis distribute space, worked through with real numeric examples.
Module 23 → Flexbox — The Complete GuideDiscussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.