-
Bubble Navigation Menu
HTML
CSS
JavaScript
Bubble navigation menu with floating animated items
Home
Explore
Saves
Alerts
Profile
@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;700&display=swap'); :root { --nav-bg: #0a0a0f; --bubble-1: #c084fc; --bubble-2: #60a5fa; --bubble-3: #34d399; --bubble-4: #f472b6; --bubble-5: #fbbf24; --glow-blur: 28px; } * { box-sizing: border-box; margin: 0; padding: 0; } .scene { min-height: 480px; background: #0a0a0f; display: flex; align-items: center; justify-content: center; font-family: 'Syne', sans-serif; border-radius: var(--border-radius-lg); overflow: hidden; position: relative; } .ambient { position: absolute; inset: 0; background: radial-gradient(ellipse 60% 40% at 20% 80%, rgba(192,132,252,0.12) 0%, transparent 60%), radial-gradient(ellipse 50% 35% at 80% 20%, rgba(96,165,250,0.10) 0%, transparent 60%); pointer-events: none; } .nav-container { display: flex; gap: 20px; align-items: center; padding: 24px; position: relative; } .bubble-item { position: relative; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 10px; } .bubble { width: 72px; height: 72px; border-radius: 50%; display: flex; align-items: center; justify-content: center; position: relative; transition: transform 0.3s cubic-bezier(0.34,1.56,0.64,1); animation: float 3s ease-in-out infinite; } .bubble-item:nth-child(1) .bubble { animation-delay: 0s; } .bubble-item:nth-child(2) .bubble { animation-delay: 0.5s; } .bubble-item:nth-child(3) .bubble { animation-delay: 1s; } .bubble-item:nth-child(4) .bubble { animation-delay: 1.5s; } .bubble-item:nth-child(5) .bubble { animation-delay: 2s; } .bubble::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: inherit; filter: blur(var(--glow-blur)); opacity: 0.55; transition: opacity 0.3s ease; z-index: -1; } .bubble::after { content: ''; position: absolute; top: 10px; left: 14px; width: 22px; height: 14px; background: rgba(255,255,255,0.28); border-radius: 50%; transform: rotate(-35deg); pointer-events: none; } .bubble svg { width: 26px; height: 26px; stroke: rgba(255,255,255,0.92); fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; position: relative; z-index: 1; } .b1 { background: radial-gradient(circle at 35% 35%, #e9d5ff, #9333ea); } .b2 { background: radial-gradient(circle at 35% 35%, #bfdbfe, #2563eb); } .b3 { background: radial-gradient(circle at 35% 35%, #a7f3d0, #059669); } .b4 { background: radial-gradient(circle at 35% 35%, #fbcfe8, #db2777); } .b5 { background: radial-gradient(circle at 35% 35%, #fde68a, #d97706); } .bubble-label { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: rgba(255,255,255,0.45); transition: color 0.3s ease; user-select: none; } .bubble-item:hover .bubble { transform: scale(1.22) translateY(-6px); } .bubble-item:hover .bubble::before { opacity: 0.85; } .bubble-item:hover .bubble-label { color: rgba(255,255,255,0.9); } .bubble-item.active .bubble { transform: scale(1.18) translateY(-4px); animation: float-active 2s ease-in-out infinite; } .bubble-item.active .bubble::before { opacity: 0.9; } .bubble-item.active .bubble-label { color: rgba(255,255,255,1); } .active-ring { position: absolute; inset: -5px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.6); opacity: 0; transform: scale(0.7); transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.34,1.56,0.64,1); } .bubble-item.active .active-ring { opacity: 1; transform: scale(1); } .ripple { position: absolute; inset: -5px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.4); animation: ripple-out 1s ease-out forwards; pointer-events: none; } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-8px); } } @keyframes float-active { 0%, 100% { transform: scale(1.18) translateY(-4px); } 50% { transform: scale(1.18) translateY(-10px); } } @keyframes ripple-out { 0% { transform: scale(1); opacity: 0.7; } 100% { transform: scale(2.2); opacity: 0; } } .page-content { position: absolute; bottom: 36px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; opacity: 0; animation: fade-up 0.5s ease forwards; } .page-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,0.25); transition: background 0.3s ease, transform 0.3s ease; } .page-dot.lit { background: rgba(255,255,255,0.8); transform: scale(1.4); } @keyframes fade-up { from { opacity: 0; transform: translateX(-50%) translateY(8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
const items = document.querySelectorAll('.bubble-item'); const dots = document.querySelectorAll('.page-dot'); items.forEach((item, i) => { item.addEventListener('click', () => { items.forEach(el => el.classList.remove('active')); dots.forEach(el => el.classList.remove('lit')); item.classList.add('active'); dots[i].classList.add('lit'); const bubble = item.querySelector('.bubble'); const ripple = document.createElement('div'); ripple.className = 'ripple'; bubble.appendChild(ripple); setTimeout(() => ripple.remove(), 1000); }); });
Live Preview