25 CSS Blockquotes06 / 25
Animated CSS Gradient Border Blockquote
A quote card wrapped in a slowly rotating conic-gradient border — the effect every 'top CSS tricks' video promises, done the 2026 way: a registered @property custom property (--bq06-angle) makes the gradient's angle itself animatable, so the colors orbit the card with zero JavaScript and zero pseudo-element hacks. The border is painted by a two-layer background (padding-box fill over border-box gradient), which — unlike outline or box-shadow tricks — respects border-radius perfectly and costs one element.
Published
The code
<section class="bq-06" aria-label="Animated gradient border blockquote demo">
<div class="bq-06__stage">
<figure class="bq-06__card">
<blockquote>
<p>“We shipped the redesign in six weeks. The border animation in this quote card took two of them — and it was worth every hour.”</p>
</blockquote>
<figcaption class="bq-06__by">
<span class="bq-06__dot" aria-hidden="true"></span>
<span><strong>Marcus Webb</strong> · Design Engineer, Meridian</span>
</figcaption>
</figure>
<p class="bq-06__chip" aria-hidden="true">@property <angle> · conic-gradient border-box · 0 JS</p>
</div>
</section><section class="bq-06" aria-label="Animated gradient border blockquote demo">
<div class="bq-06__stage">
<figure class="bq-06__card">
<blockquote>
<p>“We shipped the redesign in six weeks. The border animation in this quote card took two of them — and it was worth every hour.”</p>
</blockquote>
<figcaption class="bq-06__by">
<span class="bq-06__dot" aria-hidden="true"></span>
<span><strong>Marcus Webb</strong> · Design Engineer, Meridian</span>
</figcaption>
</figure>
<p class="bq-06__chip" aria-hidden="true">@property <angle> · conic-gradient border-box · 0 JS</p>
</div>
</section>@property --bq06-angle {
syntax: '<angle>';
initial-value: 40deg;
inherits: false;
}
.bq-06,
.bq-06 *,
.bq-06 *::before,
.bq-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-06 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.15 0.012 270);
--card: oklch(0.2 0.015 270);
--ink: oklch(0.96 0.008 270);
--mut: oklch(0.66 0.02 270);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-06__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(70% 55% at 50% 120%,oklch(0.24 0.05 300/.5),transparent),var(--bg);
overflow-y: auto;
}
.bq-06__card {
width: min(100%,520px);
padding: clamp(24px,4vw,36px);
border: 1.5px solid transparent;
border-radius: 20px;
background: linear-gradient(var(--card),var(--card)) padding-box,conic-gradient(from var(--bq06-angle),oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25)) border-box;
animation: bq06-spin 7s linear infinite;
box-shadow: 0 24px 60px oklch(0 0 0/.45);
}
@keyframes bq06-spin {
to {
--bq06-angle: 400deg;
}
}
.bq-06__card blockquote p {
font-size: clamp(17px,2.2vw,21px);
line-height: 1.6;
font-weight: 550;
letter-spacing: -.01em;
text-wrap: pretty;
}
.bq-06__by {
display: flex;
align-items: center;
gap: 10px;
margin-top: 20px;
font-size: 13.5px;
color: var(--mut);
}
.bq-06__by strong {
color: var(--ink);
font-weight: 650;
}
.bq-06__dot {
width: 9px;
height: 9px;
border-radius: 99px;
background: conic-gradient(oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25));
flex: none;
}
.bq-06__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(1 0 0/.12);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.bq-06 * {
transition-duration: .01ms !important;
}
.bq-06__card {
animation: none;
}
}@property --bq06-angle {
syntax: '<angle>';
initial-value: 40deg;
inherits: false;
}
.bq-06,
.bq-06 *,
.bq-06 *::before,
.bq-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-06 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.15 0.012 270);
--card: oklch(0.2 0.015 270);
--ink: oklch(0.96 0.008 270);
--mut: oklch(0.66 0.02 270);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-06__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(70% 55% at 50% 120%,oklch(0.24 0.05 300/.5),transparent),var(--bg);
overflow-y: auto;
}
.bq-06__card {
width: min(100%,520px);
padding: clamp(24px,4vw,36px);
border: 1.5px solid transparent;
border-radius: 20px;
background: linear-gradient(var(--card),var(--card)) padding-box,conic-gradient(from var(--bq06-angle),oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25)) border-box;
animation: bq06-spin 7s linear infinite;
box-shadow: 0 24px 60px oklch(0 0 0/.45);
}
@keyframes bq06-spin {
to {
--bq06-angle: 400deg;
}
}
.bq-06__card blockquote p {
font-size: clamp(17px,2.2vw,21px);
line-height: 1.6;
font-weight: 550;
letter-spacing: -.01em;
text-wrap: pretty;
}
.bq-06__by {
display: flex;
align-items: center;
gap: 10px;
margin-top: 20px;
font-size: 13.5px;
color: var(--mut);
}
.bq-06__by strong {
color: var(--ink);
font-weight: 650;
}
.bq-06__dot {
width: 9px;
height: 9px;
border-radius: 99px;
background: conic-gradient(oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25));
flex: none;
}
.bq-06__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(1 0 0/.12);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.bq-06 * {
transition-duration: .01ms !important;
}
.bq-06__card {
animation: none;
}
}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: Animated CSS Gradient Border Blockquote
Source: https://codefronts.com/snippets/css-blockquotes/animated-css-gradient-border-blockquote/
A quote card wrapped in a slowly rotating conic-gradient border — the effect every 'top CSS tricks' video promises, done the 2026 way: a registered @property custom property (--bq06-angle) makes the gradient's angle itself animatable, so the colors orbit the card with zero JavaScript and zero pseudo-element hacks. The border is painted by a two-layer background (padding-box fill over border-box gradient), which — unlike outline or box-shadow tricks — respects border-radius perfectly and costs one element.
## HTML
```html
<section class="bq-06" aria-label="Animated gradient border blockquote demo">
<div class="bq-06__stage">
<figure class="bq-06__card">
<blockquote>
<p>“We shipped the redesign in six weeks. The border animation in this quote card took two of them — and it was worth every hour.”</p>
</blockquote>
<figcaption class="bq-06__by">
<span class="bq-06__dot" aria-hidden="true"></span>
<span><strong>Marcus Webb</strong> · Design Engineer, Meridian</span>
</figcaption>
</figure>
<p class="bq-06__chip" aria-hidden="true">@property <angle> · conic-gradient border-box · 0 JS</p>
</div>
</section>
```
## CSS
```css
@property --bq06-angle {
syntax: '<angle>';
initial-value: 40deg;
inherits: false;
}
.bq-06,
.bq-06 *,
.bq-06 *::before,
.bq-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-06 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.15 0.012 270);
--card: oklch(0.2 0.015 270);
--ink: oklch(0.96 0.008 270);
--mut: oklch(0.66 0.02 270);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-06__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(70% 55% at 50% 120%,oklch(0.24 0.05 300/.5),transparent),var(--bg);
overflow-y: auto;
}
.bq-06__card {
width: min(100%,520px);
padding: clamp(24px,4vw,36px);
border: 1.5px solid transparent;
border-radius: 20px;
background: linear-gradient(var(--card),var(--card)) padding-box,conic-gradient(from var(--bq06-angle),oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25)) border-box;
animation: bq06-spin 7s linear infinite;
box-shadow: 0 24px 60px oklch(0 0 0/.45);
}
@keyframes bq06-spin {
to {
--bq06-angle: 400deg;
}
}
.bq-06__card blockquote p {
font-size: clamp(17px,2.2vw,21px);
line-height: 1.6;
font-weight: 550;
letter-spacing: -.01em;
text-wrap: pretty;
}
.bq-06__by {
display: flex;
align-items: center;
gap: 10px;
margin-top: 20px;
font-size: 13.5px;
color: var(--mut);
}
.bq-06__by strong {
color: var(--ink);
font-weight: 650;
}
.bq-06__dot {
width: 9px;
height: 9px;
border-radius: 99px;
background: conic-gradient(oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25));
flex: none;
}
.bq-06__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(1 0 0/.12);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.bq-06 * {
transition-duration: .01ms !important;
}
.bq-06__card {
animation: none;
}
}
```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: Animated CSS Gradient Border Blockquote
Source: https://codefronts.com/snippets/css-blockquotes/animated-css-gradient-border-blockquote/
A quote card wrapped in a slowly rotating conic-gradient border — the effect every 'top CSS tricks' video promises, done the 2026 way: a registered @property custom property (--bq06-angle) makes the gradient's angle itself animatable, so the colors orbit the card with zero JavaScript and zero pseudo-element hacks. The border is painted by a two-layer background (padding-box fill over border-box gradient), which — unlike outline or box-shadow tricks — respects border-radius perfectly and costs one element.
## HTML
```html
<section class="bq-06" aria-label="Animated gradient border blockquote demo">
<div class="bq-06__stage">
<figure class="bq-06__card">
<blockquote>
<p>“We shipped the redesign in six weeks. The border animation in this quote card took two of them — and it was worth every hour.”</p>
</blockquote>
<figcaption class="bq-06__by">
<span class="bq-06__dot" aria-hidden="true"></span>
<span><strong>Marcus Webb</strong> · Design Engineer, Meridian</span>
</figcaption>
</figure>
<p class="bq-06__chip" aria-hidden="true">@property <angle> · conic-gradient border-box · 0 JS</p>
</div>
</section>
```
## CSS
```css
@property --bq06-angle {
syntax: '<angle>';
initial-value: 40deg;
inherits: false;
}
.bq-06,
.bq-06 *,
.bq-06 *::before,
.bq-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bq-06 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
--bg: oklch(0.15 0.012 270);
--card: oklch(0.2 0.015 270);
--ink: oklch(0.96 0.008 270);
--mut: oklch(0.66 0.02 270);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.bq-06__stage {
width: 100%;
height: 100vh;
height: 100svh;
display: grid;
place-items: center;
align-content: center;
gap: 26px;
padding: clamp(20px,5vw,56px);
background: radial-gradient(70% 55% at 50% 120%,oklch(0.24 0.05 300/.5),transparent),var(--bg);
overflow-y: auto;
}
.bq-06__card {
width: min(100%,520px);
padding: clamp(24px,4vw,36px);
border: 1.5px solid transparent;
border-radius: 20px;
background: linear-gradient(var(--card),var(--card)) padding-box,conic-gradient(from var(--bq06-angle),oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25)) border-box;
animation: bq06-spin 7s linear infinite;
box-shadow: 0 24px 60px oklch(0 0 0/.45);
}
@keyframes bq06-spin {
to {
--bq06-angle: 400deg;
}
}
.bq-06__card blockquote p {
font-size: clamp(17px,2.2vw,21px);
line-height: 1.6;
font-weight: 550;
letter-spacing: -.01em;
text-wrap: pretty;
}
.bq-06__by {
display: flex;
align-items: center;
gap: 10px;
margin-top: 20px;
font-size: 13.5px;
color: var(--mut);
}
.bq-06__by strong {
color: var(--ink);
font-weight: 650;
}
.bq-06__dot {
width: 9px;
height: 9px;
border-radius: 99px;
background: conic-gradient(oklch(0.72 0.17 25),oklch(0.75 0.15 320),oklch(0.7 0.14 250),oklch(0.72 0.17 25));
flex: none;
}
.bq-06__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
color: var(--mut);
padding: 7px 13px;
border: 1px solid oklch(1 0 0/.12);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.bq-06 * {
transition-duration: .01ms !important;
}
.bq-06__card {
animation: none;
}
}
```How this works
Gradients aren't animatable — but a registered custom property is. That inversion is the whole technique:
@property --bq06-angle{
syntax:'<angle>'; initial-value:0deg; inherits:false;
}
.card{
border:1.5px solid transparent; border-radius:20px;
background:
linear-gradient(var(--card), var(--card)) padding-box,
conic-gradient(from var(--bq06-angle),
oklch(0.72 0.17 25), oklch(0.75 0.15 320),
oklch(0.7 0.14 250), oklch(0.72 0.17 25)) border-box;
animation:bq06-spin 7s linear infinite;
}
@keyframes bq06-spin{ to{ --bq06-angle:360deg; } }Without @property, custom properties are opaque strings — animating one just snaps at 50%. Registering it with syntax:'<angle>' tells the engine it's a real angle, so the keyframe interpolates smoothly and the conic gradient repaints each frame.
The border itself is the classic two-background sandwich: a flat card-colored gradient clipped to padding-box sits over the conic clipped to border-box; the transparent 1.5px border is the window where the bottom layer shows through. Because it's a real border, the radius curves it perfectly — the thing outline and clip-path versions always get wrong. The first and last conic stops repeat the same color so the seam at 0deg is invisible. Reduced-motion users get the gradient frozen at a designed angle — the card still looks finished, it just doesn't move.
Make it yours
- Speed and mood: 7s linear reads as ambient; 2.5s reads as loading-spinner — keep ambient borders slower than 6s.
- Thickness: the border width IS the gradient reveal — 1px is jewelry, 3px is festive. Adjust border and border-radius together to keep the curve smooth.
- Hover-only motion: move the animation to .card:hover, .card:focus-within with animation-play-state — ambient calm, alive on approach.
- Glow pairing: add a blurred drop-shadow in one of the gradient hues at 25% — see demo 10 for the full glow treatment; here restraint keeps it editorial.
Gotchas — read before shipping
- Forgetting @property is the classic failure: the animation 'runs' but the angle jumps 0→360 with no in-between. Firefox shipped @property in 128 (mid-2024); older Firefox shows the static border.
- The two backgrounds must be listed padding-box FIRST, border-box second — reversed, the card color paints over the gradient and the border vanishes.
- background-clip shorthand resets: if you later override background on the card (e.g. a hover), you must restate both layers, clips included.
- An infinite animation repaints forever, even offscreen in some engines — for long pages, pause it with animation-play-state when not hovered, or gate it behind :has(:hover) on the section.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 128+ | 114+ |
Floor set by oklch(), @property, text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
Floor set by @property (Chrome 85 / Safari 16.4 / Firefox 128). Everywhere else the card renders with a static multicolor border — a designed fallback, not a broken one.