ساخت افکت جریان آب با CSS
افکت جریان آب (water flow) یکی از جلوههای بصری جذاب برای وبسایتهاست که میتواند به هدرها، کارتها یا پسزمینهها حس پویایی اضافه کند. در این مقاله به روشهای مختلف پیادهسازی افکت آب با CSS میپردازیم: از روش ساده با گرادیان و pseudo-element تا تکنیکهای پیشرفتهتر با SVG، ماسکها و بهینهسازی برای عملکرد و دسترسی.
چرا از CSS استفاده کنیم؟
- قابلیت اجرا در مرورگر بدون وابستگی به اسکریپت
- قابلیت ترکیب با SVG و فیلترها برای جلوههای طبیعیتر
- کنترل دقیقتر انیمیشن، مصرف کمتر منابع نسبت به جاوااسکریپت در اغلب موارد
روش پایه: موج با pseudo-elements و گرادیان
در این روش با دو لایه موج که هرکدام انیمیشن متفاوتی دارند، جریان طبیعیتری ساخته میشود. مثال ساده زیر را ببینید:
<div class="ocean">
<div class="wave wave1"></div>
<div class="wave wave2"></div>
</div>
.ocean {
position: relative;
width: 320px;
height: 200px;
overflow: hidden;
background: linear-gradient(#083048, #04263a);
border-radius: 8px;
}
.wave {
position: absolute;
bottom: 0;
left: 50%;
width: 200%;
height: 60%;
background:
radial-gradient(circle at 25% 50%, rgba(255,255,255,0.12) 0 10%, transparent 11%),
linear-gradient(180deg, rgba(0,150,255,0.6), rgba(0,110,190,0.6));
transform: translateX(-50%);
will-change: transform;
}
.wave1 {
opacity: 0.65;
animation: flow1 8s linear infinite;
}
.wave2 {
opacity: 0.45;
filter: blur(3px);
animation: flow2 10s linear infinite reverse;
}
@keyframes flow1 {
0% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-40%) translateY(-8px) skewX(-6deg); }
100% { transform: translateX(-30%) translateY(0); }
}
@keyframes flow2 {
0% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-60%) translateY(-6px) skewX(6deg); }
100% { transform: translateX(-50%) translateY(0); }
}
/* احترام به تنظیمات کاهش حرکت */@media (prefers-reduced-motion: reduce) {
.wave { animation: none; }
}
این کد دو لایه موج ایجاد میکند که با انیمیشنهای مختلف جابهجا و کمی کج میشوند تا حس جریان آب ایجاد شود. استفاده از will-change و filter: blur برای عمق دادن مفید است. در صورت فعال بودن prefers-reduced-motion انیمیشنها غیرفعال میشوند تا تجربه کاربری بهتری فراهم شود.
توضیح فنی و بهینهسازی
در این مثال موجها با تغییر transform (ترجمه و skew) انیمیشن میشوند که اجرای GPU-accelerated دارند. بهتر است از translateZ(0) یا will-change: transform استفاده کنید تا به GPU منتقل شوند. همچنین مراقب اندازه و تعداد لایهها باشید چون استفاده زیاد از filter یا blur میتواند بار محاسباتی افزایش دهد.
بهبود: استفاده از متغیرهای CSS و کنترل سرعت
:root {
--wave-speed-1: 8s;
--wave-speed-2: 12s;
--wave-color-1: rgba(0,150,255,0.6);
--wave-color-2: rgba(0,110,190,0.5);
}
.wave1 { animation: flow1 var(--wave-speed-1) linear infinite; }
.wave2 { animation: flow2 var(--wave-speed-2) linear infinite; }
.wave {
background:
radial-gradient(circle at 25% 50%, rgba(255,255,255,0.12) 0 10%, transparent 11%),
linear-gradient(180deg, var(--wave-color-1), var(--wave-color-2));
}
در این نسخه از CSS Variables برای کنترل آسان سرعت و رنگ استفاده شده است؛ مزیت این روش قابلیت تغییر پویا از طریق جاوااسکریپت یا کلاسهاست بدون نیاز به ویرایش رشتههای طولانی CSS.
روش پیشرفته: ترکیب SVG و mask برای موجهای دقیقتر
برای موجهایی با شکل دقیقتر و کیفیت مقیاسپذیر میتوانیم از SVG به عنوان ماسک یا تصویر پسزمینه استفاده کنیم. مزیت SVG حفظ صافی لبهها در هر رزولوشن است. مثال سادهای از استفاده SVG به عنوان ماسک:
<div class="water-mask">
<div class="water-fill"></div>
</div>
.water-mask {
width: 100%;
max-width: 600px;
height: 220px;
background: linear-gradient(#052734, #013046);
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200"><path d="M0 80 C150 0 350 160 800 60 L800 200 L0 200 Z" fill="black"/></svg>');
mask-size: cover;
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200"><path d="M0 80 C150 0 350 160 800 60 L800 200 L0 200 Z" fill="black"/></svg>');
-webkit-mask-size: cover;
position: relative;
overflow: hidden;
}
.water-fill {
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(0,170,255,0.7), rgba(0,110,190,0.7));
transform: translateX(0);
animation: slide 6s linear infinite;
}
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(-30%); }
}
در این مثال از data URI برای SVG ماسک استفاده شده تا نیاز به فایل اضافی از بین برود. mask-image باعث میشود که شکل موج دقیق SVG، نواحی قابل مشاهده را تعیین کند و با انیمیشن پسزمینه میتوان جریان را ایجاد کرد.
جدول مقایسه روشها
| روش | مزایا | معایب |
|---|---|---|
| گرادیان و pseudo-element | ساده، بدون نیاز به فایل خارجی، خوب برای انیمیشنهای سبک | کنترل شکل موج محدود، ممکن است کمتر طبیعی بهنظر برسد |
| SVG + mask | شکل دقیق و مقیاسپذیر، ظاهری طبیعیتر | کمی پیچیدهتر و ممکن است در بعضی مرورگرها نیاز به prefix |
| Canvas/JS | بالاترین میزان کنترل و فیزیک شبیهسازی | پیچیدگی و مصرف منابع بیشتر |
نکات نهایی و بهترین شیوهها
- از transform برای انیمیشن استفاده کنید تا از رندر موثر GPU بهرهمند شوید (translate، scale، rotate).
- برای بهبود دسترسی، همیشه @media (prefers-reduced-motion: reduce) را در نظر بگیرید.
- میزان blur و تعداد لایهها را مطابق نیاز کاهش دهید؛ فیلترها هزینه محاسباتی بیشتری دارند.
- برای سازگاری موبایل، رزولوشن و اندازه عناصر را تست کنید و از background-size مناسب استفاده کنید.
نتیجهگیری
با ترکیب گرادیانها، pseudo-elementها، SVG و CSS variables میتوان افکت جریان آب زیبا و بهینهای ساخت که هم چشمنواز باشد و هم قابل تغییر و سازگار با دسترسی. بسته به نیاز پروژه (سبک بودن vs دقت بصری) میتوانید یکی از روشها را انتخاب و با بهینهسازیهای مطرحشده عملکرد را حفظ کنید.
آیا این مطلب برای شما مفید بود ؟




