More Navigation Snippets
Floating Dock — Free HTML CSS JS macOS Dock Snippet
Floating Dock · Navigation · Plain HTML, CSS & JS · Live preview
What's included
Features
1 + (MAX_SCALE - 1) * t² where t = 1 - dist/SPREAD — a quadratic falloff that mirrors the physical feel of the macOS Dock precisely.--scale and --ty are set per-icon via JS and consumed by the CSS transform. The CSS transition interpolates between values, eliminating the need for a JS animation loop.element.animate() fires a 3-keyframe bounce on click — scale up 15%, lift 8px, return — without requiring class toggles or event listener cleanup.backdrop-filter: blur(20px) + rgba background + subtle white border creates the frosted-glass dock shelf, matching the macOS aesthetic.translateY negative), so the bottom edges stay aligned to the dock shelf while the tops extend upward — exactly like macOS.tabindex="0" and a keydown handler for Enter/Space — the bounce fires on keyboard activation too.MAX_SCALE (default 1.8) and SPREAD (default 120px) are top-of-file constants — one line to change the effect intensity or reach.About this UI Snippet
Floating Dock — macOS Magnification Effect, Gaussian Proximity Scale & CSS Custom Property Animation

The macOS Dock's icon magnification is one of the most studied interaction effects in UI design — smooth, responsive, and physically intuitive. This snippet reproduces it in pure HTML, CSS, and JavaScript: a glassmorphism toolbar with coloured icon tiles that scale up toward the cursor using a Gaussian proximity formula, lift off the shelf, and bounce on click — with CSS custom properties driving every transform frame.
The macOS Dock icon magnification effect is one of the most recognisable and studied animations in software UI. It demonstrates a core principle: interactions should feel physical, as though the cursor is pushing objects rather than toggling states. This snippet reproduces the full effect — proximity-based magnification, smooth falloff, vertical lift, click bounce, label tooltip, glassmorphism container, and separator line — in pure HTML, CSS, and vanilla JavaScript with zero dependencies.
The magnification math: Gaussian proximity formula
The core of the effect is a distance-based scale calculation. When the cursor is at pixel X, for each dock icon the code computes dist = Math.abs(mouseX - iconCenter). It then computes t = 1 - dist / SPREAD — a linear falloff where t = 1 at the cursor and t = 0 at distance = SPREAD (120px by default). The scale is computed as 1 + (MAX_SCALE - 1) * t * t — squaring t makes the falloff nonlinear (Gaussian-like), so nearby icons grow large quickly while distant icons barely move. The vertical lift is LIFT * t * t — a negative value (−12px) that moves icons upward proportionally to their scale. Both are written to CSS custom properties (--scale and --ty) on each item element so the CSS transform expression reads them: transform: scale(var(--scale)) translateY(var(--ty)).
CSS custom properties as per-element animation state
Writing magnification data to CSS custom properties on individual elements (rather than inline transforms) has an important advantage: the CSS transition declaration on .icon-bg animates between the old and new custom property values automatically. When the cursor moves and --scale updates, the transition interpolates from the previous scale to the new one — giving the spring-ease feel without any JavaScript animation loop. The transition uses cubic-bezier(.34,1.56,.64,1), the same spring-overshoot easing used throughout the snippet collection, which gives the icons a slight bounce when they reach their peak.
The click bounce using Web Animations API
Clicking an icon triggers a programmatic keyframe animation using the Web Animations API (element.animate()). The three keyframes scale the icon up 15% and lift it an extra 8px before returning to the base value. The easing is the same spring cubic-bezier. Using element.animate() for the click bounce is preferable to adding/removing a CSS class because: it doesn't require a transitionend or animationend cleanup listener, it composes with the existing CSS transition without conflict, and it fires once and cleans itself up.
Glassmorphism container
The dock container uses background: rgba(255,255,255,0.08), backdrop-filter: blur(20px), and a 1px border: rgba(255,255,255,0.12) — the standard glassmorphism recipe. Icons are coloured <div> tiles with border-radius: 14px and individual linear-gradient backgrounds, matching the macOS icon aesthetic.
Customising the dock
Change MAX_SCALE (default 1.8) and SPREAD (default 120px) to tune magnification intensity and spread. Increase MAX_SCALE to 2.2 for a more dramatic effect. Change the icon SVGs and gradient colours to match your app. Add or remove .dock-item divs — the layout is display:flex; align-items:flex-end so all icons naturally bottom-align and taller magnified icons push upward rather than downward. Pair with a hamburger nav for a full navigation system.
Step by step
How to Use
- 1Load the snippetPaste the HTML, CSS, and JS into your page. A glassmorphism dock bar appears at the bottom with five colour-coded app icons and a trash icon after a separator.
- 2Move the cursor slowly over the dockIcons near the cursor magnify smoothly up to 1.8× their size and lift slightly off the shelf. Icons further away scale proportionally less — the falloff is Gaussian, not linear.
- 3Move across the full dockAs the cursor moves, the magnification wave follows — each icon grows and shrinks based on its real-time distance from the cursor, just like the macOS Dock.
- 4Click any iconThe clicked icon bounces up 8px and scales to 115% before springing back to its current magnified size, providing satisfying click feedback.
- 5Hover to see the labelA small tooltip label appears above each icon on hover — "Finder", "Terminal", etc. It fades in with a CSS opacity transition.
- 6Customise icons and coloursSwap each
.icon-bggradient and SVG to match your app's icons. AdjustMAX_SCALEandSPREADin the JS to tune the magnification intensity and reach.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Increase MAX_SCALE at the top of the JS (default 1.8). Try 2.2 for a more dramatic macOS-like effect or 1.4 for a subtle zoom. Increase SPREAD (default 120px) to make the magnification wave wider — more icons are affected as the cursor approaches.
Duplicate a .dock-item div in the HTML. Set the data-label attribute for the tooltip text, change the background gradient on .icon-bg, and swap the SVG icon. The JS reads all .dock-item elements automatically.
Setting an inline style.transform directly would conflict with the CSS transition declaration — the browser would skip the transition because the old value is the same inline style that was just overwritten. Writing to CSS custom properties (--scale, --ty) consumed by the CSS transform expression lets the transition engine compare the old and new custom property values and interpolate between them.
Yes. Use the JSX, Vue, Angular, or Tailwind export buttons on this page. In React, attach the mousemove and mouseleave handlers to the dock container via a ref in useEffect with cleanup. Keep the per-icon --scale values in a useRef (not useState) to avoid re-renders on every mouse move — write directly to the DOM element's CSS custom properties for smooth 60fps updates. In Vue, use a template ref and onMounted; in Angular, use @ViewChild and ngAfterViewInit.
Set opacity: 0; transform: translateY(100%) on .dock-wrap by default, then add a :hover or a class that sets opacity: 1; transform: translateY(0). Trigger the class on body:hover or bind it to a bottom-of-screen IntersectionObserver trigger.