Xlera8

یک افکت شناور فانتزی برای آواتار شما

آیا می دانید چنین اثری که در آن سر شخصی از دایره یا سوراخ عبور می کند؟ انیمیشن معروف خوک خوک که در آن هنگام بیرون آمدن از یک سری حلقه‌های قرمز برای خداحافظی دست تکان می‌دهد، نمونه‌ای عالی است. کیلیان والخوف در واقع چندی پیش آن را در CSS-Tricks دوباره ایجاد کرد.

من ایده مشابهی دارم اما به روشی متفاوت و با پراکندگی انیمیشن برخورد کردم. من فکر می کنم این بسیار کاربردی است و یک افکت شناور منظم را ایجاد می کند که می توانید در چیزی مانند آواتار خود استفاده کنید.

می بینیم که؟ می‌خواهیم یک انیمیشن مقیاس‌پذیر بسازیم که به نظر می‌رسد آواتار درست از دایره‌ای که در آن قرار دارد بیرون می‌آید. جالب است، درست است؟ به کد نگاه نکنید و بیایید گام به گام این انیمیشن را با هم بسازیم.

HTML: فقط یک عنصر

اگر کد نسخه ی نمایشی را بررسی نکرده اید و در تعجب هستید که تعداد آنها چقدر است divاین طول می کشد، سپس همانجا توقف کنید، زیرا نشانه گذاری ما چیزی جز یک عنصر تصویر واحد نیست:

<img src="" alt="">

بله، یک عنصر واحد! بخش چالش برانگیز این تمرین استفاده از کمترین مقدار کد ممکن است. اگر بوده اید دنبال من برای مدتی باید به این عادت کنید. من سخت تلاش می کنم تا راه حل های CSS را پیدا کنم که بتوان با کوچکترین و قابل نگهداری ترین کد ممکن به دست آورد.

نوشتم یک سری مقاله در اینجا در CSS-Tricks که در آن افکت‌های شناور مختلف را با استفاده از نشانه‌گذاری HTML یکسان حاوی یک عنصر بررسی می‌کنم. من به جزئیات در مورد گرادیان ها، ماسک کردن، برش دادن، خطوط کلی و حتی تکنیک های چیدمان می پردازم. من به شدت توصیه می کنم آنها را بررسی کنید زیرا از بسیاری از ترفندهای موجود در این پست دوباره استفاده خواهم کرد.

یک فایل تصویری مربعی با پس‌زمینه شفاف برای کاری که انجام می‌دهیم بهترین کار را خواهد داشت. اگر می‌خواهید با آن شروع کنید، این موردی است که من از آن استفاده می‌کنم.

طراحی شده توسط کانگ

من امیدوارم که نمونه‌های زیادی از این مورد را با استفاده از تصاویر واقعی ببینم - پس لطفاً نتیجه نهایی خود را پس از پایان کار در نظرات به اشتراک بگذارید تا بتوانیم مجموعه‌ای بسازیم!

قبل از پرش به CSS، ابتدا افکت را تشریح می کنیم. تصویر با شناور بزرگ‌تر می‌شود، بنابراین مطمئناً از آن استفاده خواهیم کرد transform: scale() در آنجا. یک دایره پشت آواتار وجود دارد و یک گرادیان شعاعی باید این کار را انجام دهد. در نهایت، ما به راهی برای ایجاد یک حاشیه در پایین دایره نیاز داریم که ظاهر آواتار را در پشت دایره ایجاد کند.

بیا دست به کار شویم!

اثر مقیاس

بیایید با اضافه کردن تبدیل شروع کنیم:

img { width: 280px; aspect-ratio: 1; cursor: pointer; transition: .5s;
}
img:hover { transform: scale(1.35);
}

هنوز هیچ چیز پیچیده ای نیست، درست است؟ بیایید ادامه دهیم.

دایره

گفتیم که پس زمینه یک گرادیان شعاعی خواهد بود. این عالی است زیرا می‌توانیم توقف‌های سختی بین رنگ‌های یک گرادیان شعاعی ایجاد کنیم، که به نظر می‌رسد در حال کشیدن دایره‌ای با خطوط یکدست هستیم.

img { --b: 5px; /* border width */ width: 280px; aspect-ratio: 1; background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), #C02942 calc(100% - var(--b)) 99%, #0000 ); cursor: pointer; transition: .5s;
}
img:hover { transform: scale(1.35);
}

به متغیر CSS توجه کنید، --b، من از آنجا استفاده می کنم. این نشان دهنده ضخامت "حاشیه" است که در واقع فقط برای تعیین توقف های رنگ سخت برای قسمت قرمز گرادیان شعاعی استفاده می شود.

