<main id=app>
  
  <h1>Gooey Navigation</h1>
  <p>Not very practical unless you change the <code>--distance</code> to something like <code>-35%</code>, <br>but a fun little experiment none-the-less!</p>
  
  <nav>
    <!-- gooey menu background -->
    <aside class="goo">
      <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </aside>
    <!-- actual menu, cannot be inside gooey due to svg filter -->
    <ul class="menu">
      <li><a href="#">
        <svg viewBox="0 0 24 24"><use href="#home" /></svg></a></li>
      <li><a href="#">
        <svg viewBox="0 0 24 24"><use href="#heart" /></svg></a></li>
      <li><a href="#">
        <svg viewBox="0 0 24 24"><use href="#bag" /></svg></a></li>
      <li><a href="#">
        <svg viewBox="0 0 24 24"><use href="#settings" /></svg></a></li>
    </ul>
  </nav>
  
</main>


<svg viewBox="0 0 24 24">
  
  <!-- filter to make gooey effect -->
  <filter id="schlurp">
    <feGaussianBlur id="SourceGraphic" stdDeviation="10" />
    <feColorMatrix values="
       1 0 0 0 0
       0 1 0 0 0
       0 0 1 0 0 
       0 0 0 20 -10
    " />
  </filter>
  
  <defs>
    <g id="home">
      <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
      <polyline points="9 22 9 12 15 12 15 22" />
    </g>
    <g id="heart">
      <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
    </g>
    <g id="bag">
      <path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" />
      <line x1="3" y1="6" x2="21" y2="6" />
      <path d="M16 10a4 4 0 0 1-8 0" />
    </g>
    <g id="settings">
      <line x1="4" y1="21" x2="4" y2="14" />
      <line x1="4" y1="10" x2="4" y2="3" />
      <line x1="12" y1="21" x2="12" y2="12" />
      <line x1="12" y1="8" x2="12" y2="3" />
      <line x1="20" y1="21" x2="20" y2="16" />
      <line x1="20" y1="12" x2="20" y2="3" />
      <line x1="1" y1="14" x2="7" y2="14" />
      <line x1="9" y1="8" x2="15" y2="8" />
      <line x1="17" y1="16" x2="23" y2="16" />
    </g>
  </defs>
  
</svg>
:root {
  --default: #00ffc3;
  --hover: #efceff;
  --size: 80px;
  --distance: calc(var(--size) * -.8);
  --spring-easing: linear(
    0, 0.807 3.1%, 1.234 5.2%, 1.391, 1.505, 1.576 8.3%, 1.596, 1.607 9.4%, 1.608,
    1.606 10.1%, 1.589, 1.557, 1.508 12.3%, 1.393 13.8%, 1.057 17.5%, 0.91 19.6%,
    0.861, 0.825, 0.801, 0.788 23.4%, 0.787, 0.789, 0.797 25.3%, 0.81 26.1%,
    0.849 27.6%, 0.969 31.5%, 1.02 33.3%, 1.042, 1.058, 1.068, 1.074 37.6% 38.9%,
    1.067 40.3%, 1.053 41.9%, 1.011 45.7%, 0.993, 0.98, 0.974 51.7% 53.1%,
    0.977 54.6%, 1.002 61.8%, 1.007, 1.009 65.7%, 1.008 68.9%, 0.999 75.9%,
    0.997 79.8%, 1.001 92.7% 100%
  );
  --duration: 3s;
}

.goo,
.goo ul {
  background: inherit;
  filter: url("#schlurp"); // this is reference to svg filter in HTML.
}

ul {
  display: flex;
  justify-content: center;
  background: inherit;
  padding: 0 calc(var(--size) / 2);
  li {
    width: var(--size);
    height: var(--size);
    background: var(--default);
    margin: 0 3px;
    color: black;
    position: relative;
  }
}

.goo ul li {
  &:before {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    border-radius: 100%;
    background: inherit;
    transition: all 0.85s ease;
    transform: translate3d(0, 0, 0); // performance / stability
    will-change: transform; // performance / stability
    backface-visibility: hidden; // performance / stability
  }
  &.hover:before {
    transition: all var(--duration) var(--spring-easing);
    transform: translate3d(0, var(--distance), 0);
    background: var(--hover);
  }
}

.menu {
  position: absolute;
  z-index: 1;
  background: transparent;
  text-align: center;
  // overflow: hidden;
}

.menu li {
  background: transparent;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  transition: all 0.85s ease;
  height: calc(var(--size) * 2);

  &:hover {
    transition: all calc( var(--duration) - 0.2s ) var(--spring-easing);
    transform: translate3d(0, var(--distance), 0);
    color: white;
  }

  a {
    display: grid;
    grid-template-rows: 1fr 1fr;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: rgba(0, 0, 0, 0.6);
    transition: color 0.5s ease;
    width: 100%;
    height: 100%;
  }
  &:hover a {
    color: rgba(0, 0, 0, 0.9);
  }
}

nav {
  display: flex;
  justify-content: center;
  margin: 0;
  background: var(--default);
  position: fixed;
  bottom: 0px;
  left: 0px;
  right: 0px;
}












/* unimportant styles */

body {
  color: white;
  background: #333844;
  padding: 20px 0;
  font-family: "Heebo", sans-serif;
  display: flex;
  justify-content: center;
  text-align: center;
}

p {
  max-width: 70ch;
  font-weight: 200;
}

ul {
  list-style: none;
  margin: 0;
}

svg {
  width: calc(var(--size)/3);
  height: calc(var(--size)/3);
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
View Compiled
/*

The transition seems to have some rendering/performance issues 
in Chrome due to GPU layers, but works 😚👌 in FireFox.

*/










// need a tiny bit of JS to make both menus activate together.
// feel free to comment if you figure out another way.

$(".menu li").on("mouseover touchstart", function() {
  let idx = $(this).index();
  $(".goo li").removeClass("hover");
  $("nav li").eq(idx).addClass("hover");
}).on("mouseout touchend", function() {
  $("nav li").removeClass("hover");
});

External CSS

  1. https://fonts.googleapis.com/css?family=Heebo:100,300,400,500,700,800,900

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js