A box is rarely finished when its content and spacing are right. The last layer of polish comes from the edges: a border to define the boundary, a shadow to lift the box off the page, and a radius to soften the corners. All three are simple properties once you know their syntax.
What border styles are there?
A border needs a width, a style and a colour, and the style is what makes it visible — a border with a width but no style is invisible.
.card {
border: 1px solid #e2e2e2; /* width style colour */
border-top: 2px dashed #999; /* one side only */
border-width: 1px 2px 1px 2px; /* top right bottom left */
border-color: #ddd #ccc; /* vertical then horizontal */
border-style: solid;
}
There are eight border styles: solid, dashed, dotted, double, groove, ridge, inset and outset. Solid is the one you will use almost every time; dashed and dotted are useful for indicating something provisional, and double gives a classic "rule" look on a box. The directional shorthands follow the same order everywhere in CSS: top, right, bottom, left.
One detail worth knowing: a border takes up space in the box, and under the default content-box sizing it is added outside the content. Under border-box it is taken out of the width you set. This is the second reason almost every project sets border-box.
How does box-shadow work?
The syntax is an offset x, an offset y, a blur radius, a spread radius and a colour, in that order. The first two move the shadow, the blur softens its edge, and the spread grows or shrinks the shadow shape before the blur is applied.
.card {
box-shadow:
0 1px 2px rgb(0 0 0 / 0.08), /* a subtle lift */
0 8px 24px rgb(0 0 0 / 0.06); /* a larger, softer shadow */
}
Two shadows are separated by a comma, and each one paints behind the previous, which is how the layered look of a raised card is built. Multiple shadows are worth using for anything that floats: a tight shadow for the contact with the surface and a wide one for the ambient light.
An inset keyword makes the shadow draw inside the box instead of outside, which is how a pressed or inset effect is created.
.input {
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.12);
}
.card:hover {
box-shadow: 0 12px 28px rgb(0 0 0 / 0.14);
}
Keep the vertical offset non-zero. A shadow with no offset, only a blur, looks like a glow rather than a shadow, and it does not read as a raised surface.
How does border-radius work?
It takes one length for all four corners, or up to four for top-left, top-right, bottom-right and bottom-left. A percentage is relative to the box's own dimensions, which is what makes elliptical corners possible.
.card { border-radius: 8px; }
.pill { border-radius: 999px; } /* fully rounded ends */
.circle { border-radius: 50%; } /* only square if width equals height */
.asym { border-radius: 12px 4px 12px 4px; }
The large value trick — 999px on a pill-shaped element — works because the radius is clamped to half the smaller of the width and height, so any value above that produces a full semicircle. For a circle, use 50 percent and make sure the element is square, otherwise you get an ellipse.
There is a subtlety with percentage radii on a non-square box: the horizontal and vertical radii are scaled independently, so the corner shape is an ellipse rather than a circle. If you need a true circle, set equal width and height.
Can a border be a gradient?
Not directly, but there is a well-known technique that fakes it using a background and an inner element, and it has become much simpler with the addition of multiple backgrounds.
.gradient-border {
border: 2px solid transparent;
background:
linear-gradient(#fff, #fff) padding-box,
linear-gradient(45deg, #800d4d, #ff9ec7) border-box;
border-radius: 12px;
}
The two background layers are clipped differently: the first is clipped to the padding box, the second to the border box, so the gradient shows only in the border area. It is a good trick, and it is worth understanding rather than copying blindly.
How do you style a border on only one side?
Every border property has a long form that takes four values in a fixed order - top, right, bottom, left - and a shorthand that takes one value for all four. To set one side you use the side-specific long form.
.card {
border-style: solid;
border-width: 1px;
border-color: #d8e0e8;
/* only the top edge, in a different colour and twice as thick */
border-top: 3px solid #185ca5;
}
/* the same thing written as a long hand */
.card {
border-top-width: 3px;
border-top-style: solid;
border-top-color: #185ca5;
}The order of the four values matters and is worth memorising, because getting it wrong is a classic source of a border that looks like it is on the wrong side. It is top, then right, then bottom, then left - the same clockwise order as margin and padding. Three values mean top, both sides, then bottom.
For an accent bar on the side of a card, the technique is to set a transparent border on every side and then give one side a colour. The border still occupies its space, so the layout does not shift, and the other three edges stay invisible rather than being absent.
.notice {
border: 1px solid transparent;
border-inline-start: 4px solid #c9821a;
padding: 0.75rem 1rem;
background: #fdf6ea;
}One caveat about the shorthand: border: none resets the width, the style and the colour of all four sides at once. That is usually what you want when removing a border, but it also means a later rule setting only border-color will not bring the border back - the style is still none, and a border with no style is not drawn at all.
Quick reference
- A border needs a style as well as a width, or it is invisible.
box-shadowtakes x, y, blur, spread and colour; several shadows stack.- Keep the vertical offset non-zero or it reads as a glow.
insetdraws a shadow inside the box.border-radiustakes one to four values, and 999px on a pill gives full round ends.- Percentage radii are scaled per axis, so a circle needs a square element.
Try it yourself: build a card with a one-pixel border, a two-layer shadow and a radius of twelve pixels. Then hover it and change the shadow to a larger offset. Finally, set the border to a gradient using the padding-box and border-box technique, and check in the developer tools that the border area is the only part that shows the colour.