Dec 19

CSS box-decoration-break

Deal with styling for elements that span multiple lines.

By Kilian Valkhof

box-decoration-break is a CSS property that lets you decide what the decorations of a box should do if that box is broken across multiple lines.

Now that sentence probably means nothing if you don't already know what box-decoration-break does, so let's back up a whole bunch of steps and figure out why this is something that needs to be decided on.

What is a box?

Let's start with the first part: boxes. In CSS, everything is a box. Every element in your DOM is a box, every pseudo-element you add in CSS is a box, and even every text node is a box.

In other words, the entire web page is made up of rectangles. There are different types of rectangles, but for box decoration-break, there are two types we need to know about: block boxes and inline boxes. In CSS, elements can either be "block" or "inline."

Example of a block element
.block-el {
text-align: center;
aspect-ratio: 1/1;
max-block-size: 200px;
display: grid;
place-items: center;
border: 4px solid dodgerblue;
padding: 40px
}
This is a block box

When an element is a block element, it takes up the entire width of the parent element, and if you add a new block element after it, that will be placed below the first block element. Things like divs, headings, and paragraphs are block elements: They stack on top of each other.

Inline elements, on the other hand, only take up the space they need and sit "inline" with the surrounding text. Examples include spans, links, and strong elements.

Example of an inline elememt
.inline-el {
line-height: 2.5;
text-align: center;
}

.inline-el span {
border: 4px solid dodgerblue;
padding: 4px 10px
}

Hello, this is a long unbroken inline box in a text line.

What are decorations?

In CSS, (box-)decorations are things like borders, outlines, backgrounds, and shadows (but also margin, padding, and clip-path). They let you change the box from a transparent rectangle into a nicely glowing pill button, a floating card, or a recessed input field.

Usually, these decorations are applied to all sides of the box: top, right, bottom, and left, though you can also apply borders and outlines only to specific sides.

Simple decorated box
.decorated {
font-size: 1.5rem;
font-weight: bold;
color: white;
outline: 5px dashed red;
border: 5px dashed green;
padding: 20px;
aspect-ratio: initial;
background: repeating-linear-gradient(45deg, red, red 10px, green 10px, green 20px);
border-radius: 999px;
box-shadow: 0 0 20px yellow, 0 0 10px 5px inset yellow;
}
This is a decorated box

What’s a break?

Most inline elements are short and fit start-to-end in a single line. If an inline element is very long, it will automatically wrap across multiple lines.

To do that, the browser first renders the inline element as a very wide rectangle that includes all the contents in a single line. Then, it will break that rectangle up into however many lines it needs to make the content fit the screen.

This breaking is where things might not happen as you expect. Let’s say you have an inline box with a blue border on all sides: top, right, bottom, and left. Those borders are exactly where you think they are when the browser first renders that very long inline element.

Initial box styles
.initial-box {
border:4px solid dodgerblue;
padding: 4px 10px;
}

This is a long unbroken inline box

But then the browser chops it up into multiple segments, and while the element still has the border at the left and right sides, there’s now a bunch of new left and right sides to this element, and they look awful.

Broken appearance box styles
.broken-box {
width: 100px;
}

.broken-box span {
border:4px solid dodgerblue;
padding: 4px 10px;
}

This is a long unbroken inline box

Enter box-decoration-break

With box-decoration-break, we can tell the browser how to handle those breaks in one of two ways:

Slice

This is the default value, and it’s like the example above. The browser renders the inline element in one long line and then chops that line up into multiple segments, leading to “frayed” edges on either side for everything but the first and last lines.

Clone

Setting box-decoration-break to clone will take those decorations and clone them to each segment, meaning that each line is turned into its own little box.

Using box-decoration-break: clone
.box-decoration-break-clone {
width: 100px;
}

.box-decoration-break-clone span {
border:4px solid dodgerblue;
padding: 4px 10px;

box-decoration-break: clone;
}

