→ לכל המאגר

B19 · כרטיס וידאו שמתנגן בהובר

התנהגויות HTML video · JS תמונות וגלריותכרטיסיםhover ומיקרו ממתין

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

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

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

הדמו

וידאו
פרויקט ראשון
וידאו
פרויקט שני
וידאו
פרויקט שלישי

בדסקטופ: הובר מנגן. במובייל: נגיעה מנגנת ועוצרת.

preload="none" הוא הלב: הדפדפן לא נוגע בקובץ הווידאו עד ההובר הראשון, והפוסטר לבדו מצויר. הווידאו חייב muted כדי שדפדפנים ירשו ניגון בלי לחיצה, ו-playsinline כדי שאייפון לא יפתח נגן מסך מלא.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --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}
.center{text-align:center}

/* B19 · כרטיס וידאו שמתנגן בהובר */
.vgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap, clamp(16px, 1.6vw, 36px));padding-inline:var(--gutter, clamp(24px, 5vw, 96px))}
.vcardx{position:relative;border-radius:var(--r, 14px);overflow:hidden;background:#0f1020;aspect-ratio:16/10;cursor:pointer}
.vcardx img,.vcardx video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.vcardx video{opacity:0;transition:opacity .3s ease}
.vcardx.playing video{opacity:1}
.vcardx figcaption{position:absolute;inset-inline:0;bottom:0;padding:14px 16px;color:#fff;font-size:14px;font-weight:500;background:linear-gradient(transparent,rgba(0,0,0,.6));z-index:2}
.vcardx .badge{position:absolute;top:12px;inset-inline-end:12px;z-index:2;background:rgba(255,255,255,.92);color:#111;border-radius:999px;padding:5px 12px;font-size:11px;letter-spacing:.08em}
@media(max-width:767px){.vgrid{grid-template-columns:1fr}}

HTML

<div class="stage tight"><div class="vgrid">
  <figure class="vcardx"><img src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.jpg" alt=""><video preload="none" muted loop playsinline poster="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.jpg" data-src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.mp4"></video><span class="badge">וידאו</span><figcaption>פרויקט ראשון</figcaption></figure>
  <figure class="vcardx"><img src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-b.jpg" alt=""><video preload="none" muted loop playsinline poster="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-b.jpg" data-src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-b.mp4"></video><span class="badge">וידאו</span><figcaption>פרויקט שני</figcaption></figure>
  <figure class="vcardx"><img src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.jpg" alt=""><video preload="none" muted loop playsinline poster="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.jpg" data-src="https://liavwebdesign-spec.github.io/motion-vault/assets/media/demo-a.mp4"></video><span class="badge">וידאו</span><figcaption>פרויקט שלישי</figcaption></figure>
</div>
<p class="center" style="color:var(--muted);font-size:14px">בדסקטופ: הובר מנגן. במובייל: נגיעה מנגנת ועוצרת.</p></div>

JS

(function(){
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  const hoverable=matchMedia("(hover:hover)").matches;
  document.querySelectorAll(".vcardx").forEach(card=>{
    const v=card.querySelector("video");
    let loaded=false;
    const play=()=>{
      if(reduce)return;
      if(!loaded){v.src=v.dataset.src;loaded=true;}
      card.classList.add("playing");
      const p=v.play();if(p&&p.catch)p.catch(()=>{});
    };
    const stop=()=>{card.classList.remove("playing");v.pause();try{v.currentTime=0;}catch(e){}};
    if(hoverable){
      card.addEventListener("mouseenter",play);
      card.addEventListener("mouseleave",stop);
      card.addEventListener("focusin",play);
      card.addEventListener("focusout",stop);
    }else{
      card.addEventListener("click",()=>card.classList.contains("playing")?stop():play());
    }
  });
})();