25 CSS Blockquotes15 / 25
Inline Highlighted Text CSS Blockquote
A quote where the key phrases carry a painted highlight — built on the semantic <mark> element with the one property that makes multi-line highlights survive: box-decoration-break: clone, which re-applies the padding and rounded corners on every wrapped fragment instead of slicing the highlight open at line breaks. Two highlight voices are shown — a solid wash and a skewed 'hand-swiped' variant via a transformed ::before — and the demo explains when <mark> is semantically right versus a styled .
Published Updated
The code
<section class="bq-15" aria-label="Inline highlighted text blockquote demo">
<div class="bq-15__stage">
<figure class="bq-15__quote">
<p class="bq-15__kicker">Annotated · from the postmortem</p>
<blockquote>
<p>The outage taught us that <mark class="bq-15__hl">alerting is a design problem, not a tooling problem</mark> — we had forty dashboards and zero answers. The fix wasn't another graph; it was deciding, in advance, <mark class="bq-15__hl bq-15__hl--swipe">which three numbers mean the site is healthy</mark> and paging on nothing else.</p>
</blockquote>
<figcaption class="bq-15__by">Incident review, <cite>Q3 Reliability Report</cite> — highlights by the SRE lead</figcaption>
</figure>
<p class="bq-15__chip" aria-hidden="true"><mark> · box-decoration-break:clone · skewed ::before swipe</p>
</div>
</section><section class="bq-15" aria-label="Inline highlighted text blockquote demo">
<div class="bq-15__stage">
<figure class="bq-15__quote">
<p class="bq-15__kicker">Annotated · from the postmortem</p>
<blockquote>
<p>The outage taught us that <mark class="bq-15__hl">alerting is a design problem, not a tooling problem</mark> — we had forty dashboards and zero answers. The fix wasn't another graph; it was deciding, in advance, <mark class="bq-15__hl bq-15__hl--swipe">which three numbers mean the site is healthy</mark> and paging on nothing else.</p>
</blockquote>
<figcaption class="bq-15__by">Incident review, <cite>Q3 Reliability Report</cite> — highlights by the SRE lead</figcaption>
</figure>
<p class="bq-15__chip" aria-hidden="true"><mark> · box-decoration-break:clone · skewed ::before swipe</p>
</div>
</section>.bq-15,
.bq-15 *,
.bq-15 *::before,
.bq-15 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-15 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.985 0.004 95);
--ink: oklch(0.25 0.015 80);
--mut: oklch(0.54 0.015 80);
--hl: oklch(0.88 0.16 95);
--hl2: oklch(0.85 0.1 340);
font-family: Georgia,'Times New Roman',serif;
color: var(--ink);
}
.bq-15__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: var(--bg);
overflow-y: auto;
}
.bq-15__quote {
max-width: 58ch;
}
.bq-15__kicker {
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--mut);
margin-bottom: 16px;
}
.bq-15__quote blockquote p {
font-size: clamp(19px,2.5vw,25px);
line-height: 1.68;
text-wrap: pretty;
}
.bq-15__hl {
background: color-mix(in oklch,var(--hl) 55%,transparent);
padding: .08em .3em;
border-radius: .3em;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
color: inherit;
}
.bq-15__hl--swipe {
position: relative;
background: none;
padding: 0;
}
.bq-15__hl--swipe::before {
content: '';
position: absolute;
inset: -.04em -.28em;
background: color-mix(in oklch,var(--hl2) 62%,transparent);
border-radius: .4em .2em .45em .25em;
transform: skewX(-8deg) rotate(-.6deg);
z-index: -1;
}
.bq-15__by {
margin-top: 20px;
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 13px;
color: var(--mut);
}
.bq-15__by cite {
font-style: italic;
}
.bq-15__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(0 0 0/.1);
border-radius: 99px;
background: oklch(1 0 0);
}
@media (prefers-reduced-motion: reduce) {
.bq-15 * {
transition-duration: .01ms !important;
}
}.bq-15,
.bq-15 *,
.bq-15 *::before,
.bq-15 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-15 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.985 0.004 95);
--ink: oklch(0.25 0.015 80);
--mut: oklch(0.54 0.015 80);
--hl: oklch(0.88 0.16 95);
--hl2: oklch(0.85 0.1 340);
font-family: Georgia,'Times New Roman',serif;
color: var(--ink);
}
.bq-15__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: var(--bg);
overflow-y: auto;
}
.bq-15__quote {
max-width: 58ch;
}
.bq-15__kicker {
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--mut);
margin-bottom: 16px;
}
.bq-15__quote blockquote p {
font-size: clamp(19px,2.5vw,25px);
line-height: 1.68;
text-wrap: pretty;
}
.bq-15__hl {
background: color-mix(in oklch,var(--hl) 55%,transparent);
padding: .08em .3em;
border-radius: .3em;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
color: inherit;
}
.bq-15__hl--swipe {
position: relative;
background: none;
padding: 0;
}
.bq-15__hl--swipe::before {
content: '';
position: absolute;
inset: -.04em -.28em;
background: color-mix(in oklch,var(--hl2) 62%,transparent);
border-radius: .4em .2em .45em .25em;
transform: skewX(-8deg) rotate(-.6deg);
z-index: -1;
}
.bq-15__by {
margin-top: 20px;
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 13px;
color: var(--mut);
}
.bq-15__by cite {
font-style: italic;
}
.bq-15__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(0 0 0/.1);
border-radius: 99px;
background: oklch(1 0 0);
}
@media (prefers-reduced-motion: reduce) {
.bq-15 * {
transition-duration: .01ms !important;
}
}Here's a working CSS Blockquote from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Inline Highlighted Text CSS Blockquote
Source: https://codefronts.com/snippets/css-blockquotes/highlighted-run/
A quote where the key phrases carry a painted highlight — built on the semantic <mark> element with the one property that makes multi-line highlights survive: box-decoration-break: clone, which re-applies the padding and rounded corners on every wrapped fragment instead of slicing the highlight open at line breaks. Two highlight voices are shown — a solid wash and a skewed 'hand-swiped' variant via a transformed ::before — and the demo explains when <mark> is semantically right versus a styled .
## HTML
```html
<section class="bq-15" aria-label="Inline highlighted text blockquote demo">
<div class="bq-15__stage">
<figure class="bq-15__quote">
<p class="bq-15__kicker">Annotated · from the postmortem</p>
<blockquote>
<p>The outage taught us that <mark class="bq-15__hl">alerting is a design problem, not a tooling problem</mark> — we had forty dashboards and zero answers. The fix wasn't another graph; it was deciding, in advance, <mark class="bq-15__hl bq-15__hl--swipe">which three numbers mean the site is healthy</mark> and paging on nothing else.</p>
</blockquote>
<figcaption class="bq-15__by">Incident review, <cite>Q3 Reliability Report</cite> — highlights by the SRE lead</figcaption>
</figure>
<p class="bq-15__chip" aria-hidden="true"><mark> · box-decoration-break:clone · skewed ::before swipe</p>
</div>
</section>
```
## CSS
```css
.bq-15,
.bq-15 *,
.bq-15 *::before,
.bq-15 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-15 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.985 0.004 95);
--ink: oklch(0.25 0.015 80);
--mut: oklch(0.54 0.015 80);
--hl: oklch(0.88 0.16 95);
--hl2: oklch(0.85 0.1 340);
font-family: Georgia,'Times New Roman',serif;
color: var(--ink);
}
.bq-15__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: var(--bg);
overflow-y: auto;
}
.bq-15__quote {
max-width: 58ch;
}
.bq-15__kicker {
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--mut);
margin-bottom: 16px;
}
.bq-15__quote blockquote p {
font-size: clamp(19px,2.5vw,25px);
line-height: 1.68;
text-wrap: pretty;
}
.bq-15__hl {
background: color-mix(in oklch,var(--hl) 55%,transparent);
padding: .08em .3em;
border-radius: .3em;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
color: inherit;
}
.bq-15__hl--swipe {
position: relative;
background: none;
padding: 0;
}
.bq-15__hl--swipe::before {
content: '';
position: absolute;
inset: -.04em -.28em;
background: color-mix(in oklch,var(--hl2) 62%,transparent);
border-radius: .4em .2em .45em .25em;
transform: skewX(-8deg) rotate(-.6deg);
z-index: -1;
}
.bq-15__by {
margin-top: 20px;
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 13px;
color: var(--mut);
}
.bq-15__by cite {
font-style: italic;
}
.bq-15__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(0 0 0/.1);
border-radius: 99px;
background: oklch(1 0 0);
}
@media (prefers-reduced-motion: reduce) {
.bq-15 * {
transition-duration: .01ms !important;
}
}
```Here's a working CSS Blockquote from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Inline Highlighted Text CSS Blockquote
Source: https://codefronts.com/snippets/css-blockquotes/highlighted-run/
A quote where the key phrases carry a painted highlight — built on the semantic <mark> element with the one property that makes multi-line highlights survive: box-decoration-break: clone, which re-applies the padding and rounded corners on every wrapped fragment instead of slicing the highlight open at line breaks. Two highlight voices are shown — a solid wash and a skewed 'hand-swiped' variant via a transformed ::before — and the demo explains when <mark> is semantically right versus a styled .
## HTML
```html
<section class="bq-15" aria-label="Inline highlighted text blockquote demo">
<div class="bq-15__stage">
<figure class="bq-15__quote">
<p class="bq-15__kicker">Annotated · from the postmortem</p>
<blockquote>
<p>The outage taught us that <mark class="bq-15__hl">alerting is a design problem, not a tooling problem</mark> — we had forty dashboards and zero answers. The fix wasn't another graph; it was deciding, in advance, <mark class="bq-15__hl bq-15__hl--swipe">which three numbers mean the site is healthy</mark> and paging on nothing else.</p>
</blockquote>
<figcaption class="bq-15__by">Incident review, <cite>Q3 Reliability Report</cite> — highlights by the SRE lead</figcaption>
</figure>
<p class="bq-15__chip" aria-hidden="true"><mark> · box-decoration-break:clone · skewed ::before swipe</p>
</div>
</section>
```
## CSS
```css
.bq-15,
.bq-15 *,
.bq-15 *::before,
.bq-15 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-15 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.985 0.004 95);
--ink: oklch(0.25 0.015 80);
--mut: oklch(0.54 0.015 80);
--hl: oklch(0.88 0.16 95);
--hl2: oklch(0.85 0.1 340);
font-family: Georgia,'Times New Roman',serif;
color: var(--ink);
}
.bq-15__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: var(--bg);
overflow-y: auto;
}
.bq-15__quote {
max-width: 58ch;
}
.bq-15__kicker {
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--mut);
margin-bottom: 16px;
}
.bq-15__quote blockquote p {
font-size: clamp(19px,2.5vw,25px);
line-height: 1.68;
text-wrap: pretty;
}
.bq-15__hl {
background: color-mix(in oklch,var(--hl) 55%,transparent);
padding: .08em .3em;
border-radius: .3em;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
color: inherit;
}
.bq-15__hl--swipe {
position: relative;
background: none;
padding: 0;
}
.bq-15__hl--swipe::before {
content: '';
position: absolute;
inset: -.04em -.28em;
background: color-mix(in oklch,var(--hl2) 62%,transparent);
border-radius: .4em .2em .45em .25em;
transform: skewX(-8deg) rotate(-.6deg);
z-index: -1;
}
.bq-15__by {
margin-top: 20px;
font-family: 'Segoe UI',system-ui,sans-serif;
font-size: 13px;
color: var(--mut);
}
.bq-15__by cite {
font-style: italic;
}
.bq-15__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(0 0 0/.1);
border-radius: 99px;
background: oklch(1 0 0);
}
@media (prefers-reduced-motion: reduce) {
.bq-15 * {
transition-duration: .01ms !important;
}
}
```How this works
The naive version — background on a span — breaks the moment the phrase wraps: the middle lines lose their padding and corners. One property fixes it:
mark{
background:color-mix(in oklch, var(--hl) 38%, transparent);
padding:.1em .32em; border-radius:.3em;
-webkit-box-decoration-break:clone;
box-decoration-break:clone; /* every fragment gets the box */
color:inherit; /* kill the default black-on-yellow */
}When an inline box fragments across lines, box-decoration-break:slice (the default) treats the fragments as one sliced-open box — no left padding on continuation lines, no rounded corners mid-phrase. clone re-draws the full box decoration on each fragment, which is what a human with a highlighter pen actually produces. Safari still wants the -webkit- prefix.
Semantics: <mark> means 'relevant in the current context' — search hits, the phrase this paragraph analyses, the words a reviewer flagged. If the emphasis belongs to the AUTHOR's voice, that's <em>/<strong>, styled however you like. The second variant here (the swiped look) is the same mark element with a skewed, slightly rotated ::before behind the text — the paint layer is decoration, so the semantics don't change with the styling.
Make it yours
- Highlight hue: yellow reads 'annotation', mint reads 'success/insight', pink reads 'editorial voice'. Keep alpha ~35–45% so descenders stay readable through the wash.
- Animated reveal: transition background-size from 0% 100% to 100% 100% on a left-anchored gradient — highlights that sweep in as the section scrolls into view (pair with a scroll-driven animation).
- Underline hybrid: swap the wash for background:linear-gradient(transparent 62%, var(--hl) 62%) — the 'floating marker underline' that sits behind only the bottom of the glyphs.
- Reader affordance: add title or a footnote link on marks used as annotations — visual highlight alone doesn't tell readers WHY it's marked.
Gotchas — read before shipping
- Browser default <mark> is pure yellow with black text — it ignores your dark theme and fails contrast on colored backgrounds. Always restyle both background AND color.
- box-decoration-break needs the -webkit- prefix in Safari to this day; without it, iOS shows sliced highlights.
- Don't use <mark> for brand-colored decoration of random words — screen readers can announce marks (VoiceOver does), so gratuitous marks become gratuitous noise.
- Padding on inline elements doesn't push line-height apart vertically — .1em of block padding overlaps adjacent lines slightly; keep it ≤ .15em or bump the quote's line-height.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by oklch(), color-mix(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
box-decoration-break:clone — Chrome 130 unprefixed (22 with -webkit-), Safari via prefix, Firefox 32. Ship both lines and coverage is effectively total; the floor is oklch/color-mix cosmetics.