RizTech Academy logo
RizTech Academy
CSS FoundationsLesson 7 of 825 min

Backgrounds, borders, radius and shadows

This is the decorative half of CSS: the properties that turn a correct layout into something that looks made on purpose. None of it is complicated. The parts worth learning properly are the ones with a trap — background sizing, and shadows that look cheap.

Backgrounds

.hero {
  background-color: #1a4d2e;
  background-image: url("images/shop.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

Or the shorthand, which resets everything you do not mention:

.hero {
  background: #1a4d2e url("images/shop.jpg") center / cover no-repeat;
}

The / before cover is required — it separates position from size and is the part people get wrong. Position first, then /, then size.

Always set a background-color behind a background-image. The image might fail, or not have loaded yet, and white text on nothing is invisible.

cover versus contain

background-size: cover;     /* fill the box, crop the overflow */
background-size: contain;   /* fit entirely, leave empty space */
background-size: 100% auto;
background-size: 200px 100px;

cover is what you want for a hero: the box is always filled. It crops, so the edges of the image are lost — and on a narrow phone in portrait a wide landscape photo loses most of its sides. If the subject is off-centre, say so:

background-position: 70% center;

contain never crops and leaves gaps, which is right for a logo and wrong for a hero.

A background image is not content

This is the rule that matters. A background-image has no alt, is not announced by a screen reader, and is not indexed. So:

Use background-image for decoration — a texture, a gradient, a hero the text sits on top of.

Use <img> for content — a product photograph, a person, anything a visitor would want to see or would miss if it were absent.

The test from module 1 still applies: if the image carries information, it needs an alt, so it needs to be an <img>.

An <img> is also better for performance: it can be lazy-loaded, it can carry srcset for different screen sizes, and the browser can prioritise it. A CSS background is discovered later, after the stylesheet has been parsed.

Gradients

background: linear-gradient(to bottom, #1a4d2e, #0f3d20);
background: linear-gradient(135deg, #1a4d2e 0%, #2d7a4a 50%, #0f3d20 100%);
background: radial-gradient(circle at top right, #2d7a4a, #1a4d2e);

A gradient is an image, so it goes in background-image and can be layered with one. This is the standard trick for keeping text readable on a photo:

.hero {
  background:
    linear-gradient(rgb(0 0 0 / 0.55), rgb(0 0 0 / 0.55)),
    url("images/shop.jpg") center / cover no-repeat;
  color: white;
}

Layers are listed front to back — the first one is on top. That is the opposite of what most people guess, and it is why the dark overlay goes first.

A two-stop gradient with the same colour twice is how you get a flat tint. It is much better than a separate overlay div, and better than opacity on the image, which would fade the text too.

One accessibility note: a gradient over a photo is how you make white text pass contrast. Check it in devtools' Accessibility pane rather than trusting your eye — a photo's brightness varies across it, and text that is readable over the dark part may fail over the light part.

Borders

border: 2px solid #ddd;                 /* width | style | colour */
border-width: 2px;
border-style: solid;                    /* dashed dotted double none */
border-color: #ddd;
border-block-end: 1px solid #eee;       /* logical: the bottom, in English */

border-style is required. border: 2px #ddd with no style draws nothing, because the default style is none. That is a common five-minute bug and devtools shows the declaration accepted, because it is valid — just invisible.

A border adds to the element's size, so it is part of the box-sizing story from the box-model lesson. With border-box it comes out of the content area instead.

outline is not a border

outline: 2px solid #1a4d2e;
outline-offset: 2px;

An outline is drawn outside the border, takes up no space, and does not affect layout. Which is exactly why it is used for focus rings — adding one does not shift the page.

It also means an outline can be a useful debugging tool: * { outline: 1px solid red } shows you every box without moving anything, where border would reflow the entire page.

border-radius

border-radius: 8px;
border-radius: 8px 8px 0 0;          /* TRouBLe again: TL TR BR BL */
border-radius: 50%;                  /* a circle, on a square element */
border-radius: 999px;                /* a pill — any large value works */

Note the clockwise order starts at top-left here, not top, which is different from padding and margin.

border-radius: 50% makes a circle only if the element is square. On a rectangle it gives an ellipse. For a circular avatar:

.avatar {
  width: 48px;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
}

aspect-ratio: 1 guarantees square without hard-coding the height, and object-fit: cover stops a non-square photo being squashed — which is the default and looks terrible.

overflow: hidden on a rounded parent is what clips a child's corners to match. Without it, an image inside a rounded card has square corners poking out.

Shadows

box-shadow: 0 1px 3px rgb(0 0 0 / 0.12);
/*          x  y  blur  colour */
box-shadow: 0 4px 6px rgb(0 0 0 / 0.1), 0 10px 20px rgb(0 0 0 / 0.08);
box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.06);
box-shadow: 0 0 0 3px rgb(26 77 46 / 0.4);     /* no blur: a ring */

Four values: horizontal offset, vertical offset, blur, colour. A fifth, spread, comes before the colour and is rarely useful.

What makes a shadow look cheap, and this is the whole reason this section exists:

  • Too dark. rgb(0 0 0 / 0.5) is a smudge. Real shadows on a white page are subtle — 0.08 to 0.15 alpha.
  • No vertical offset. box-shadow: 0 0 10px black glows in all directions, which no light source does. Light comes from above: a positive y and x of 0.
  • One layer. Real shadows are a tight dark one close to the object and a wide soft one further out. Two or three layers with increasing blur and decreasing alpha is what expensive interfaces do.
/* a believable card */
.card {
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.08),
    0 4px 12px rgb(0 0 0 / 0.06);
}
/* lifted on hover */
.card:hover {
  box-shadow:
    0 2px 4px rgb(0 0 0 / 0.08),
    0 12px 28px rgb(0 0 0 / 0.1);
}

Shadows stack front to back like backgrounds, and they do not affect layout at all — so a shadow can overlap a neighbour, and a hover that only changes the shadow never causes reflow, which makes it cheap to animate.

text-shadow takes the same values minus inset. Use it sparingly; one legitimate case is text over a photo where a gradient overlay is not enough.

The ring pattern

:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgb(26 77 46 / 0.4);
}

A zero-blur shadow is a solid ring. It is a common focus style — but note that box-shadow is invisible in Windows high-contrast mode, where outline is not. For focus specifically, prefer outline with outline-offset, or use both.

filter and backdrop-filter

filter: grayscale(1);
filter: brightness(0.8) blur(2px);
backdrop-filter: blur(10px);       /* blurs what is BEHIND the element */

backdrop-filter is the frosted-glass effect on a sticky header. It is expensive to render — noticeably so on a mid-range phone — so use it on one small element, never on something large or animated.

filter: grayscale(1) on hover for a photo grid is a cheap, effective touch.

Check your work

The shorthand's /. Separates position from size: center / cover.

Why always set a background colour behind an image. The image may fail or not have arrived.

cover versus contain. Fill and crop, versus fit and leave gaps.

When a background image is wrong. When it carries information — that needs an <img> with alt.

Which background layer is on top. The first one listed.

How to keep text readable on a photo. A translucent gradient layered above it, not opacity.

Why border: 2px #ddd draws nothing. border-style defaults to none.

Why outline is used for focus. It takes no space, so adding it does not shift the layout.

border-radius order. Clockwise from top-left.

Why border-radius: 50% is not always a circle. It needs a square element — aspect-ratio: 1.

What clips a child's corners. overflow: hidden on the rounded parent.

Three things that make a shadow look cheap. Too dark, no vertical offset, one layer.

Why a shadow is cheap to animate. It does not affect layout.

Where box-shadow focus rings fail. Windows high-contrast mode.

Why to use backdrop-filter sparingly. It is expensive on a mid-range phone.

Practice

  1. Set a hero background with the shorthand. Leave out the / before cover and see what happens.
  2. Remove the background-color and throttle to Slow 4G. Watch the text before the image arrives.
  3. Compare cover and contain on the same box at two different aspect ratios.
  4. Set background-position: 70% center on an off-centre subject and resize.
  5. Put a photo on a page as a background-image, then as an <img> with alt. Listen to both with a screen reader.
  6. Layer a dark gradient over a photo. Swap the layer order and explain the result.
  7. Check the contrast of white text over your hero in devtools' Accessibility pane, at both a dark and a light part of the photo.
  8. Write border: 2px #ddd and find out why nothing appears.
  9. Add * { outline: 1px solid red }, then try the same with border and compare how much the page moves.
  10. Make a circular avatar from a non-square photo. Then remove object-fit: cover.
  11. Round a card's corners and put an image at its top edge. Fix the poking corners.
  12. Write box-shadow: 0 0 10px black, then a two-layer subtle shadow. Compare.
  13. Animate only the shadow on hover and confirm in devtools' Performance panel that nothing reflows.
  14. Build a focus ring with box-shadow, then with outline and outline-offset.
  15. Add backdrop-filter: blur(10px) to a sticky header and scroll on a phone. Note whether it stutters.

Official documentation

Next: typography, and what a web font actually costs.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship