→ לכל המאגר

G101 · עדשת רנטגן שנוסעת בגלילה

GSAP GSAP · ScrollTrigger · clip-path תמונות וגלריותתהליך ושלבים ממתין

שתי גרסאות של אותה תמונה זו על זו (חוץ ופנים, לפני ואחרי, שרטוט ומוצר), ועדשה עגולה שנוסעת על פניהן עם הגלילה וחושפת את השכבה התחתונה רק בתוכה.

מתי משתמשים: אדריכלות ושיפוצים, רפואה, מכונאות, כל "מה מתחת לפני השטח". תמונה אחת, מסלול של שלוש עד ארבע נקודות.

הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.

הדמו

גלול למטה, הדמו מגיע ↓
מה שמתחת
מה שרואים
גלול כדי להזיז את העדשה
עוד מסלול גלילה. נסה גם חזרה למעלה ↑
השכבה העליונה מקבלת clip-path circle עם מרכז שנע לאורך נקודות בסקראב (motion של המרכז דרך משתני CSS). במובייל העדשה גדולה יותר יחסית (34% מהרוחב) כי המסך צר.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".

פתח קובץ עצמאי ↗
הצג את הקוד כאן

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.ph{display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;border-radius:var(--r, 14px)}
.ph-c{background:linear-gradient(160deg,#0b7285,#3bc9db)}
.ph-l{background:rgba(16,18,43,.72);color:#fff;padding:.18em .7em;border-radius:999px;line-height:1.3;font-size:max(.78em,12px)}

/* G101 · עדשת רנטגן שנוסעת בגלילה */
.xr{position:relative;height:280vh}
.xr-pin{position:sticky;top:0;height:100vh;display:grid;place-items:center;overflow:hidden}
.xr-fig{position:relative;width:min(900px,92vw);aspect-ratio:16/9;border-radius:var(--r, 14px);overflow:hidden;--lx:80%;--ly:30%;--lr:16%}
.xr-fig .ph{position:absolute;inset:0;border-radius:0;font-size:22px}
.xr-under{background:repeating-linear-gradient(45deg,#1b2a4a 0 14px,#243766 14px 28px)}
.xr-over{clip-path:circle(var(--lr) at var(--lx) var(--ly))}
.xr-ring{position:absolute;left:var(--lx);top:var(--ly);width:calc(var(--lr) * 2 * 16 / 9 * 1);aspect-ratio:1;translate:-50% -50%;border-radius:50%;border:3px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.2),0 20px 50px rgba(0,0,0,.3);pointer-events:none}
.xr-lbl{position:absolute;bottom:18px;inset-inline-start:18px;background:color-mix(in srgb,var(--bg, #f7f7fa) 92%,transparent);color:var(--ink, #16182b);padding:10px 14px;border-radius:10px;font-size:14px;font-weight:600}
@media(max-width:767px){.xr-fig{--lr:24%}}

HTML

<div class="xr">
  <div class="xr-pin"><div class="xr-fig">
    <div class="ph xr-under"><span class="ph-l">מה שמתחת</span></div>
    <div class="ph ph-c xr-over"><span class="ph-l">מה שרואים</span></div>
    <div class="xr-ring"></div>
    <div class="xr-lbl">גלול כדי להזיז את העדשה</div>
  </div></div>
</div>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const fig=document.querySelector(".xr-fig");
  if(matchMedia("(prefers-reduced-motion: reduce)").matches){fig.style.setProperty("--lr","40%");return;}
  // העדשה חושפת את השכבה התחתונה: clip-path על העליונה הוא הפוך, לכן משתמשים ב-mask דרך שתי שכבות:
  // העליונה נחתכת ל"הכל חוץ מהעיגול" באמצעות עיגול ענק פחות עיגול קטן (evenodd ב-polygon לא זמין ל-circle),
  // ולכן במקום זה השכבה התחתונה נחתכת לעיגול ויושבת מעל. הסדר ב-DOM הפוך מהשם, וזה בכוונה.
  const under=fig.querySelector(".xr-under"),over=fig.querySelector(".xr-over");
  over.style.clipPath="none";under.style.zIndex=2;under.style.clipPath="circle(var(--lr) at var(--lx) var(--ly))";
  const stops=[{x:80,y:30},{x:50,y:60},{x:22,y:35},{x:60,y:78}];
  const o={x:80,y:30};
  const tl=gsap.timeline({scrollTrigger:{trigger:".xr",start:"top top",end:"bottom bottom",scrub:.7},onUpdate(){fig.style.setProperty("--lx",o.x+"%");fig.style.setProperty("--ly",o.y+"%");}});
  stops.slice(1).forEach(p=>tl.to(o,{x:p.x,y:p.y,duration:1,ease:"power2.inOut"}));
  tl.to(".xr-lbl",{opacity:0,duration:.2},0);
})();