Aller au contenu

Autres

Footer en verre liquide

Footer en verre dépoli : bord liquide qui ondule, lentille qui suit la souris, newsletter et thème sombre qui se répand en cercle. HTML, CSS et JavaScript.

0 vue · 0 copie

Partager

Résultat

Plein écran
<div class="room">
  <!-- Décor : étagères, TV, lampe (100 % CSS) -->
  <div class="shelf left"><i></i><i></i><i></i></div>
  <div class="shelf right"><i></i><i></i><i></i></div>
  <div class="screen"></div>
  <div class="lamp"></div>

  <footer class="liquid" id="footer">
    <span class="drop d1"></span>
    <span class="drop d2"></span>
    <span class="drop d3"></span>
    <span class="lens" id="lens"></span>

    <div class="top">
      <section class="newsletter">
        <div class="brand"><span class="logo">T</span>TAPLA</div>
        <h2 class="headline" id="headline">One good idea, every Friday.</h2>
        <form class="subscribe" id="subscribe" novalidate>
          <input type="email" id="email" placeholder="you@email.com" aria-label="Email" autocomplete="email">
          <button type="submit">Subscribe</button>
        </form>
        <p class="note" id="note">Two minutes to read. Unsubscribe anytime.</p>
      </section>

      <nav class="links glass-card" aria-label="Footer">
        <div><h3>Product</h3><a href="#">Overview</a><a href="#">Websites</a><a href="#">Digital menu</a><a href="#">Loyalty</a><a href="#">ERP</a></div>
        <div><h3>Company</h3><a href="#">About</a><a href="#">Careers <em>Hiring</em></a><a href="#">Press</a><a href="#">Partners</a></div>
        <div><h3>Resources</h3><a href="#">Help Center</a><a href="#">Free codes</a><a href="#">Changelog</a><a href="#">Security</a></div>
        <div><h3>Legal</h3><a href="#">Privacy</a><a href="#">Terms</a><a href="#">Cookies</a><a href="#">Licenses</a></div>
      </nav>
    </div>

    <div class="bar">
      <p class="copy">© 2026 TAPLA <span class="status"><i></i>All systems normal</span></p>
      <div class="bar-right">
        <div class="socials glass-card">
          <a href="#" aria-label="X"><svg viewBox="0 0 24 24"><path d="M4 4l16 16M20 4L4 20" /></svg></a>
          <a href="#" aria-label="LinkedIn"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="3" /><path d="M8 10v7M8 7v.01M12 17v-4a2 2 0 0 1 4 0v4M12 10v7" /></svg></a>
          <a href="#" aria-label="GitHub"><svg viewBox="0 0 24 24"><path d="M9 19c-4 1.3-4-2-6-2.5m12 5v-3.5a3 3 0 0 0-.9-2.4c3-.3 6-1.5 6-6.6a5 5 0 0 0-1.4-3.6 4.7 4.7 0 0 0-.1-3.6s-1.1-.3-3.6 1.4a12.4 12.4 0 0 0-6.5 0C6 2.5 4.9 2.8 4.9 2.8a4.7 4.7 0 0 0-.1 3.6A5 5 0 0 0 3.4 10c0 5.1 3 6.3 6 6.6a3 3 0 0 0-.9 2.4V22" /></svg></a>
          <a href="#" aria-label="Instagram"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><path d="M17.5 6.5v.01" /></svg></a>
          <a href="#" aria-label="YouTube"><svg viewBox="0 0 24 24"><rect x="2.5" y="5.5" width="19" height="13" rx="4" /><path d="M10 9.5v5l4.5-2.5z" /></svg></a>
        </div>
        <label class="theme">
          <span>Evening</span>
          <input type="checkbox" id="theme" role="switch">
          <span class="switch"><i></i></span>
        </label>
      </div>
    </div>

    <div class="giant" aria-hidden="true">TAPLA</div>
  </footer>
</div>
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap");

* { box-sizing: border-box; }

@property --wave {
  syntax: "<length>";
  initial-value: 34px;
  inherits: false;
}

