AI CSS Animations

macOS Glass Dock

A frosted macOS style dock over a drifting wallpaper. Icons magnify under the cursor, neighbors grow a little with :has(), a label pops up, and one app bounces like it is launching.

Also known as: macos dock css, dock magnification css, glass dock css.

HTML

<div class="gls-macos-glass-dock">
  <nav class="gls-macos-glass-dock-dock" aria-label="Dock">
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Files">
      <svg viewBox="0 0 24 24" fill="#fff" aria-hidden="true"><path d="M3 7.5A2.5 2.5 0 0 1 5.5 5H9l2 2h7.5A2.5 2.5 0 0 1 21 9.5v7a2.5 2.5 0 0 1-2.5 2.5h-13A2.5 2.5 0 0 1 3 16.5z"/></svg>
    </a>
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Messages">
      <svg viewBox="0 0 24 24" fill="#fff" aria-hidden="true"><path d="M12 4c4.7 0 8.5 3 8.5 6.8s-3.8 6.8-8.5 6.8c-1 0-2-.1-2.9-.4L4.5 19l1.3-3.4C4.4 14.4 3.5 12.7 3.5 10.8 3.5 7 7.3 4 12 4z"/></svg>
    </a>
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Music">
      <svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 17.5V6l10-2v11.5"/><circle cx="6.5" cy="17.5" r="2.5" fill="#fff"/><circle cx="16.5" cy="15.5" r="2.5" fill="#fff"/></svg>
    </a>
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Photos">
      <svg viewBox="0 0 24 24" aria-hidden="true"><g opacity="0.85"><circle cx="12" cy="7.5" r="4.5" fill="#f59e0b"/><circle cx="16.5" cy="12" r="4.5" fill="#22c55e"/><circle cx="12" cy="16.5" r="4.5" fill="#3b82f6"/><circle cx="7.5" cy="12" r="4.5" fill="#ec4899"/></g></svg>
    </a>
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Calendar">
      <svg viewBox="0 0 24 24" aria-hidden="true"><text x="12" y="8.5" text-anchor="middle" font-family="system-ui, sans-serif" font-size="5.5" font-weight="700" fill="#ef4444">SEP</text><text x="12" y="19.5" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" font-weight="600" fill="#111827">29</text></svg>
    </a>
    <a class="gls-macos-glass-dock-app" href="#" aria-label="Settings">
      <svg viewBox="0 0 24 24" fill="none" stroke="#fff" aria-hidden="true"><circle cx="12" cy="12" r="6.6" stroke-width="3.6" stroke-dasharray="2.6 2.58"/><circle cx="12" cy="12" r="4.2" stroke-width="2.2"/></svg>
    </a>
  </nav>
</div>

CSS

