Free
Footer
Velisse Footer
A footer block extracted from the Velisse template, available in Tailwind CSS and Bootstrap.
0
3
A footer block extracted from the Velisse template, available in Tailwind CSS and Bootstrap.
<!DOCTYPE html>
<html lang="en">
<head>
<script>
window.FontAwesomeConfig = { autoReplaceSvg: 'nest' };
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Velisse Footer | Tailwind CSS UI Block</title>
<meta name="description" content="A footer block extracted from the Velisse template, available in Tailwind CSS and Bootstrap.">
<meta name="keywords" content="Velisse, Tailwind CSS template, HTML website template, beauty salon template, hair salon, makeup studio, skincare clinic, nail studio, spa website">
<meta name="author" content="Let's templates">
<link rel="canonical" href="">
<meta property="og:type" content="product">
<meta property="og:site_name" content="Let's templates">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="">
<meta property="og:title" content="Velisse | Tailwind CSS Health & Fitness Template">
<meta property="og:description" content="An elegant Tailwind CSS beauty salon template with an editorial portrait hero, treatment cards, a tabbed price list and online booking.">
<meta property="og:image" content="">
<meta property="og:image:alt" content="Velisse template preview">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="">
<meta name="twitter:title" content="Velisse | Tailwind CSS Health & Fitness Template">
<meta name="twitter:description" content="An elegant Tailwind CSS beauty salon template with an editorial portrait hero, treatment cards, a tabbed price list and online booking.">
<meta name="twitter:image" content="">
<meta name="twitter:image:alt" content="Velisse template preview">
<script src="https://cdn.tailwindcss.com/3.4.17"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Bodoni+Moda:ital,wght@0,400;0,500;1,400&family=Urbanist:wght@400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: { gold: '#d4a72c', ink: '#1d1d1f', smoke: '#7a7a7d', mist: '#eceef0', pearl: '#f6f6f4' },
fontFamily: { serif: ['"Bodoni Moda"', 'serif'], sans: ['Urbanist', 'sans-serif'] }
}
}
}
</script>
<style>
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: 180ms ease-out both page-fade-out; }
::view-transition-new(root) { animation: 220ms ease-in both page-fade-in; }
@keyframes page-fade-out { to { opacity: 0; } }
@keyframes page-fade-in { from { opacity: 0; } }
html { scroll-behavior: smooth; }
.hero-glow { background: radial-gradient(120% 90% at 45% 40%, #fbfbfa 0%, #e9eaeb 55%, #a9acaf 100%); }
.price-row { background-image: radial-gradient(circle, #b9b9bb 1px, transparent 1.2px); background-size: 7px 2px; background-repeat: repeat-x; background-position: 0 72%; }
.reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; transition-delay: var(--reveal-delay, 0ms); }
.reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
</style>
</head>
<body class="bg-pearl font-sans text-ink antialiased">
<% active_page = "index" %>
<% { "index" => "Home", "team" => "Our Team", "services" => "Services", "prices" => "Prices", "contact" => "Contact" }.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% { "index" => "Home", "team" => "Our Team", "services" => "Services", "prices" => "Prices", "contact" => "Contact" }.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% [["12", "Years of craft"], ["9", "Specialists"], ["4.9", "Guest rating"]].each do |value, label| %>
<% end %>
<% [
["Hair styling", "Cuts, colour and updos shaped to your face and lifestyle.", "1562322140-8baeececf3df", "Stylist blow-drying a guest's hair", "services.html"],
["Signature facial", "A deep-cleansing ritual that leaves skin calm and luminous.", "1616394584738-fc6e612e71b9", "Guest relaxing during a facial with a cream mask", "signature-facial.html"],
["Bridal styling", "Hair and makeup trials and wedding-day styling at our studio or yours.", "1487412947147-5cebf100ffc2", "Makeup artist applying lipstick to a bride", "bridal-styling.html"],
["Nail care", "Long-lasting manicures and nail art in a calm, clean room.", "1604654894610-df63bc536371", "Hands with glossy black and tortoiseshell nails", "services.html"],
["Body rituals", "Scrubs, wraps and foot treatments to reset tired skin.", "1519415510236-718bdfcd89c8", "Feet resting in a bowl with fresh flowers", "services.html"],
["Makeup lessons", "One-to-one sessions to master your everyday look.", "1516975080664-ed2fc6a32937", "Makeup brushes arranged in a holder", "services.html"]
].each_with_index do |(title, copy, image, alt, href), index| %>
<% end %>
<% price_lists = {
"Hair" => [["Women's cut & finish", "$85"], ["Men's cut", "$55"], ["Full colour", "$140"], ["Balayage", "$220"], ["Blow-dry", "$45"]],
"Face" => [["Signature facial", "$120"], ["Express glow", "$70"], ["Brow shaping", "$30"], ["Lash lift", "$75"]],
"Nails" => [["Gel manicure", "$50"], ["Classic pedicure", "$55"], ["Nail art (from)", "$15"], ["Removal", "$15"]],
"Body" => [["Body scrub", "$90"], ["Detox wrap", "$110"], ["Foot ritual", "$60"]]
} %>
<% price_lists.keys.each_with_index do |name, index| %>
<% end %>
<% price_lists.each_with_index do |(name, items), index| %>
<% items.each do |item, price| %>
<% end %>
<% end %>
<% [["Amara Diallo", "Founder & colourist", 4], ["Léa Martin", "Skin therapist", 2], ["Sofia Rossi", "Makeup artist", 5], ["Noah Kim", "Senior stylist", 3]].each_with_index do |(name, role, avatar), index| %>
<% end %>
<% [
["I left feeling looked after, not processed. The facial was the calmest hour of my month.", "Grace O.", "Signature facial"],
["Amara finally got my colour right after years of brassy results. I'm never going anywhere else.", "Jules P.", "Full colour"],
["Sofia did my bridal makeup and it lasted through tears, dancing and a rainy photo shoot.", "Hannah L.", "Bridal styling"]
].each do |quote, name, service| %>
<% end %>
<!-- block:start footer -->
<footer class="bg-pearl">
<div class="mx-auto grid max-w-7xl gap-10 px-5 py-16 md:grid-cols-4 md:px-10">
<div class="md:col-span-2">
<a href="index.html" class="flex items-center gap-3">
<span class="grid h-11 w-11 place-items-center rounded-full border-2 border-ink font-serif text-lg italic">V</span>
<span class="text-xl font-medium tracking-[0.3em]">VLS</span>
</a>
<p class="mt-5 max-w-sm text-ink/70">Hair, skin, nails and makeup in a calm studio where every guest gets our full attention.</p>
</div>
<div>
<h2 class="font-serif text-xl">Visit</h2>
<address class="mt-4 not-italic leading-relaxed text-ink/70">48 Rue des Lilas<br>Montréal, QC H2T 1S6</address>
<a href="tel:+15145550163" class="mt-2 block text-ink/70 hover:text-gold">+1 (514) 555-0163</a>
</div>
<div>
<h2 class="font-serif text-xl">Hours</h2>
<p class="mt-4 leading-relaxed text-ink/70">Tue–Fri 10:00–20:00<br>Sat 9:00–17:00<br>Sun–Mon closed</p>
</div>
</div>
<div class="border-t border-ink/10">
<div class="mx-auto flex max-w-7xl flex-col gap-3 px-5 py-6 text-sm text-smoke md:flex-row md:items-center md:justify-between md:px-10">
<p>© <span data-current-year>2026</span> Velisse Beauty Studio</p>
<ul class="flex gap-6 font-serif text-base text-ink">
<li><a href="https://twitter.com" class="hover:text-gold">Tw</a></li>
<li><a href="https://instagram.com" class="hover:text-gold">Ig</a></li>
<li><a href="https://facebook.com" class="hover:text-gold">Fb</a></li>
</ul>
</div>
</div>
</footer>
<!-- block:end footer -->
<script>
document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
const menu = document.getElementById(button.getAttribute('aria-controls'));
if (!menu) return;
button.addEventListener('click', () => {
const open = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!open));
menu.classList.toggle('hidden', open);
});
});
document.querySelectorAll('[data-tabs]').forEach((group) => {
const tabs = [...group.querySelectorAll('[role="tab"]')];
const select = (tab) => {
tabs.forEach((other) => {
const active = other === tab;
other.setAttribute('aria-selected', String(active));
other.tabIndex = active ? 0 : -1;
document.getElementById(other.getAttribute('aria-controls')).classList.toggle('hidden', !active);
});
};
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => select(tab));
tab.addEventListener('keydown', (event) => {
if (!['ArrowRight', 'ArrowLeft'].includes(event.key)) return;
const next = tabs[(index + (event.key === 'ArrowRight' ? 1 : -1) + tabs.length) % tabs.length];
select(next);
next.focus();
});
});
});
document.querySelectorAll('[data-carousel]').forEach((carousel) => {
const track = carousel.querySelector('[data-carousel-track]');
if (!track) return;
const slides = [...track.children];
const dots = carousel.querySelector('[data-carousel-dots]');
let index = 0;
const perView = () => Math.max(1, Math.round(track.clientWidth / slides[0].clientWidth));
const maxIndex = () => Math.max(0, slides.length - perView());
const render = () => {
track.style.transform = `translateX(-${index * slides[0].clientWidth}px)`;
dots?.querySelectorAll('button').forEach((dot, i) => dot.setAttribute('aria-current', String(i === index)));
};
const go = (next) => { const max = maxIndex(); index = next > max ? 0 : next < 0 ? max : next; render(); };
const buildDots = () => {
if (!dots) return;
dots.innerHTML = '';
for (let i = 0; i <= maxIndex(); i++) {
const dot = document.createElement('button');
dot.type = 'button';
dot.className = 'h-2 w-2 rounded-full bg-current opacity-30 aria-[current=true]:opacity-100';
dot.setAttribute('aria-label', `Go to review ${i + 1}`);
dot.addEventListener('click', () => go(i));
dots.append(dot);
}
};
carousel.querySelector('[data-carousel-prev]')?.addEventListener('click', () => go(index - 1));
carousel.querySelector('[data-carousel-next]')?.addEventListener('click', () => go(index + 1));
addEventListener('resize', () => { buildDots(); go(Math.min(index, maxIndex())); });
buildDots();
render();
});
document.querySelectorAll('[data-accordion]').forEach((accordion) => {
const triggers = accordion.querySelectorAll('[data-accordion-trigger]');
triggers.forEach((trigger) => {
trigger.addEventListener('click', () => {
const willOpen = trigger.getAttribute('aria-expanded') !== 'true';
triggers.forEach((other) => {
const open = other === trigger && willOpen;
other.setAttribute('aria-expanded', String(open));
document.getElementById(other.getAttribute('aria-controls')).classList.toggle('hidden', !open);
other.querySelector('[data-accordion-icon]')?.classList.toggle('rotate-45', open);
});
});
});
});
document.querySelectorAll('[data-contact-form]').forEach((form) => {
form.addEventListener('submit', (event) => {
event.preventDefault();
const status = form.querySelector('[data-form-status]');
if (!form.checkValidity()) {
status.textContent = form.dataset.error || 'Please complete the required fields.';
return;
}
status.textContent = form.dataset.success || 'Thanks! We will be in touch soon.';
form.reset();
});
});
document.querySelectorAll('[data-current-year]').forEach((el) => { el.textContent = new Date().getFullYear(); });
(() => {
const items = document.querySelectorAll('[data-reveal]');
const skip = navigator.webdriver || !('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!items.length || skip) return;
document.documentElement.classList.add('reveal-ready');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
entry.target.classList.add('is-visible');
observer.unobserve(entry.target);
});
}, { rootMargin: '0px 0px -10% 0px' });
items.forEach((item) => observer.observe(item));
})();
</script>
</body>
</html>
Health & Fitness
Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.