/* Thème clair (jour) et sombre (« Evening ») */
:root {
  --glass: rgba(255, 248, 240, .30);
  --glass-strong: rgba(255, 250, 244, .46);
  --line: rgba(255, 255, 255, .55);
  --text: #1c1714;
  --muted: rgba(28, 23, 20, .62);
  --input: rgba(40, 32, 26, .55);
  --giant-a: rgba(255, 255, 255, .85);
  --giant-b: rgba(120, 90, 60, .35);
}
:root.evening {
  --glass: rgba(18, 16, 15, .58);
  --glass-strong: rgba(28, 25, 23, .62);
  --line: rgba(255, 255, 255, .16);
  --text: #f5f1ec;
  --muted: rgba(245, 241, 236, .6);
  --input: rgba(255, 255, 255, .1);
  --giant-a: rgba(255, 255, 255, .35);
  --giant-b: rgba(255, 255, 255, .05);
}

body {
  margin: 0;
  min-height: 100vh;
  background: #2b2119;
  font-family: "Inter", system-ui, sans-serif;
  color: var(--text);
}

/* ---------- Décor du salon ---------- */
.room {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 120px 14px 14px;
  overflow: hidden;
  background:
    radial-gradient(ellipse 40% 30% at 20% 15%, rgba(255, 210, 160, .35), transparent 70%),
    linear-gradient(180deg, #e9e1d6 0%, #d8ccbd 45%, #a98b6c 46%, #8a6c50 100%);
}
.shelf { position: absolute; top: 40px; width: 18%; height: 46%; border: 10px solid #6b4a30; border-top-width: 14px; background: #f1ebe3; }
.shelf.left { left: 6%; }
.shelf.right { right: 6%; }
.shelf i { display: block; height: 10px; margin-top: 28%; background: #6b4a30; box-shadow: 0 14px 18px rgba(255, 190, 120, .55); }
.screen { position: absolute; top: 18%; left: 30%; width: 40%; height: 30%; border-radius: 6px; background: linear-gradient(160deg, #26221f, #0e0d0c); box-shadow: 0 20px 40px rgba(0, 0, 0, .35); }
.lamp { position: absolute; top: 12%; left: 76%; width: 34px; height: 34px; border-radius: 50%; background: #fff3dc; box-shadow: 0 0 60px 30px rgba(255, 210, 150, .45); }

/* ---------- Le footer en verre liquide ---------- */
.liquid {
  --wave: 34px;
  position: relative;
  z-index: 1;
  padding: 40px clamp(18px, 3vw, 34px) 0;
  border-radius: 30px;
  background: var(--glass);
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 30px 60px rgba(40, 25, 10, .35);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
          backdrop-filter: blur(22px) saturate(160%);
  overflow: hidden;
  transition: background .5s ease, border-color .5s ease;
  /* Bord supérieur en vague : la bande ondulée rétrécit jusqu'à disparaître (bord droit) */
  -webkit-mask:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 30' preserveAspectRatio='none'%3E%3Cpath d='M0 30V16Q25 2 50 16T100 16T150 16T200 16V30Z'/%3E%3C/svg%3E") 0 0 / 420px var(--wave) repeat-x,
    linear-gradient(#000 0 0) 0 var(--wave) / 100% 100% no-repeat;
          mask:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 30' preserveAspectRatio='none'%3E%3Cpath d='M0 30V16Q25 2 50 16T100 16T150 16T200 16V30Z'/%3E%3C/svg%3E") 0 0 / 420px var(--wave) repeat-x,
    linear-gradient(#000 0 0) 0 var(--wave) / 100% 100% no-repeat;
  animation: rise 1.1s cubic-bezier(.2, .9, .25, 1) both, flatten 1.3s ease-out .5s forwards, flow 1.6s linear 2;
}

/* Gouttes de verre sur le bord */
.drop {
  position: absolute;
  top: 6px;
  z-index: 3;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, .95), rgba(255, 255, 255, .25) 35%, rgba(255, 255, 255, .08) 70%);
  border: 1px solid rgba(255, 255, 255, .6);
  box-shadow: inset -3px -4px 8px rgba(0, 0, 0, .15), 0 6px 14px rgba(0, 0, 0, .15);
  opacity: 0;
  animation: drop-in .8s cubic-bezier(.3, 1.6, .5, 1) forwards, bob 4s ease-in-out infinite;
}
.d1 { left: 21%; width: 26px; height: 22px; animation-delay: 1s, 1.8s; }
.d2 { left: 56%; width: 14px; height: 12px; animation-delay: 1.2s, 2.2s; }
.d3 { right: 9%; width: 18px; height: 16px; animation-delay: 1.35s, 2.6s; }

/* Lentille liquide qui suit la souris */
.lens {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 4;
  width: 130px;
  height: 130px;
  margin: -65px 0 0 -65px;
  border-radius: 50%;
  pointer-events: none;
  background:
    repeating-radial-gradient(circle, transparent 0 14px, rgba(255, 255, 255, .07) 15px 16px, transparent 17px 22px),
    radial-gradient(circle at 40% 35%, rgba(255, 255, 255, .25), transparent 55%);
  border: 1px solid rgba(255, 255, 255, .35);
  box-shadow: inset 0 0 30px rgba(255, 255, 255, .18), inset 0 -10px 30px rgba(0, 0, 0, .18), 0 10px 30px rgba(0, 0, 0, .12);
  -webkit-backdrop-filter: blur(1.5px) brightness(1.08) saturate(1.6) contrast(1.05);
          backdrop-filter: blur(1.5px) brightness(1.08) saturate(1.6) contrast(1.05);
  opacity: 0;
  transform: translate(var(--lx, 50%), var(--ly, 50%)) scale(var(--ls, .6));
  transition: opacity .35s ease;
}
.liquid.is-hover .lens { opacity: 1; }

/* ---------- Contenu ---------- */
.top {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.4fr);
  gap: clamp(18px, 4vw, 54px);
  align-items: start;
}

.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 15px; letter-spacing: .02em; animation: fade-up .6s ease 1.1s both; }
.logo {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: linear-gradient(135deg, #2fa58a, #0e5b4a); color: #fff; font-size: 14px; font-weight: 800;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4);
}

.headline { margin: 18px 0 18px; font-size: clamp(26px, 3.4vw, 38px); line-height: 1.12; font-weight: 700; letter-spacing: -.02em; }
.headline span { display: inline-block; opacity: 0; filter: blur(8px); transform: translateY(10px); animation: word .6s ease forwards; }

.subscribe {
  display: flex;
  gap: 6px;
  max-width: 360px;
  padding: 5px;
  border-radius: 99px;
  background: var(--input);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .25);
  animation: fade-up .6s ease 1.7s both;
  transition: background .5s ease;
}
.subscribe input {
  flex: 1; min-width: 0; padding: 0 14px; border: 0; outline: none; background: none;
  font: 500 13px "Inter", sans-serif; color: #fff;
}
.subscribe input::placeholder { color: rgba(255, 255, 255, .6); }
.subscribe button {
  padding: 10px 18px; border: 0; border-radius: 99px; background: #15110e; color: #fff;
  font: 600 12.5px "Inter", sans-serif; cursor: pointer; transition: transform .2s, background .3s;
}
.subscribe button:hover { transform: scale(1.04); }
.subscribe.is-error { animation: shake .4s ease; box-shadow: 0 0 0 2px #f87171; }
.subscribe.is-done button { background: #16a34a; }
.note { margin: 10px 0 0 14px; font-size: 11.5px; color: var(--muted); animation: fade-up .6s ease 1.8s both; }

.glass-card {
  background: var(--glass-strong);
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), 0 10px 30px rgba(0, 0, 0, .08);
  transition: background .5s ease, border-color .5s ease;
}
.links {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  padding: 22px 24px;
  border-radius: 20px;
  animation: card-in .8s cubic-bezier(.2, .9, .3, 1.1) 1.2s both;
}
.links h3 { margin: 0 0 10px; font-size: 11px; font-weight: 500; color: var(--muted); }
.links a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  padding: 4px 0;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  transition: transform .25s ease, color .25s;
}
.links a::after {
  content: ""; position: absolute; left: 0; bottom: 1px; width: 100%; height: 1.5px; border-radius: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform .3s ease;
}
.links a:hover { transform: translateX(3px); }
.links a:hover::after { transform: scaleX(1); }
.links em {
  padding: 2px 6px; border-radius: 99px; background: #0f766e; color: #fff;
  font: 600 9px/1.2 "Inter", sans-serif; font-style: normal;
}

/* ---------- Barre du bas ---------- */
.bar {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 28px;
  animation: fade-up .6s ease 1.9s both;
}
.copy { margin: 0; font-size: 12px; color: var(--muted); }
.status { margin-left: 14px; color: var(--text); font-weight: 500; }
.status i { display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 0 0 rgba(34, 197, 94, .6); animation: ping 2s ease-out infinite; }

.bar-right { display: flex; align-items: center; gap: 14px; }
.socials { display: flex; gap: 2px; padding: 4px; border-radius: 99px; }
.socials a { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; color: var(--text); transition: background .2s, transform .25s; }
.socials a:hover { background: rgba(255, 255, 255, .35); transform: translateY(-2px); }
.socials svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.theme { display: flex; align-items: center; gap: 9px; font-size: 12px; color: var(--muted); cursor: pointer; }
.theme input { position: absolute; opacity: 0; pointer-events: none; }
.switch {
  position: relative; width: 40px; height: 22px; border-radius: 99px;
  background: rgba(255, 255, 255, .5); border: 1px solid var(--line);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2); transition: background .35s;
}
.switch i {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; box-shadow: 0 2px 5px rgba(0, 0, 0, .3);
  transition: transform .45s cubic-bezier(.3, 1.6, .5, 1);
}
.theme input:checked + .switch { background: #2c2724; }
.theme input:checked + .switch i { transform: translateX(18px); }
.theme input:focus-visible + .switch { outline: 2px solid #22c55e; outline-offset: 2px; }

/* ---------- Mot géant en verre ---------- */
.giant {
  position: relative;
  z-index: 1;
  margin: 14px 0 -0.18em;
  text-align: center;
  font-size: clamp(90px, 21vw, 300px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.04em;
  color: transparent;
  background: linear-gradient(180deg, var(--giant-a), var(--giant-b) 70%), linear-gradient(100deg, transparent 35%, rgba(255, 255, 255, .7) 50%, transparent 65%);
  background-size: 100% 100%, 250% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  filter: drop-shadow(0 1px 0 rgba(255, 255, 255, .5)) drop-shadow(0 10px 20px rgba(0, 0, 0, .18));
  animation: giant-in 1.2s cubic-bezier(.2, .9, .3, 1) 1.4s both, shine 5s ease-in-out 2.6s infinite;
  user-select: none;
}

/* ---------- Changement de thème : vague sombre depuis l'interrupteur ---------- */
::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-new(root) { animation: reveal .9s cubic-bezier(.6, 0, .2, 1) both; }

/* ---------- Téléphone ---------- */
@media (max-width: 760px) {
  .top { grid-template-columns: minmax(0, 1fr); }
  .links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bar { flex-direction: column; align-items: flex-start; }
  .bar-right { width: 100%; justify-content: space-between; }
  .room { padding-top: 70px; }
}

/* ---------- Animations ---------- */
@keyframes rise { from { transform: translateY(110%); } to { transform: none; } }
@keyframes flatten { to { --wave: 0px; } }
@keyframes flow { to { -webkit-mask-position: -420px 0, 0 var(--wave); mask-position: -420px 0, 0 var(--wave); } }
@keyframes drop-in { from { opacity: 0; transform: translateY(16px) scale(.3); } to { opacity: 1; transform: none; } }
@keyframes bob { 50% { translate: 0 -4px; } }
@keyframes fade-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes card-in { from { opacity: 0; transform: translateY(20px) scale(.97); filter: blur(6px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes word { to { opacity: 1; filter: blur(0); transform: none; } }
@keyframes giant-in { from { opacity: 0; transform: translateY(40%); filter: blur(10px); } to { opacity: 1; transform: none; } }
@keyframes shine { 0%, 60% { background-position: 0 0, 120% 0; } 100% { background-position: 0 0, -120% 0; } }
@keyframes ping { 70% { box-shadow: 0 0 0 7px rgba(34, 197, 94, 0); } 100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); } }
@keyframes shake { 25%, 75% { transform: translateX(-5px); } 50% { transform: translateX(5px); } }
@keyframes reveal { from { clip-path: circle(0 at var(--tx, 90%) var(--ty, 90%)); } to { clip-path: circle(150% at var(--tx, 90%) var(--ty, 90%)); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0s !important; transition-duration: .01ms !important; }
}
// Liquid Glass Footer — vanilla JS
const footer = document.getElementById('footer');
const lens = document.getElementById('lens');

// ---------- Titre : les mots apparaissent un par un (flou → net) ----------
const headline = document.getElementById('headline');
headline.innerHTML = headline.textContent.trim().split(/\s+/)
  .map((w, i) => `<span style="animation-delay:${(1.25 + i * 0.09).toFixed(2)}s">${w}</span>`)
  .join(' ');

// ---------- Lentille liquide : suit la souris avec inertie, grossit avec la vitesse ----------
let target = { x: 0, y: 0 };
let pos = { x: 0, y: 0 };
let scale = 0.6;
let running = false;

function frame() {
  const dx = target.x - pos.x;
  const dy = target.y - pos.y;
  pos.x += dx * 0.16;
  pos.y += dy * 0.16;
  const speed = Math.min(Math.hypot(dx, dy) / 60, 1);
  scale += ((0.85 + speed * 0.35) - scale) * 0.12;
  lens.style.setProperty('--lx', `${pos.x}px`);
  lens.style.setProperty('--ly', `${pos.y}px`);
  lens.style.setProperty('--ls', scale.toFixed(3));
  if (Math.abs(dx) + Math.abs(dy) > 0.3 || footer.classList.contains('is-hover')) {
    requestAnimationFrame(frame);
  } else {
    running = false;
  }
}

footer.addEventListener('pointermove', (e) => {
  if (e.pointerType === 'touch') return;
  const r = footer.getBoundingClientRect();
  target = { x: e.clientX - r.left, y: e.clientY - r.top };
  if (!footer.classList.contains('is-hover')) {
    pos = { ...target };
    footer.classList.add('is-hover');
  }
  if (!running) { running = true; requestAnimationFrame(frame); }
});
footer.addEventListener('pointerleave', () => footer.classList.remove('is-hover'));

// ---------- Newsletter ----------
const form = document.getElementById('subscribe');
const email = document.getElementById('email');
const note = document.getElementById('note');

form.addEventListener('submit', (e) => {
  e.preventDefault();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email.value.trim())) {
    form.classList.remove('is-error'); void form.offsetWidth; form.classList.add('is-error');
    email.focus();
    return;
  }
  form.classList.remove('is-error');
  form.classList.add('is-done');
  form.querySelector('button').textContent = 'Subscribed ✓';
  note.textContent = 'Thanks! See you on Friday.';
  email.value = '';
  // Ici : envoyez l'adresse à votre service d'e-mails.
});
email.addEventListener('input', () => form.classList.remove('is-error'));

// ---------- Thème « Evening » : la nuit se répand depuis l'interrupteur ----------
const toggle = document.getElementById('theme');

toggle.addEventListener('change', () => {
  const r = toggle.nextElementSibling.getBoundingClientRect();
  const root = document.documentElement;
  root.style.setProperty('--tx', `${((r.left + r.width / 2) / innerWidth) * 100}%`);
  root.style.setProperty('--ty', `${((r.top + r.height / 2) / innerHeight) * 100}%`);

  const apply = () => root.classList.toggle('evening', toggle.checked);
  if (document.startViewTransition && !matchMedia('(prefers-reduced-motion: reduce)').matches) {
    document.startViewTransition(apply);
  } else {
    apply();
  }
});

Copiez le fichier complet, collez-le dans un fichier « index.html » et ouvrez-le dans votre navigateur.

Autres codes

Voir tous les codes

Vous voulez ces effets sur votre site ?

On crée votre site sur mesure, rapide et bilingue, avec les animations qui font la différence.

Demander un devis