Blur Morph Transition
Content softly de-focuses then re-focuses as the new view emerges. Calm and considered — ideal for data-heavy SaaS dashboards and admin apps.
Blur Morph Transition the 5th of 11 designs in the 11 CSS Page Transitions collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="app">
<!-- Sidebar -->
<aside class="sidebar">
<div class="sidebar-brand">
<div class="brand-icon">◆</div>
<div class="brand-name">Velocity</div>
</div>
<div class="nav-section">Main</div>
<button class="nav-item active" data-page="overview">
<span class="nav-icon">▦</span> Overview
</button>
<button class="nav-item" data-page="analytics">
<span class="nav-icon">▲</span> Analytics
<span class="nav-badge">3</span>
</button>
<button class="nav-item" data-page="transactions">
<span class="nav-icon">≡</span> Transactions
</button>
<div class="nav-section">System</div>
<button class="nav-item" data-page="settings">
<span class="nav-icon">⚙</span> Settings
</button>
</aside>
<!-- Main -->
<div class="main">
<!-- Topbar -->
<div class="topbar">
<div class="topbar-title" id="topbarTitle">Overview</div>
<div class="topbar-right">
<div class="search-bar">🔍 Search...</div>
<div class="avatar">KL</div>
</div>
</div>
<!-- Pages -->
<div class="page-stack">
<!-- Overview -->
<div class="dash-page active" id="overview">
<div class="page-heading">Good afternoon, Kayla 👋</div>
<div class="page-sub">Here's what's happening with your business today.</div>
<div class="kpi-row">
<div class="kpi-card" style="--glow-a: var(--blue)">
<div class="kpi-icon" style="background:rgba(59,130,246,0.15);color:var(--blue)">💰</div>
<div class="kpi-value">$84.2k</div>
<div class="kpi-label">Total Revenue</div>
<div class="kpi-delta up">↑ 12.4% vs last month</div>
</div>
<div class="kpi-card" style="--glow-a: var(--purple)">
<div class="kpi-icon" style="background:rgba(139,92,246,0.15);color:var(--purple)">👥</div>
<div class="kpi-value">3,241</div>
<div class="kpi-label">Active Users</div>
<div class="kpi-delta up">↑ 8.1% vs last month</div>
</div>
<div class="kpi-card" style="--glow-a: var(--green)">
<div class="kpi-icon" style="background:rgba(16,185,129,0.15);color:var(--green)">✓</div>
<div class="kpi-value">98.2%</div>
<div class="kpi-label">Uptime</div>
<div class="kpi-delta up">↑ 0.3% vs last month</div>
</div>
<div class="kpi-card" style="--glow-a: var(--orange)">
<div class="kpi-icon" style="background:rgba(245,158,11,0.15);color:var(--orange)">⚡</div>
<div class="kpi-value">142ms</div>
<div class="kpi-label">Avg Response</div>
<div class="kpi-delta down">↓ 18ms vs last month</div>
</div>
</div>
<div class="charts-row">
<div class="chart-card">
<div class="chart-title">Revenue by Month</div>
<div class="chart-sub">January — June 2025</div>
<div class="bar-chart">
<div class="bar" style="height:55%;background:rgba(59,130,246,0.3)"></div>
<div class="bar" style="height:70%;background:rgba(59,130,246,0.4)"></div>
<div class="bar" style="height:45%;background:rgba(59,130,246,0.3)"></div>
<div class="bar" style="height:85%;background:rgba(59,130,246,0.5)"></div>
<div class="bar" style="height:72%;background:rgba(59,130,246,0.4)"></div>
<div class="bar" style="height:95%;background:var(--blue)"></div>
</div>
</div>
<div class="chart-card">
<div class="chart-title">Traffic Sources</div>
<div class="chart-sub">Current month breakdown</div>
<div class="donut-wrap">
<div class="donut"></div>
<div class="legend">
<div class="legend-item"><div class="legend-dot" style="background:var(--blue)"></div>Direct 42%</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--purple)"></div>Search 26%</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--green)"></div>Social 16%</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--muted)"></div>Other 16%</div>
</div>
</div>
</div>
</div>
</div>
<!-- Analytics -->
<div class="dash-page" id="analytics">
<div class="page-heading">Analytics</div>
<div class="page-sub">Funnel performance and conversion data.</div>
<div class="charts-row">
<div class="chart-card">
<div class="chart-title">Conversion Funnel</div>
<div class="chart-sub">Visitors → Paying customers</div>
<div class="funnel">
<div class="funnel-row">
<div class="funnel-label">Visitors</div>
<div class="funnel-bar-bg"><div class="funnel-bar-fill" style="width:100%;background:var(--blue)">48,291</div></div>
</div>
<div class="funnel-row">
<div class="funnel-label">Sign-ups</div>
<div class="funnel-bar-bg"><div class="funnel-bar-fill" style="width:62%;background:var(--purple)">29,940</div></div>
</div>
<div class="funnel-row">
<div class="funnel-label">Activated</div>
<div class="funnel-bar-bg"><div class="funnel-bar-fill" style="width:38%;background:var(--green)">18,350</div></div>
</div>
<div class="funnel-row">
<div class="funnel-label">Trial</div>
<div class="funnel-bar-bg"><div class="funnel-bar-fill" style="width:21%;background:var(--orange)">10,141</div></div>
</div>
<div class="funnel-row">
<div class="funnel-label">Paid</div>
<div class="funnel-bar-bg"><div class="funnel-bar-fill" style="width:9%;background:var(--pink)">4,346</div></div>
</div>
</div>
</div>
<div class="chart-card">
<div class="chart-title">Key Metrics</div>
<div class="chart-sub">Rolling 30-day averages</div>
<div style="display:flex;flex-direction:column;gap:20px;margin-top:8px">
<div>
<div class="kpi-label">Conversion Rate</div>
<div class="kpi-value" style="font-size:22px">8.9%</div>
<div class="kpi-delta up">↑ 1.2pp this month</div>
</div>
<div>
<div class="kpi-label">Avg Session Duration</div>
<div class="kpi-value" style="font-size:22px">4m 32s</div>
<div class="kpi-delta up">↑ 14s this month</div>
</div>
<div>
<div class="kpi-label">Bounce Rate</div>
<div class="kpi-value" style="font-size:22px">34.1%</div>
<div class="kpi-delta down">↓ 2.4pp this month</div>
</div>
</div>
</div>
</div>
</div>
<!-- Transactions -->
<div class="dash-page" id="transactions">
<div class="page-heading">Transactions</div>
<div class="page-sub">Recent payment activity across all accounts.</div>
<div class="table-card">
<div class="table-header">
<div class="table-title">Recent Transactions</div>
<div style="font-size:12px;color:var(--blue);cursor:pointer">Export CSV</div>
</div>
<div class="table-row head">
<div>Customer</div><div>Amount</div><div>Date</div><div>Status</div>
</div>
<div class="table-row"><div>Acme Corp</div><div>$4,200.00</div><div>Jun 12</div><div><span class="status-pill status-active">Paid</span></div></div>
<div class="table-row"><div>GlobalTech</div><div>$11,800.00</div><div>Jun 11</div><div><span class="status-pill status-pending">Pending</span></div></div>
<div class="table-row"><div>Sunrise Co</div><div>$860.00</div><div>Jun 10</div><div><span class="status-pill status-active">Paid</span></div></div>
<div class="table-row"><div>Nova Labs</div><div>$2,100.00</div><div>Jun 9</div><div><span class="status-pill status-failed">Failed</span></div></div>
<div class="table-row"><div>Peak Media</div><div>$7,450.00</div><div>Jun 8</div><div><span class="status-pill status-active">Paid</span></div></div>
<div class="table-row"><div>Drift Studio</div><div>$3,300.00</div><div>Jun 7</div><div><span class="status-pill status-active">Paid</span></div></div>
<div class="table-row"><div>Cloud Nine</div><div>$18,000.00</div><div>Jun 6</div><div><span class="status-pill status-pending">Pending</span></div></div>
</div>
</div>
<!-- Settings -->
<div class="dash-page" id="settings">
<div class="page-heading">Settings</div>
<div class="page-sub">Manage your account and preferences.</div>
<div class="settings-grid">
<div class="settings-nav">
<div class="settings-nav-item active">General</div>
<div class="settings-nav-item">Security</div>
<div class="settings-nav-item">Billing</div>
<div class="settings-nav-item">Notifications</div>
<div class="settings-nav-item">Integrations</div>
</div>
<div class="settings-section">
<div class="settings-row">
<div>
<div class="settings-label">Email Notifications</div>
<div class="settings-desc">Receive alerts for new transactions and reports</div>
</div>
<button class="toggle-switch on" onclick="this.classList.toggle('on')"></button>
</div>
<div class="settings-row">
<div>
<div class="settings-label">Two-Factor Authentication</div>
<div class="settings-desc">Add an extra layer of security to your account</div>
</div>
<button class="toggle-switch on" onclick="this.classList.toggle('on')"></button>
</div>
<div class="settings-row">
<div>
<div class="settings-label">Weekly Digest</div>
<div class="settings-desc">Get a summary of your metrics every Monday</div>
</div>
<button class="toggle-switch" onclick="this.classList.toggle('on')"></button>
</div>
<div class="settings-row">
<div>
<div class="settings-label">Beta Features</div>
<div class="settings-desc">Access new features before public release</div>
</div>
<button class="toggle-switch" onclick="this.classList.toggle('on')"></button>
</div>
<div class="settings-row">
<div>
<div class="settings-label">Usage Analytics</div>
<div class="settings-desc">Help us improve by sharing anonymous usage data</div>
</div>
<button class="toggle-switch on" onclick="this.classList.toggle('on')"></button>
</div>
</div>
</div>
</div>
</div><!-- /page-stack -->
</div><!-- /main -->
</div><!-- /app --> *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #090912;
--surface: #0f0f1c;
--surface-2: #161627;
--border: rgba(255,255,255,0.06);
--text: #e2e2f0;
--muted: #6060a0;
--blue: #3b82f6;
--purple: #8b5cf6;
--green: #10b981;
--orange: #f59e0b;
--red: #ef4444;
--pink: #ec4899;
--dur: 500ms;
--ease: cubic-bezier(0.4, 0, 0.2, 1);
}
html, body {
height: 100%;
font-family: 'Plus Jakarta Sans', sans-serif;
background: var(--bg);
color: var(--text);
overflow: hidden;
}
/* App Shell */
.app {
display: grid;
grid-template-columns: 220px 1fr;
height: 100vh;
}
/* Sidebar */
.sidebar {
background: var(--surface);
border-right: 1px solid var(--border);
padding: 24px 16px;
display: flex;
flex-direction: column;
gap: 4px;
}
.sidebar-brand {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
margin-bottom: 24px;
}
.brand-icon {
width: 32px; height: 32px;
background: linear-gradient(135deg, var(--blue), var(--purple));
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.brand-name {
font-size: 15px;
font-weight: 700;
color: var(--text);
letter-spacing: -0.01em;
}
.nav-section { font-size: 10px; letter-spacing: 0.15em; text-transform: uppercase; color: var(--muted); padding: 16px 12px 8px; }
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 8px;
cursor: pointer;
font-size: 13.5px;
font-weight: 500;
color: var(--muted);
border: none;
background: none;
width: 100%;
text-align: left;
transition: background 0.15s, color 0.15s;
}
.nav-item:hover { background: rgba(255,255,255,0.04); color: var(--text); }
.nav-item.active { background: rgba(59,130,246,0.12); color: var(--blue); }
.nav-icon { font-size: 15px; width: 20px; text-align: center; }
.nav-badge {
margin-left: auto;
padding: 2px 8px;
border-radius: 10px;
font-size: 10px;
font-weight: 700;
background: var(--blue);
color: white;
}
/* Main area */
.main {
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Top bar */
.topbar {
height: 60px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
flex-shrink: 0;
}
.topbar-title {
font-size: 15px;
font-weight: 600;
color: var(--text);
transition: all var(--dur) var(--ease);
}
.topbar-right { display: flex; gap: 16px; align-items: center; }
.avatar {
width: 32px; height: 32px;
border-radius: 50%;
background: linear-gradient(135deg, var(--purple), var(--pink));
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 700;
}
.search-bar {
display: flex;
align-items: center;
gap: 8px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 8px;
padding: 6px 14px;
font-size: 12px;
color: var(--muted);
width: 200px;
}
/* Page stack */
.page-stack {
flex: 1;
position: relative;
overflow: hidden;
}
.dash-page {
position: absolute;
inset: 0;
overflow-y: auto;
padding: 32px;
opacity: 0;
filter: blur(8px);
transform: scale(0.98) translateY(8px);
pointer-events: none;
transition:
opacity var(--dur) var(--ease),
filter var(--dur) var(--ease),
transform var(--dur) var(--ease);
will-change: opacity, filter, transform;
}
.dash-page.active {
opacity: 1;
filter: blur(0px);
transform: scale(1) translateY(0px);
pointer-events: auto;
}
/* Dashboard components */
.page-heading {
font-size: 22px;
font-weight: 700;
color: var(--text);
margin-bottom: 8px;
letter-spacing: -0.02em;
}
.page-sub {
font-size: 13px;
color: var(--muted);
margin-bottom: 28px;
}
/* KPI row */
.kpi-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin-bottom: 24px;
}
.kpi-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
position: relative;
overflow: hidden;
}
.kpi-card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, var(--glow-a) 0%, transparent 60%);
opacity: 0.06;
pointer-events: none;
}
.kpi-icon {
width: 36px; height: 36px;
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-size: 17px;
margin-bottom: 14px;
}
.kpi-value {
font-size: 26px;
font-weight: 700;
letter-spacing: -0.03em;
color: var(--text);
margin-bottom: 4px;
}
.kpi-label {
font-size: 12px;
color: var(--muted);
margin-bottom: 10px;
}
.kpi-delta {
font-size: 11px;
font-weight: 600;
display: flex;
align-items: center;
gap: 4px;
}
.kpi-delta.up { color: var(--green); }
.kpi-delta.down { color: var(--red); }
/* Charts row */
.charts-row {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 16px;
margin-bottom: 24px;
}
.chart-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
}
.chart-title {
font-size: 13px;
font-weight: 600;
color: var(--text);
margin-bottom: 4px;
}
.chart-sub { font-size: 11px; color: var(--muted); margin-bottom: 20px; }
/* Fake bar chart */
.bar-chart {
display: flex;
align-items: flex-end;
gap: 6px;
height: 120px;
}
.bar {
flex: 1;
border-radius: 4px 4px 0 0;
transition: height 1s cubic-bezier(0.32, 0.72, 0, 1);
min-width: 0;
}
/* Fake donut */
.donut-wrap {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.donut {
width: 100px; height: 100px;
border-radius: 50%;
background: conic-gradient(
var(--blue) 0% 42%,
var(--purple) 42% 68%,
var(--green) 68% 84%,
var(--muted) 84% 100%
);
position: relative;
}
.donut::after {
content: '';
position: absolute;
inset: 20px;
border-radius: 50%;
background: var(--surface);
}
.legend {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
font-size: 11px;
color: var(--muted);
width: 100%;
}
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-dot { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }
/* Table */
.table-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.table-header {
padding: 16px 20px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
}
.table-title { font-size: 13px; font-weight: 600; }
.table-row {
display: grid;
grid-template-columns: 1fr 1fr 1fr 80px;
padding: 14px 20px;
border-bottom: 1px solid var(--border);
font-size: 12.5px;
align-items: center;
transition: background 0.15s;
}
.table-row:last-child { border-bottom: none; }
.table-row:hover { background: rgba(255,255,255,0.02); }
.table-row.head { color: var(--muted); font-size: 11px; font-weight: 500; }
.status-pill {
padding: 3px 10px;
border-radius: 10px;
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.status-active { background: rgba(16,185,129,0.15); color: var(--green); }
.status-pending { background: rgba(245,158,11,0.15); color: var(--orange); }
.status-failed { background: rgba(239,68,68,0.15); color: var(--red); }
/* Analytics page */
.funnel {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 24px;
}
.funnel-row {
display: flex;
align-items: center;
gap: 16px;
}
.funnel-label { font-size: 12px; color: var(--muted); width: 100px; flex-shrink: 0; }
.funnel-bar-bg {
flex: 1;
height: 28px;
background: var(--surface-2);
border-radius: 4px;
overflow: hidden;
}
.funnel-bar-fill {
height: 100%;
border-radius: 4px;
display: flex;
align-items: center;
padding-left: 10px;
font-size: 11px;
font-weight: 700;
color: white;
white-space: nowrap;
}
/* Settings page */
.settings-grid {
display: grid;
grid-template-columns: 200px 1fr;
gap: 24px;
}
.settings-nav { display: flex; flex-direction: column; gap: 2px; }
.settings-nav-item {
padding: 10px 14px;
border-radius: 8px;
font-size: 13px;
color: var(--muted);
cursor: pointer;
transition: all 0.15s;
}
.settings-nav-item.active { background: rgba(59,130,246,0.12); color: var(--blue); }
.settings-nav-item:hover { background: rgba(255,255,255,0.04); color: var(--text); }
.settings-section {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.settings-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 24px;
border-bottom: 1px solid var(--border);
}
.settings-row:last-child { border-bottom: none; }
.settings-label { font-size: 13.5px; font-weight: 500; margin-bottom: 3px; }
.settings-desc { font-size: 12px; color: var(--muted); }
.toggle-switch {
width: 40px; height: 22px;
background: rgba(255,255,255,0.1);
border-radius: 11px;
position: relative;
cursor: pointer;
transition: background 0.25s;
border: none;
flex-shrink: 0;
}
.toggle-switch.on { background: var(--blue); }
.toggle-switch::after {
content: '';
position: absolute;
width: 16px; height: 16px;
background: white;
border-radius: 50%;
top: 3px; left: 3px;
transition: transform 0.25s;
}
.toggle-switch.on::after { transform: translateX(18px); }
@media (max-width: 768px) {
.app { grid-template-columns: 1fr; }
.sidebar { display: none; }
.kpi-row { grid-template-columns: 1fr 1fr; }
.charts-row { grid-template-columns: 1fr; }
}
@media (max-width: 500px) {
.kpi-row { grid-template-columns: 1fr; }
} const navItems = document.querySelectorAll('.nav-item');
const pages = document.querySelectorAll('.dash-page');
const titles = { overview: 'Overview', analytics: 'Analytics', transactions: 'Transactions', settings: 'Settings' };
navItems.forEach(item => {
item.addEventListener('click', () => {
const target = item.dataset.page;
navItems.forEach(n => n.classList.remove('active'));
item.classList.add('active');
pages.forEach(p => p.classList.remove('active'));
document.getElementById(target).classList.add('active');
document.getElementById('topbarTitle').textContent = titles[target];
});
});