CSS Animated Text Effects for Bootstrap 5
Six looping animated headline effects, from a gradient shimmer and letter wave to neon glow and bouncing letters, all in pure CSS.
<section class="txt-section wdw-stage"><div class="container">
<header class="text-center mb-5"><span class="wdw-eyebrow mb-3">CSS text effects</span><h1 class="h2 wdw-heading mb-2">Animated text styles</h1><p class="text-body-secondary mb-0">Six looping headline effects built with plain CSS keyframes. Copy the CSS for any of them.</p></header>
<div class="row g-4"><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the gradient shimmer effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-shimmer-t">Web Designer</span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Gradient shimmer</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="shimmer" aria-label="Copy CSS for gradient shimmer effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the wave effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-wave-w"><span style="--i:0">W</span><span style="--i:1">e</span><span style="--i:2">b</span><span class="txt-sp" style="--i:3"> </span><span style="--i:4">D</span><span style="--i:5">e</span><span style="--i:6">s</span><span style="--i:7">i</span><span style="--i:8">g</span><span style="--i:9">n</span><span style="--i:10">e</span><span style="--i:11">r</span></span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Wave</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="wave" aria-label="Copy CSS for wave effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the blur focus effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-blur-w"><span style="--i:0">W</span><span style="--i:1">e</span><span style="--i:2">b</span><span class="txt-sp" style="--i:3"> </span><span style="--i:4">D</span><span style="--i:5">e</span><span style="--i:6">s</span><span style="--i:7">i</span><span style="--i:8">g</span><span style="--i:9">n</span><span style="--i:10">e</span><span style="--i:11">r</span></span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Blur focus</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="blur" aria-label="Copy CSS for blur focus effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card txt-neon" data-bs-theme="dark"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the neon glow effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-neon-t">Web Designer</span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Neon glow</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="neon" aria-label="Copy CSS for neon glow effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the bounce effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-bounce-w"><span style="--i:0">W</span><span style="--i:1">e</span><span style="--i:2">b</span><span class="txt-sp" style="--i:3"> </span><span style="--i:4">D</span><span style="--i:5">e</span><span style="--i:6">s</span><span style="--i:7">i</span><span style="--i:8">g</span><span style="--i:9">n</span><span style="--i:10">e</span><span style="--i:11">r</span></span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Bounce</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="bounce" aria-label="Copy CSS for bounce effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div><div class="col-md-6 col-lg-4"><div class="card wdw-card border-0 h-100 txt-card"><div class="card-body txt-stage" role="img" aria-label="Web Designer, animated with the spaced reveal effect"><p class="txt-demo mb-0" aria-hidden="true"><span class="txt-track-t">Web Designer</span></p></div><div class="card-footer bg-transparent border-0 px-4 pb-4 pt-0 d-flex justify-content-between align-items-center gap-2"><span class="fw-semibold text-body-emphasis">Spaced reveal</span><button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3 txt-copy" data-effect="track" aria-label="Copy CSS for spaced reveal effect"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M10.5 5.5v-2a1.5 1.5 0 00-1.5-1.5H4A1.5 1.5 0 002.5 3.5V9A1.5 1.5 0 004 10.5h1.5"/></svg><span class="txt-copy-label">Copy CSS</span></button></div></div></div></div><p class="visually-hidden" role="status" id="txtCopyStatus"></p></div></section>
/* Web Designer Wall library style — shared base for every Bootstrap 5 snippet.
Indigo accent, Plus Jakarta Sans, soft cards, pill buttons. Works in light and dark. */
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap");
:root,
[data-bs-theme="light"] {
--wdw-font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--bs-body-font-family: var(--wdw-font);
--bs-primary: #4f46e5;
--bs-primary-rgb: 79, 70, 229;
--bs-primary-text-emphasis: #3730a3;
--bs-primary-bg-subtle: #eef2ff;
--bs-primary-border-subtle: #c7d2fe;
--bs-link-color: #4f46e5;
--bs-link-color-rgb: 79, 70, 229;
--bs-link-hover-color: #4338ca;
--bs-link-hover-color-rgb: 67, 56, 202;
--bs-focus-ring-color: rgba(79, 70, 229, 0.25);
--bs-border-radius: 0.75rem;
--bs-border-radius-lg: 1rem;
--bs-border-radius-xl: 1.25rem;
--wdw-radius-card: 1.25rem;
--wdw-shadow: 0 1px 2px rgba(16, 24, 40, 0.05), 0 16px 40px -16px rgba(16, 24, 40, 0.22);
--wdw-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06), 0 4px 12px -4px rgba(16, 24, 40, 0.12);
--wdw-stage: #f5f6fb;
}
[data-bs-theme="dark"] {
--bs-primary: #818cf8;
--bs-primary-rgb: 129, 140, 248;
--bs-primary-text-emphasis: #c7d2fe;
--bs-primary-bg-subtle: rgba(129, 140, 248, 0.14);
--bs-primary-border-subtle: rgba(129, 140, 248, 0.35);
--bs-link-color: #a5b4fc;
--bs-link-color-rgb: 165, 180, 252;
--bs-link-hover-color: #c7d2fe;
--bs-link-hover-color-rgb: 199, 210, 254;
--bs-focus-ring-color: rgba(129, 140, 248, 0.35);
--wdw-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 16px 40px -16px rgba(0, 0, 0, 0.7);
--wdw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px -4px rgba(0, 0, 0, 0.5);
--wdw-stage: #0f1117;
}
body { font-family: var(--wdw-font); -webkit-font-smoothing: antialiased; }
/* Bootstrap compiles its blue into these components; point them at the accent. */
.btn-primary {
--bs-btn-bg: var(--bs-primary); --bs-btn-border-color: var(--bs-primary);
--bs-btn-hover-bg: #4338ca; --bs-btn-hover-border-color: #4338ca;
--bs-btn-active-bg: #3730a3; --bs-btn-active-border-color: #3730a3;
--bs-btn-disabled-bg: var(--bs-primary); --bs-btn-disabled-border-color: var(--bs-primary);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
[data-bs-theme="dark"] .btn-primary { --bs-btn-color: #0f1117; --bs-btn-hover-bg: #a5b4fc; --bs-btn-hover-border-color: #a5b4fc; --bs-btn-hover-color: #0f1117; --bs-btn-active-color: #0f1117; }
.btn-outline-primary {
--bs-btn-color: var(--bs-primary); --bs-btn-border-color: var(--bs-primary);
--bs-btn-hover-bg: var(--bs-primary); --bs-btn-hover-border-color: var(--bs-primary);
--bs-btn-active-bg: var(--bs-primary); --bs-btn-active-border-color: var(--bs-primary);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn { --bs-btn-font-weight: 600; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: .5rem; }
.btn-sm { min-height: 36px; }
.form-control, .form-select { min-height: 44px; border-radius: .75rem; }
.form-control:focus, .form-select:focus, .form-check-input:focus { border-color: rgba(var(--bs-primary-rgb), .6); box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.form-check-input:checked { background-color: var(--bs-primary); border-color: var(--bs-primary); }
.nav-pills { --bs-nav-pills-link-active-bg: var(--bs-primary); }
.nav { --bs-nav-link-color: var(--bs-secondary-color); --bs-nav-link-hover-color: var(--bs-emphasis-color); }
.pagination { --bs-pagination-active-bg: var(--bs-primary); --bs-pagination-active-border-color: var(--bs-primary); --bs-pagination-color: var(--bs-body-color); --bs-pagination-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.progress, .progress-stacked { --bs-progress-bar-bg: var(--bs-primary); }
.list-group { --bs-list-group-active-bg: var(--bs-primary); --bs-list-group-active-border-color: var(--bs-primary); }
.dropdown-menu { --bs-dropdown-link-active-bg: var(--bs-primary); border-radius: .875rem; box-shadow: var(--wdw-shadow-sm); }
.accordion { --bs-accordion-active-bg: var(--bs-primary-bg-subtle); --bs-accordion-active-color: var(--bs-primary-text-emphasis); --bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.badge { font-weight: 600; }
/* Library building blocks — use these instead of re-inventing them per snippet. */
.wdw-stage { min-height: 100vh; display: flex; align-items: center; background: var(--wdw-stage); padding-block: 3rem; }
.wdw-card { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color-translucent); border-radius: var(--wdw-radius-card); box-shadow: var(--wdw-shadow); }
.wdw-card-sm { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color-translucent); border-radius: 1rem; box-shadow: var(--wdw-shadow-sm); }
.wdw-aurora { position: relative; color: #fff; background: radial-gradient(60% 55% at 100% 0, #818cf8 0, transparent 70%), radial-gradient(65% 60% at 0 100%, #ec4899 0, transparent 65%), #1e1b4b; }
.wdw-eyebrow { display: inline-block; font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--bs-primary); }
.wdw-heading { font-weight: 800; letter-spacing: -.02em; color: var(--bs-emphasis-color); }
.wdw-muted { color: var(--bs-secondary-color); }
.wdw-icon { width: 2.75rem; height: 2.75rem; flex: none; display: inline-flex; align-items: center; justify-content: center; border-radius: .875rem; background: var(--bs-primary-bg-subtle); color: var(--bs-primary); }
/* Component */
.txt-stage { min-height: 150px; display: grid; place-items: center; padding: 1.5rem 1rem; overflow: hidden; }
.txt-demo { font-size: clamp(1.6rem, 3.6vw, 2rem); font-weight: 800; letter-spacing: -.01em; color: var(--bs-emphasis-color); white-space: nowrap; }
.txt-wave-w span, .txt-blur-w span, .txt-bounce-w span { display: inline-block; }
.txt-sp { width: .3em; }
/* shimmer: primary token only, highlight mixes toward the surface colour */
.txt-shimmer-t { background-image: linear-gradient(90deg, var(--bs-primary) 0 35%, color-mix(in srgb, var(--bs-primary) 35%, var(--bs-body-bg)) 50%, var(--bs-primary) 65% 100%); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; animation: txt-shim 4s linear infinite; }
@keyframes txt-shim { from { background-position: 100% 0; } to { background-position: -100% 0; } }
/* wave */
.txt-wave-w span { color: var(--bs-primary); animation: txt-wave 1.6s ease-in-out infinite; animation-delay: calc(var(--i) * .08s); }
@keyframes txt-wave { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-.35em); } }
/* blur */
.txt-blur-w span { color: var(--bs-primary); animation: txt-blur 3s ease-in-out infinite; animation-delay: calc(var(--i) * .1s); }
@keyframes txt-blur { 0%, 100% { filter: blur(6px); opacity: .25; } 30%, 70% { filter: blur(0); opacity: 1; } }
/* neon: a fixed dark inset panel with a primary border, in both themes */
.txt-neon { --bs-card-bg: #070a16; background-color: #070a16; border: 1px solid rgba(var(--bs-primary-rgb), .6) !important; box-shadow: inset 0 0 40px rgba(var(--bs-primary-rgb), .18), var(--wdw-shadow); }
.txt-neon-t { color: #fff; text-shadow: 0 0 6px rgba(var(--bs-primary-rgb), 1), 0 0 16px rgba(var(--bs-primary-rgb), .9), 0 0 36px rgba(var(--bs-primary-rgb), .7); animation: txt-neon 2.4s ease-in-out infinite; }
@keyframes txt-neon { 0%, 18%, 22%, 100% { opacity: 1; } 20% { opacity: .55; } 50% { text-shadow: 0 0 4px rgba(var(--bs-primary-rgb), 1), 0 0 10px rgba(var(--bs-primary-rgb), .9), 0 0 20px rgba(var(--bs-primary-rgb), .6); } }
/* bounce */
.txt-bounce-w { letter-spacing: .02em; }
.txt-bounce-w span { color: var(--bs-primary); animation: txt-bounce 1.2s cubic-bezier(.3,1.6,.5,1) infinite; animation-delay: calc(var(--i) * .07s); }
@keyframes txt-bounce { 0%, 55%, 100% { transform: translateY(0) scale(1); } 25% { transform: translateY(-.35em) scale(1.1); } }
/* tracking */
.txt-track-t { animation: txt-track 3.6s ease-in-out infinite; color: var(--bs-primary); font-size: .85em; }
@keyframes txt-track { 0%, 100% { letter-spacing: 0; opacity: 0; } 40%, 70% { letter-spacing: .14em; opacity: 1; } }
.txt-copy { min-height: 36px; font-size: .8125rem; }
@media (max-width: 575.98px) { .txt-demo { font-size: 1.6rem; } }
@media (prefers-reduced-motion: reduce) { .txt-demo *, .txt-demo { animation: none !important; filter: none !important; opacity: 1 !important; transform: none !important; } .txt-track-t { letter-spacing: .08em; } }
(function () {
var CODE = {
shimmer: '.shimmer {\n background-image: linear-gradient(90deg, var(--bs-primary) 0 35%, color-mix(in srgb, var(--bs-primary) 35%, var(--bs-body-bg)) 50%, var(--bs-primary) 65% 100%);\n background-size: 300% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n animation: shim 4s linear infinite;\n}\n@keyframes shim { from { background-position: 100% 0; } to { background-position: -100% 0; } }',
wave: '.wave span { display: inline-block; animation: wave 1.6s ease-in-out infinite; animation-delay: calc(var(--i) * .08s); }\n@keyframes wave { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-.35em); } }',
blur: '.blur span { display: inline-block; animation: blur-in 3s ease-in-out infinite; animation-delay: calc(var(--i) * .1s); }\n@keyframes blur-in { 0%, 100% { filter: blur(6px); opacity: .25; } 30%, 70% { filter: blur(0); opacity: 1; } }',
neon: '.neon {\n color: #fff;\n text-shadow: 0 0 6px var(--glow), 0 0 16px var(--glow), 0 0 36px var(--glow);\n animation: flicker 2.4s ease-in-out infinite;\n}\n@keyframes flicker { 0%, 18%, 22%, 100% { opacity: 1; } 20% { opacity: .55; } }',
bounce: '.bounce span { display: inline-block; animation: bounce 1.2s cubic-bezier(.3,1.6,.5,1) infinite; animation-delay: calc(var(--i) * .07s); }\n@keyframes bounce { 0%, 55%, 100% { transform: translateY(0) scale(1); } 25% { transform: translateY(-.35em) scale(1.1); } }',
track: '.track { animation: track 3.6s ease-in-out infinite; }\n@keyframes track { 0%, 100% { letter-spacing: 0; opacity: 0; } 40%, 70% { letter-spacing: .14em; opacity: 1; } }'
};
function copyText(text) {
if (navigator.clipboard && navigator.clipboard.writeText) return navigator.clipboard.writeText(text);
return new Promise(function (resolve, reject) {
var ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
document.body.appendChild(ta); ta.select();
try { document.execCommand('copy') ? resolve() : reject(); } catch (e) { reject(e); } finally { ta.remove(); }
});
}
function initCopyButtons() {
var buttons = document.querySelectorAll('.txt-copy');
if (!buttons.length) return;
var status = document.getElementById('txtCopyStatus');
buttons.forEach(function (btn) {
var label = btn.querySelector('.txt-copy-label');
btn.addEventListener('click', function () {
copyText(CODE[btn.dataset.effect] || '').then(function () {
label.textContent = 'Copied';
if (status) status.textContent = 'CSS copied to clipboard';
}, function () { label.textContent = 'Press Ctrl+C'; });
setTimeout(function () { label.textContent = 'Copy CSS'; }, 1800);
});
});
}
initCopyButtons();
})();
Built on Bootstrap 5.3.8 with plain JavaScript — no jQuery. Supports light and dark mode via data-bs-theme.