مرحله بعدی بازی با اندازه گرادیان در حالت شناور است. با بزرگ شدن تصویر، دایره باید اندازه خود را حفظ کند. از آنجایی که ما الف را اعمال می کنیم scale() تحول، ما در واقع به آن نیاز داریم کاهش اندازه دایره چون در غیر این صورت با آواتار بزرگ می شود. بنابراین، در حالی که تصویر بزرگ می‌شود، برای کاهش مقیاس به گرادیان نیاز داریم.

بیایید با تعریف یک متغیر CSS شروع کنیم، --f، که "ضریب مقیاس" را تعریف می کند و از آن برای تنظیم اندازه دایره استفاده می کند. من استفاده میکنم 1 به عنوان مقدار پیش فرض، همانطور که در آن مقیاس اولیه برای تصویر و دایره ای است که از آن تبدیل می کنیم.

در اینجا یک نسخه نمایشی برای نشان دادن این ترفند وجود دارد. ماوس را نگه دارید تا ببینید در پشت صحنه چه اتفاقی می افتد:

من یک رنگ سوم به آن اضافه کردم radial-gradient برای شناسایی بهتر ناحیه گرادیان در شناور:

radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), #C02942 calc(100% - var(--b)) 99%, lightblue
);

اکنون باید پس زمینه خود را در مرکز دایره قرار دهیم و مطمئن شویم که تمام ارتفاع را می گیرد. من دوست دارم همه چیز را مستقیماً در آن اعلام کنم background ویژگی کوتاه‌نویسی، بنابراین می‌توانیم موقعیت پس‌زمینه خود را اضافه کنیم و با زدن روی آن مقادیر درست بعد از radial-gradient():

background: radial-gradient() 50% / calc(100% / var(--f)) 100% no-repeat;

پس زمینه در مرکز قرار می گیرد (50%) دارای عرض برابر است calc(100%/var(--f))، و دارای ارتفاعی برابر با 100%.

هیچ چیز مقیاس وقتی --f برابر است با 1 - دوباره مقیاس اولیه ما. در همین حال، گرادیان تمام عرض ظرف را می گیرد. وقتی افزایش می دهیم --f، اندازه عنصر رشد می کند - به لطف scale() تبدیل - و اندازه گرادیان کاهش می یابد.

وقتی همه اینها را در نسخه ی نمایشی خود اعمال می کنیم، این چیزی است که به دست می آوریم:

نزدیک تر می شویم! ما افکت سرریز را در بالا داریم، اما هنوز باید قسمت پایینی تصویر را پنهان کنیم، بنابراین به نظر می‌رسد که به جای نشستن در مقابل آن، از دایره بیرون می‌آید. این بخش دشوار کل این موضوع است و کاری است که ما در آینده انجام خواهیم داد.

حاشیه پایین

من ابتدا سعی کردم با این مشکل مقابله کنم border-bottom ویژگی، اما من نتوانستم راهی برای تطبیق اندازه حاشیه با اندازه دایره پیدا کنم. در اینجا بهترین چیزی است که می توانم به دست بیاورم و بلافاصله می توانید متوجه شوید که اشتباه است:

راه حل واقعی استفاده از outline ویژگی. آره، outline، نه border. به یک مقاله قبلی، من نشان می دهم که چگونه outline قدرتمند است و به ما اجازه می دهد تا افکت های شناور جالب ایجاد کنیم. ترکیب شده با outline-offset، ما دقیقاً همان چیزی را داریم که برای تأثیر خود نیاز داریم.

ایده این است که یک outline روی تصویر و تنظیم افست آن برای ایجاد حاشیه پایین. آفست به همان روشی که اندازه گرادیان انجام داد، به ضریب مقیاس بستگی دارد.

اکنون ما "مرز" پایینی خود را داریم (در واقع یک outline) با "حاشیه" ایجاد شده توسط گرادیان ترکیب می شود تا یک دایره کامل ایجاد کند. ما هنوز باید بخش هایی از آن را پنهان کنیم outline (از بالا و کناره ها)، که در یک لحظه به آن خواهیم رسید.

در اینجا کد ما تا کنون آمده است، شامل چند متغیر CSS دیگر که می توانید برای پیکربندی اندازه تصویر استفاده کنید (--s) و رنگ "حاشیه" (--c):

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ width: var(--s); aspect-ratio: 1; cursor: pointer; border-radius: 0 0 999px 999px; outline: var(--b) solid var(--c); outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000 ) 50% / calc(100% / var(--f)) 100% no-repeat; transform: scale(var(--f)); transition: .5s;
}
img:hover { --f: 1.35; /* hover scale */
}

