أخرى
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 مشاهدة · 0 نسخة
النتيجة
<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();
}
});
انسخ الملف الكامل، والصقه في ملف « index.html » وافتحه في المتصفح.
أكواد أخرى
عرض كل الأكوادتريد هذه التأثيرات في موقعك؟
ننجز موقعك حسب الطلب، سريعًا وبلغتين، مع الحركات التي تصنع الفرق.
اطلب عرض سعر