Загрузка...

Секция сравнения характеристик сывороток для волос с анимированной статистикой. Использует Tailwind CSS и IntersectionObserver для отображения данных при прокрутке.
<section class="md:px-12 bg-white border-neutral-100 border-b pt-32 pr-6 pb-32 pl-6">
<div class="max-w-7xl mx-auto grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-24">
<!-- Left Title -->
<div class="lg:col-span-4">
<h2 class="text-4xl md:text-5xl font-medium tracking-tight text-neutral-900 leading-[1.1]">
What makesit special
</h2>
<!-- Orange Tag (Mobile Only) -->
<div class="mt-8 lg:hidden text-xs font-semibold text-orange-600 uppercase tracking-widest">
[ IN-VITRO STUDIES ]
</div>
</div>
<!-- Right Content -->
<div class="lg:col-span-8 flex flex-col justify-between h-full">
<div class="">
<!-- Big Number -->
<div class="text-[12vw] lg:text-[10rem] font-medium leading-none text-neutral-100 select-none -ml-2 mb-6 flex">
<span id="animated-stat-number" class="">0.0</span>%
</div>
<h3 class="text-xl font-medium tracking-tight text-neutral-900 mb-4">
Revolutionary Patent Pending Blend
</h3>
<p class="text-neutral-500 max-w-lg leading-relaxed text-sm mb-16">
Our serum delivers a remarkable 22.9% increase in the tensile strength of hair fibers after just one wash,
surpassing competitors' results.
</p>
</div>
<!-- Chart Area -->
<div class="w-full relative">
<!-- Label -->
<div
class="absolute bottom-4 left-0 text-xs font-semibold text-orange-600 uppercase tracking-widest hidden lg:block">
[ IN-VITRO STUDIES ]
</div>
<!-- Bars -->
<div class="w-full max-w-xl ml-auto">
<!-- Bar 1 -->
<div class="mb-8">
<div class="text-xs text-neutral-500 mb-2 font-medium">Usual Serum</div>
<div class="w-full bg-neutral-100 h-8 relative rounded-sm">
<!-- Dashed line marker effect -->
<div class="absolute right-0 top-[-4px] bottom-[-4px] border-r border-dashed border-neutral-300"></div>
</div>
</div>
<!-- Bar 2 -->
<div class="">
<div class="flex justify-between items-end mb-2">
<span class="text-xs text-neutral-900 font-medium">Minimalist Serum</span>
<span class="text-sm text-orange-600 font-semibold">+22.9%</span>
</div>
<!-- Animated Bar -->
<div id="animated-stat-bar" class="bg-orange-600 h-8 rounded-sm relative shadow-lg shadow-orange-600/20"
style="width: 100%; transition: width 1.5s cubic-bezier(0.25, 1, 0.5, 1);">
<!-- Dashed line marker effect matching the one above -->
<div class="absolute right-0 top-[-4px] bottom-[-4px] border-r border-dashed border-neutral-900/20"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Animation Script -->
<script>
(function () {
// Grab the section that contains THIS script
const script = document.currentScript;
const section = script.closest('section');
if (!section) return;
const numberEl = section.querySelector('#animated-stat-number');
const barEl = section.querySelector('#animated-stat-bar');
if (!numberEl || !barEl) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
// Animate bar width
setTimeout(() => {
barEl.style.width = '100%';
}, 100);
// Animate number from 0.0 to 22.9
const targetValue = 22.9;
const duration = 1500;
const startTime = performance.now();
function updateNumber(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const ease = 1 - Math.pow(1 - progress, 4);
const current = progress === 1 ? targetValue : targetValue * ease;
numberEl.textContent = current.toFixed(1);
if (progress < 1) {
requestAnimationFrame(updateNumber);
}
}
requestAnimationFrame(updateNumber);
// Only run once
observer.unobserve(entry.target);
});
},
{ threshold: 0.3 }
);
observer.observe(section);
})();
</script>
</section>