This is a long broken inline box

Not only does this cause the borders you might have expected to appear again, also see how the padding on the left and right sides are now also applied to each line, rather than only to the beginning and end. 

A practical application of this is when you want to create a marker-like effect on some text to make it seem like you have highlighted a couple of lines.

Here’s that effect without cloned box-decoration-break.

Marker effect - no box-decoration-break
.marker-1 {
width: 250px;
line-height: 1.5;
font-size: 1.75rem;
}

.marker-1 span {
padding-inline: 20px;
background: linear-gradient(105deg, transparent 10px, cyan 10px, cyan calc(100% - 10px), transparent calc(100% - 10px));
}

This is a long broken inline box

And here it is with cloned box-decoration-break.

Marker effect - with box-decoration-break
.marker-2 {
width: 250px;
line-height: 1.5;
font-size: 1.75rem;
}

.marker-2 span {
padding-inline: 20px;
background: linear-gradient(105deg, transparent 10px, cyan 10px, cyan calc(100% - 10px), transparent calc(100% - 10px));

box-decoration-break: clone;
}

This is a long broken inline box

The re-introduction

As I said at the start of this article, you might have already used this feature! It’s been available in Firefox since 2014, Chromium-based browsers since 2013, and Safari since 2013. 

The Chromium and Safari implementations, however, had the -webkit- prefix because they only had partial support. It only supported the box-decoration-break of inline boxes. Inline boxes are where you encounter this issue most frequently so there is a high chance that you’ve already used this at some point in the last decade. 

But there are cases where block boxes can also get broken apart: in (infrequently used) multi-column layout. Chrome implemented support for that earlier this year and thus removed the prefix, while Safari has no support for that yet and still has the prefix. 

To support both browsers, always first write the prefixed version:

-webkit-box-decoration-break: clone;
box-decoration-break: clone;

We do this because in CSS, the last declaration wins. When that last declaration is the unprefixed one, as soon as Safari also adds support, it will default to using the proper, full implementation. Until that time, Safari doesn’t understand box-decoration-break and will ignore it, using only the prefixed version.

Block-level box-decoration-break for multi-column layout.

In the same way that inline boxes can get split up across multiple horizontal lines if they don’t fit horizontally, block boxes can get split up across multiple columns if they don’t fit in a single column vertically, like the following demo adapted from MDN:

Multi-column and box-decoration-break
/* our block style */
.multi-col span {
display: block;
font-size:1.5rem;
font-weight:bold;
color: white;
outline: 5px dashed red;
border: 5px dashed green;
padding: 20px;
aspect-ratio: initial;
background: repeating-linear-gradient(45deg, red, red 10px, green 10px, green 20px);
border-radius: 999px;
box-shadow: 0 0 20px yellow, 0 0 10px 5px inset yellow;
}

.base {
width: 33%;
}

.columns {
columns: 3;
}

.default {
box-decoration-break: slice;
}

.clone {
box-decoration-break: clone;
}
The quick orange fox

'box-decoration-break: slice'

The quick orange fox

'box-decoration-break: clone'

The quick orange fox

That’s box-decoration-break

When an element is broken across multiple lines (or columns), box-decoration-break enables you to decide whether each segment should clone the decorations for themselves or if the box should remain sliced.

It’s fully available in Chromium-based browsers and Firefox. In Safari you can use it for inline boxes with the -webkit- prefix. If you want to learn more, here are some additional resources:

Kilian Valkhof

Kilian Valkhof

Kilian is a web developer from the netherlands, building Polypane.app, the browser for developers.

Kilian selected Giving Green Fund for an honorary donation of $50

Giving Green Fund

The climate crisis sits at the heart of many problems around the world, increasing inequality and disproportionately affecting those least responsible for it. If we want to keep earth livable for our children, we need to fight it at many fronts. Giving Green is a fund that research projects and funds those most effective.