שתי תמונות באותה מסגרת וידית שנגררת ביניהן. גרירה ימינה או שמאלה חושפת יותר מכל צד, וגם החצים במקלדת מזיזים אותה.
מתי משתמשים: שיפוץ, שיניים, אסתטיקה, כושר, ניקיון, עיצוב מחדש, לפני ואחרי של אתר. ההוכחה החזקה ביותר שיש: הלקוח רואה את ההבדל במקום לקרוא עליו.
הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.
גרור את הידית, או השתמש בחצי המקלדת.
הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".
/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.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}
<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>
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);});
})();