→ לכל המאגר

B57 · גריד Masonry עם כניסה מונפשת

התנהגויות vanilla JS · CSS תמונות וגלריותכרטיסים ממתין

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

מתי משתמשים: גלריות ובלוגים עם תמונות בגבהים שונים, תיק עבודות, פיד. כשהגבהים אחידים גריד רגיל עדיף.

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

הדמו

גלול למטה, הדמו מגיע ↓
1
2
3
4
5
6
7
8
9
עוד מסלול גלילה. נסה גם חזרה למעלה ↑
מקור: ReactBits Masonry (GSAP). נכתב מחדש בלי ספרייה: JS מחשב מיקום לכל פריט ומזיז ב-transform בלבד, כך שה-reflow לא נוגע ב-layout. ResizeObserver מסדר מחדש.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --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-a{background:linear-gradient(160deg,#3b5bdb,#748ffc)}
.ph-b{background:linear-gradient(160deg,#5f3dc4,#9775fa)}
.ph-c{background:linear-gradient(160deg,#0b7285,#3bc9db)}
.ph-d{background:linear-gradient(160deg,#2b8a3e,#69db7c)}
.ph-e{background:linear-gradient(160deg,#e8590c,#ffa94d)}
.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)}

/* B57 · גריד Masonry עם כניסה מונפשת */
.ms{position:relative;max-width:1100px;margin-inline:auto}
.ms-item{position:absolute;top:0;right:0;width:var(--w);opacity:0;translate:0 40px;transition:transform .6s cubic-bezier(.2,.6,.2,1),opacity .6s,translate .6s cubic-bezier(.2,.6,.2,1);transition-delay:var(--d,0s)}
.ms.ready .ms-item{opacity:1;translate:0 0}
.ms-item .ph{width:100%;height:var(--h);border-radius:var(--r, 14px);font-size:22px}
.ms-item.ph-l{background:none}
@media (hover:hover) and (pointer:fine){.ms-item .ph{transition:transform .5s cubic-bezier(.2,.6,.2,1)}.ms-item:hover .ph{transform:scale(1.03)}}
@media (prefers-reduced-motion: reduce){.ms-item{transition:none}}

HTML

<div class="stage tight"><div class="ms">
  <div class="ms-item" style="--h:220px"><div class="ph ph-a"><span class="ph-l">1</span></div></div><div class="ms-item" style="--h:320px"><div class="ph ph-b"><span class="ph-l">2</span></div></div>
  <div class="ms-item" style="--h:180px"><div class="ph ph-c"><span class="ph-l">3</span></div></div><div class="ms-item" style="--h:260px"><div class="ph ph-d"><span class="ph-l">4</span></div></div>
  <div class="ms-item" style="--h:340px"><div class="ph ph-e"><span class="ph-l">5</span></div></div><div class="ms-item" style="--h:200px"><div class="ph ph-a"><span class="ph-l">6</span></div></div>
  <div class="ms-item" style="--h:280px"><div class="ph ph-b"><span class="ph-l">7</span></div></div><div class="ms-item" style="--h:240px"><div class="ph ph-c"><span class="ph-l">8</span></div></div>
  <div class="ms-item" style="--h:300px"><div class="ph ph-d"><span class="ph-l">9</span></div></div>
</div></div>

JS

(function(){
  const grid=document.querySelector(".ms"),items=[...grid.querySelectorAll(".ms-item")],GAP=16;
  function layout(){
    const W=grid.clientWidth,cols=W<560?1:W<900?2:3,w=(W-GAP*(cols-1))/cols,tops=new Array(cols).fill(0);
    items.forEach((it,i)=>{
      const c=tops.indexOf(Math.min(...tops)),h=parseFloat(getComputedStyle(it).getPropertyValue("--h"));
      it.style.setProperty("--w",w+"px");
      // RTL: העמודה 0 מימין, לכן מזיזים שמאלה (ערך שלילי)
      it.style.transform="translate("+(-(c*(w+GAP)))+"px,"+tops[c]+"px)";
      it.style.setProperty("--d",(i*70)+"ms");
      tops[c]+=h+GAP;
    });
    grid.style.height=Math.max(...tops)-GAP+"px";
  }
  layout();requestAnimationFrame(()=>grid.classList.add("ready"));
  new ResizeObserver(()=>layout()).observe(grid);
})();