.gls-macos-glass-dock {
  --c: var(--gls-color, #3b82f6);
  font-size: var(--gls-size, 16px);
  position: relative;
  display: grid;
  place-items: center;
  width: 22em;
  height: 12em;
  border-radius: 1.25em;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(170deg, color-mix(in srgb, var(--c) 40%, #1e1b4b), color-mix(in srgb, var(--c) 25%, #6d28d9));
  color: #fff;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.3;
}
.gls-macos-glass-dock::before,
.gls-macos-glass-dock::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
}
.gls-macos-glass-dock::before {
  left: -25%;
  top: 48%;
  width: 95%;
  height: 120%;
  background: linear-gradient(20deg, var(--c), color-mix(in srgb, var(--c) 40%, #fff) 70%);
  box-shadow: 0 0 2em color-mix(in srgb, var(--c) 60%, transparent);
  animation: gls-macos-glass-dock-wave 9s ease-in-out infinite alternate;
}
.gls-macos-glass-dock::after {
  right: -30%;
  top: 38%;
  width: 85%;
  height: 110%;
  background: linear-gradient(200deg, #fde68a, #fb7185 60%);
  box-shadow: 0 0 2em rgb(251 113 133 / 0.5);
  animation: gls-macos-glass-dock-wave 11s ease-in-out -5s infinite alternate-reverse;
}
.gls-macos-glass-dock-dock {
  position: absolute;
  left: 50%;
  bottom: 0.6em;
  display: flex;
  align-items: flex-end;
  gap: 0.4em;
  padding: 0.38em 0.45em 0.5em;
  border-radius: 1.05em;
  translate: -50% 0;
  background: color-mix(in srgb, #fff 18%, transparent);
  -webkit-backdrop-filter: blur(0.9em) saturate(1.5);
  backdrop-filter: blur(0.9em) saturate(1.5);
  border: 1px solid color-mix(in srgb, #fff 45%, transparent);
  box-shadow: 0 0.5em 1.5em -0.5em rgb(0 0 0 / 0.35), inset 0 1px 0 color-mix(in srgb, #fff 55%, transparent);
}
.gls-macos-glass-dock-app {
  position: relative;
  display: grid;
  place-items: center;
  width: 2.2em;
  height: 2.2em;
  border-radius: 0.55em;
  background: var(--tile);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.5), 0 0.15em 0.35em rgb(0 0 0 / 0.3);
  transform-origin: 50% 100%;
  transition: scale 0.25s ease, translate 0.25s ease, margin 0.25s ease;
}
.gls-macos-glass-dock-app svg { width: 1.35em; height: 1.35em; }
.gls-macos-glass-dock-app:nth-child(1) { --tile: linear-gradient(180deg, color-mix(in srgb, var(--c) 45%, #fff), var(--c)); }
.gls-macos-glass-dock-app:nth-child(2) { --tile: linear-gradient(180deg, #86efac, #16a34a); }
.gls-macos-glass-dock-app:nth-child(3) { --tile: linear-gradient(180deg, #fda4af, #e11d48); }
.gls-macos-glass-dock-app:nth-child(4) {
  --tile: #fff;
  animation: gls-macos-glass-dock-launch 4s linear infinite;
}
.gls-macos-glass-dock-app:nth-child(5) { --tile: #fff; }
.gls-macos-glass-dock-app:nth-child(6) { --tile: linear-gradient(180deg, #d1d5db, #6b7280); }
/* running indicator */
.gls-macos-glass-dock-app:nth-child(-n + 3)::before,
.gls-macos-glass-dock-app:nth-child(4)::before {
  content: "";
  position: absolute;
  bottom: -0.32em;
  width: 0.2em;
  height: 0.2em;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.85);
}
/* app name above the hovered icon */
.gls-macos-glass-dock-app::after {
  content: attr(aria-label);
  position: absolute;
  bottom: calc(100% + 0.5em);
  padding: 0.3em 0.6em;
  border-radius: 0.5em;
  background: rgb(15 23 42 / 0.6);
  color: #fff;
  font-size: 0.4em;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  translate: 0 0.3em;
  transition: opacity 0.2s ease, translate 0.2s ease;
  pointer-events: none;
}
.gls-macos-glass-dock-app:hover {
  scale: 1.45;
  translate: 0 -0.3em;
  margin-inline: 0.5em;
}
.gls-macos-glass-dock-app:hover::after { opacity: 1; translate: 0 0; }
.gls-macos-glass-dock-app:has(+ .gls-macos-glass-dock-app:hover),
.gls-macos-glass-dock-app:hover + .gls-macos-glass-dock-app {
  scale: 1.2;
  translate: 0 -0.12em;
  margin-inline: 0.22em;
}
.gls-macos-glass-dock-app:focus-visible { outline: 2px solid #fff; outline-offset: 0.15em; }
@keyframes gls-macos-glass-dock-launch {
  0%, 36%, 100% { transform: translateY(0); animation-timing-function: ease-out; }
  6% { transform: translateY(-0.9em); animation-timing-function: ease-in; }
  12% { transform: translateY(0); animation-timing-function: ease-out; }
  18% { transform: translateY(-0.9em); animation-timing-function: ease-in; }
  24% { transform: translateY(0); animation-timing-function: ease-out; }
  30% { transform: translateY(-0.9em); animation-timing-function: ease-in; }
}
@keyframes gls-macos-glass-dock-wave {
  to { transform: translate(12%, -8%) rotate(8deg); }
}

@media (prefers-reduced-motion: reduce) {
  .gls-macos-glass-dock, .gls-macos-glass-dock *, .gls-macos-glass-dock::before, .gls-macos-glass-dock::after, .gls-macos-glass-dock *::before, .gls-macos-glass-dock *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --gls-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --gls-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar glass effects