از آنجایی که ما به یک حاشیه پایین دایره ای نیاز داریم، a اضافه کردیم border-radius در سمت پایین، اجازه می دهد تا outline برای مطابقت با انحنای گرادیان.

محاسبه استفاده شده در outline-offset بسیار ساده تر از آن چیزی است که به نظر می رسد. به صورت پیش فرض، outline کشیده شده است خارج از از جعبه عنصر و در مورد ما، ما به آن نیاز داریم همپوشانی عنصر. به طور دقیق تر، ما به آن نیاز داریم تا دایره ایجاد شده توسط گرادیان را دنبال کند.

نمودار انتقال پس زمینه.

وقتی عنصر را مقیاس می کنیم، فضای بین دایره و لبه را می بینیم. فراموش نکنیم که ایده این است که پس از اجرای تبدیل مقیاس، دایره را در همان اندازه نگه داریم، که فضایی را که برای تعریف افست طرح استفاده خواهیم کرد، همانطور که در شکل بالا نشان داده شده است، باقی می‌گذارد.

فراموش نکنیم که عنصر دوم مقیاس‌بندی شده است، بنابراین نتیجه ما نیز مقیاس‌پذیر است… یعنی باید نتیجه را بر تقسیم کنیم. f برای بدست آوردن ارزش افست واقعی:

Offset = ((f - 1) * S/2) / f = (1 - 1/f) * S/2

ما یک علامت منفی اضافه می کنیم زیرا نیاز داریم که طرح کلی از بیرون به داخل برود:

Offset = (1/f - 1) * S/2

در اینجا یک نسخه ی نمایشی سریع وجود دارد که نشان می دهد چگونه طرح کلی از گرادیان پیروی می کند:

ممکن است قبلاً آن را مشاهده کرده باشید، اما ما همچنان به طرح پایین برای همپوشانی دایره نیاز داریم تا اینکه اجازه دهیم از آن عبور کند. ما می توانیم این کار را با حذف اندازه حاشیه از افست انجام دهیم:

outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2) - var(--b));

اکنون باید نحوه حذف قسمت بالایی از طرح کلی را پیدا کنیم. به عبارت دیگر، ما فقط قسمت پایین تصویر را می خواهیم outline.

ابتدا، بیایید فضایی را در بالا با بالشتک اضافه کنیم تا از همپوشانی در بالا جلوگیری کنیم:

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ width: var(--s); aspect-ratio: 1; padding-block-start: calc(var(--s)/5); /* etc. */
}
img:hover { --f: 1.35; /* hover scale */
}

هیچ منطق خاصی برای آن پد بالا وجود ندارد. ایده این است که اطمینان حاصل شود که طرح کلی سر آواتار را لمس نمی کند. من از اندازه عنصر برای تعریف آن فضا استفاده کردم تا همیشه یک نسبت داشته باشد.

توجه داشته باشید که من آن را اضافه کرده ام content-box ارزش به background:

background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000 ) 50%/calc(100%/var(--f)) 100% no-repeat content-box;

ما به این نیاز داریم زیرا ما padding را اضافه کرده‌ایم و فقط می‌خواهیم پس‌زمینه در کادر محتوا تنظیم شود، بنابراین باید صریحاً به پس‌زمینه بگوییم که در آنجا متوقف شود.

اضافه کردن ماسک CSS به ترکیب

به قسمت آخر رسیدیم! تنها کاری که باید انجام دهیم این است که برخی از قطعات را پنهان کنیم و کارمان تمام است. برای این، ما بر روی mask ویژگی و البته شیب.

در اینجا شکلی وجود دارد که نشان می دهد چه چیزی را باید پنهان کنیم یا چه چیزی را باید نشان دهیم تا دقیق تر باشد

نمایش نحوه اعمال ماسک در قسمت پایین دایره.

تصویر سمت چپ چیزی است که در حال حاضر داریم و سمت راست چیزی است که می خواهیم. قسمت سبز رنگ ماسکی را نشان می دهد که باید روی تصویر اصلی اعمال کنیم تا نتیجه نهایی را بدست آوریم.

