Пример:
Выбрать другой мяч для примера:
Вместо мяча можно поставить любое другое изображение или же просто сделать точку, заменив соответствующие стили в классе ball-nav > ul:after
HTML:
|
1 2 3 4 5 6 7 8 |
<nav class="ball-nav"> <ul> <li><a class="active" href="#link-1">Главная</a></li> <li><a href="#link-2">О нас</a></li> <li><a href="#link-3">Услуги</a></li> <li><a href="#link-4">Контакты</a></li> </ul> </nav> |
Пункт меню, на котором изначально будет находиться мячик, должен иметь класс active
CSS:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
.ball-nav { width: fit-content; margin: 20px auto; padding: 0 10px; border-radius: 16px; background: #fff; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), 0 4px 16px rgba(0, 0, 0, 0.05); } .ball-nav > ul { position: relative; list-style: none; display: flex; flex-wrap: wrap; justify-content: center; isolation: isolate; padding: 12px 4px; margin: 0; } .ball-nav > ul:after { content: ''; position: absolute; left: -14px; bottom: -62px; width: 28px; height: 28px; background-color: #FFF; background-image: url(ball.png); background-size: contain; border-radius: 50%; transform: translateX(var(--translate-x, 0)) translateY(var(--translate-y, 0)) rotate(var(--rotate-x, 0deg)); transition: none; z-index: -1; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05), 0 2px 8px rgba(0, 0, 0, 0.1); } .ball-nav > ul li, .ball-nav > ul li a { position: relative; height: 100%; display: flex; justify-content: center; align-items: center; color: #1a1a1a; text-decoration: none; font-weight: bold; font-size: 22px; text-transform: uppercase; } .ball-nav > ul li a { padding: 10px 20px 32px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .ball-nav > ul li a:hover { color: #000000; transform: translateY(-2px); } .ball-nav > ul li a.active { color: #337AB7; transform: translateY(-2px); } |
JS:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
document.addEventListener('DOMContentLoaded', () => { let nav = document.querySelector('.ball-nav > ul'); let items = document.querySelectorAll('.ball-nav > ul li a'); let anim = null; let currentActiveItem = null; let animate = (from, to, top) => { if (anim) clearInterval(anim); let start = Date.now(); anim = setInterval(() => { let p = Math.min((Date.now() - start) / 500, 1); let e = 1 - Math.pow(1 - p, 3); let x = from + (to - from) * e; let y = -40 * 4 * e * (1 - e); if (from > to) { let = r = -360 * p; } else { let = r = 360 * p; }; nav.style.setProperty('--translate-x', `${x}px`); nav.style.setProperty('--translate-y', `${y + top}px`); nav.style.setProperty('--rotate-x', `${r}deg`); if (p >= 1) { clearInterval(anim); anim = null; } }, 16); }; let getCurrentPosition = () => parseFloat(nav.style.getPropertyValue('--translate-x')) || 0; let getItemCenter = (item) => { return item.getBoundingClientRect().left + item.offsetWidth / 2 - nav.getBoundingClientRect().left; }; let getItemY = (item) => { return item.getBoundingClientRect().top - nav.getBoundingClientRect().top - nav.offsetHeight; }; let moveToItem = (item) => { let current = getCurrentPosition(); let center = getItemCenter(item); let itemY = getItemY(item); animate(current, center, itemY); }; let setActiveItem = (item) => { if (currentActiveItem) { currentActiveItem.classList.remove('active'); } currentActiveItem = item; item.classList.add('active'); moveToItem(item); }; let handleMouseLeave = () => { moveToItem(currentActiveItem); }; items.forEach(item => { item.addEventListener('mouseenter', () => moveToItem(item)); item.addEventListener('mouseleave', handleMouseLeave); item.addEventListener('click', () => setActiveItem(item)); }); nav.addEventListener('mouseleave', handleMouseLeave); setActiveItem(document.querySelector('.ball-nav > ul li a.active')); window.addEventListener('resize', () => setActiveItem(document.querySelector('.ball-nav > ul li a.active'))); }); |
За основу взято решение, найденное на codepen.io у пользователя Daniel Muñoz

Добавить комментарий: