→ לכל המאגר

B47 · סליידר השוואה לפני ואחרי

התנהגויות GSAP · Draggable · clip-path תמונות וגלריותטעינה ופידבק ממתין

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

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

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

הדמו

לפני אחרי
‹›

גרור את הידית, או השתמש בחצי המקלדת.

הידית עצמה היא אלמנט ברוחב אפס שממוקם ב-x פיזי, והכפתור ממורכז עליה בטרנספורם. זה מה שמאפשר להשתמש בערך אחד גם לחיתוך וגם למיקום, בלי לחשב חצי רוחב בכל פריים. `clip-path:inset(0 0 0 X)` משאיר את מה שמימין ל-X, ולכן בעברית "לפני" יושב בימין והגרירה שמאלה חושפת את "אחרי", בכיוון שבו קוראים. בשינוי גודל חלון חייבים לבנות את ה-Draggable מחדש עם אותו אחוז, אחרת הידית קופצת החוצה מהגבולות.

קוד להדבקה

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

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

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.stage{padding:var(--sec, clamp(120px, 12vw, 260px)) var(--gutter, clamp(24px, 5vw, 96px));position:relative}
.stage.tight{padding-block:clamp(48px,5vw,90px)}
.stage.full{padding-inline:0}
.ph{display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;border-radius:var(--r, 14px)}
.ph-b{background:linear-gradient(160deg,#5f3dc4,#9775fa)}
.ph-d{background:linear-gradient(160deg,#2b8a3e,#69db7c)}

/* B47 · סליידר השוואה לפני ואחרי */
.ba{position:relative;max-width:min(900px,94vw);margin-inline:auto;aspect-ratio:16/10;border-radius:var(--r, 14px);
  overflow:hidden;border:1px solid var(--line, #e4e4ee);user-select:none;touch-action:pan-y}
.ba-layer{position:absolute;inset:0;border-radius:0;font-size:0}
/* שכבת "לפני" יושבת מעל ונחתכת. inset(0 0 0 X) משאיר את מה שמימין ל-X */
.ba-before{clip-path:inset(0 0 0 50%)}
.ba-tag{position:absolute;top:14px;background:rgba(0,0,0,.62);color:#fff;font-size:13px;
  padding:6px 14px;border-radius:999px;backdrop-filter:blur(6px);z-index:3;pointer-events:none}
.ba-tag.is-before{right:14px}
.ba-tag.is-after{left:14px}
/* הידית: רוחב אפס שממוקם בפיקסלים פיזיים, והכפתור ממורכז עליה */
.ba-handle{position:absolute;top:0;left:0;width:0;height:100%;z-index:4;cursor:ew-resize}
.ba-line{position:absolute;top:0;left:-1px;width:2px;height:100%;background:#fff /* qa-allow: white, ידית/סמן ולא משטח טקסט */;box-shadow:0 0 0 1px rgba(0,0,0,.18)}
.ba-knob{color:#16182b /* qa-allow: literal, ידית לבנה קשיחה */;position:absolute;top:50%;left:0;transform:translate(-50%,-50%);width:48px;height:48px;border-radius:50%;
  background:#fff /* qa-allow: white, ידית/סמן ולא משטח טקסט */;box-shadow:0 6px 20px rgba(0,0,0,.28);display:grid;place-items:center;gap:0;
  font-size:17px;letter-spacing:-2px}
.ba-handle:focus-visible .ba-knob{outline:3px solid var(--accent, #4a3aff);outline-offset:3px}
.ba-hint{text-align:center;color:var(--muted, #6a6d85);font-size:14px;padding-top:14px}

HTML

<div class="stage tight">
  <div class="ba">
    <div class="ph ba-layer ba-after ph-d"></div>
    <div class="ph ba-layer ba-before ph-b"></div>
    <span class="ba-tag is-before">לפני</span>
    <span class="ba-tag is-after">אחרי</span>
    <div class="ba-handle" tabindex="0" role="slider" aria-label="השוואה בין לפני לאחרי"
         aria-valuemin="0" aria-valuemax="100" aria-valuenow="50"><span class="ba-line"></span><span class="ba-knob">‹›</span></div>
  </div>
  <p class="ba-hint">גרור את הידית, או השתמש בחצי המקלדת.</p>
</div>

JS

gsap.registerPlugin(Draggable);

(function(){
  const wrap=document.querySelector(".ba"),before=wrap.querySelector(".ba-before"),handle=wrap.querySelector(".ba-handle");
  let drag;
  function paint(){
    const x=gsap.getProperty(handle,"x");
    before.style.clipPath="inset(0 0 0 "+x+"px)";
    handle.setAttribute("aria-valuenow",Math.round(x/wrap.offsetWidth*100));
  }
  function build(){
    const w=wrap.offsetWidth;
    const pct=(+handle.getAttribute("aria-valuenow")||50)/100;
    if(drag)drag.kill();
    gsap.set(handle,{x:w*pct});
    drag=Draggable.create(handle,{type:"x",bounds:{minX:0,maxX:w},onDrag:paint,onThrowUpdate:paint})[0];
    paint();
  }
  // החצים פיזיים בכוונה: ידית נגררת נתפסת כאובייקט על המסך, לא כטקסט
  handle.addEventListener("keydown",e=>{
    const step=e.shiftKey?wrap.offsetWidth*.1:wrap.offsetWidth*.02;
    if(e.key==="ArrowLeft"||e.key==="ArrowRight"){
      e.preventDefault();
      const x=gsap.utils.clamp(0,wrap.offsetWidth,gsap.getProperty(handle,"x")+(e.key==="ArrowRight"?step:-step));
      gsap.to(handle,{x:x,duration:.18,onUpdate:paint,onComplete:paint});
    }
  });
  build();
  let t;addEventListener("resize",()=>{clearTimeout(t);t=setTimeout(build,80);});
})();