ما می توانیم دو قسمت از ماسک خود را تشخیص دهیم:

  • یک قسمت دایره ای در پایین که همان ابعاد و انحنای شیب شعاعی دارد که برای ایجاد دایره پشت آواتار استفاده کردیم.
  • یک مستطیل در بالا که ناحیه داخل طرح کلی را می پوشاند. توجه کنید که چگونه طرح در خارج از ناحیه سبز در بالا قرار دارد - این مهمترین قسمت است، زیرا اجازه می دهد طرح کلی به گونه ای بریده شود که فقط قسمت پایین قابل مشاهده باشد.

CSS نهایی ما در اینجا است:

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ --_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); width: var(--s); aspect-ratio: 1; padding-top: calc(var(--s)/5); cursor: pointer; border-radius: 0 0 999px 999px; outline: var(--b) solid var(--c); outline-offset: var(--_o); background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000) var(--_g); mask: linear-gradient(#000 0 0) no-repeat 50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%, radial-gradient( circle closest-side, #000 99%, #0000) var(--_g); transform: scale(var(--f)); transition: .5s;
}
img:hover { --f: 1.35; /* hover scale */
}

بیایید آن را تجزیه کنیم mask ویژگی. برای شروع، توجه کنید که مشابه radial-gradient() از background ملک در آنجا است من یک متغیر جدید ایجاد کردم، --_g، برای قسمت های مشترک تا چیزها کمتر به هم ریخته شود.

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; mask: radial-gradient( circle closest-side, #000 99%, #0000) var(--_g);

بعد، یک وجود دارد linear-gradient() در آنجا نیز:

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; mask: linear-gradient(#000 0 0) no-repeat 50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%, radial-gradient( circle closest-side, #000 99%, #0000) var(--_g);

این قسمت مستطیلی ماسک را ایجاد می کند. عرض آن برابر است با عرض گرادیان شعاعی منهای دو برابر ضخامت حاشیه:

calc(100% / var(--f) - 2 * var(--b))

ارتفاع مستطیل برابر با نصف است، 50%، از اندازه عنصر.

ما همچنین به شیب خطی نیاز داریم که در مرکز افقی قرار گیرد (50%) و از بالا با همان مقدار افست طرح، افست کنید. متغیر CSS دیگری ایجاد کردم، --_o، برای افست که قبلاً تعریف کردیم:

--_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

یکی از چیزهای گیج کننده در اینجا این است که ما به a نیاز داریم منفی افست برای طرح کلی (برای انتقال آن از بیرون به داخل) اما a مثبت افست برای گرادیان (برای حرکت از بالا به پایین). بنابراین، اگر تعجب می کنید که چرا افست را ضرب می کنیم، --_o، توسط -1، خوب، حالا می دانید!

در اینجا یک نسخه نمایشی برای نشان دادن پیکربندی گرادیان ماسک وجود دارد:

ماوس بالا را نگه دارید و ببینید که چگونه همه چیز با هم حرکت می کند. کادر میانی لایه ماسک متشکل از دو گرادیان را نشان می دهد. آن را به عنوان قسمت قابل مشاهده تصویر سمت چپ تصور کنید، و نتیجه نهایی را در سمت راست می گیرید!

پسگفتار

اوف، ما تمام شدیم! و نه تنها با یک انیمیشن شناور شیک به پایان رسیدیم، بلکه همه این کارها را با یک HTML انجام دادیم. <img> عنصر فقط همین و کمتر از 20 خط ترفند CSS!

مطمئنا، ما برای رسیدن به چنین اثر پیچیده ای به چند ترفند کوچک و فرمول های ریاضی اعتماد کردیم. اما از آنجایی که قطعات مورد نیاز خود را از قبل شناسایی کردیم، دقیقاً می دانستیم چه باید بکنیم.

آیا اگر به خودمان اجازه HTML بیشتری می دادیم، می توانستیم CSS را ساده کنیم؟ کاملا. اما ما اینجا هستیم تا ترفندهای جدید CSS را یاد بگیریم! این تمرین خوبی برای کشف گرادیان های CSS، ماسک کردن، و ... بود outline رفتار دارایی، دگرگونی‌ها و کلی چیزهای دیگر. اگر در هر لحظه احساس کردید گم شده اید، پس حتما بررسی کنید سریال من که از همان مفاهیم کلی استفاده می کند. گاهی اوقات دیدن نمونه های بیشتر و استفاده از موارد برای هدایت یک نقطه به خانه کمک می کند.

من آخرین نسخه نمایشی را برای شما باقی می گذارم که از عکس های توسعه دهندگان محبوب CSS استفاده می کند. فراموش نکنید که یک نسخه نمایشی با تصویر خود را به من نشان دهید تا بتوانم آن را به مجموعه اضافه کنم!

چت با ما

سلام! چگونه می توانم به شما کمک کنم؟