- Lighthouse Report לאתר האישי שלכם — Mobile Mode, עם ניתוח — הרצה על 3 עמודים עיקריים, צילומי מסך של ה-scores, וטבלה עם LCP, CLS, INP, FCP ו-TTFB before/after האופטימיזציות של הפרק
- Core Web Vitals Cheat Sheet — דף אחד עם 3 המדדים, היעדים (
LCP < 2.5s,CLS < 0.1,INP < 200ms), הסיבות הנפוצות לכישלון בכל אחד, והתיקון הראשון שצריך לנסות - רשימת 10 אופטימיזציות שאפשר לבקש מ-AI — מוכנות להעתקה כפרומפט:
loading="lazy"על תמונות מתחת ל-fold,content-visibility: autoעל sections רחוקים,font-display: swap,contain: paint, הסרתwill-changeמיותר, skeleton screens במקום spinners, העברת CSS קריטי ל-<style>inline, preload של hero image, הסרת backdrop-filter מרקעים גדולים, והמרת אנימציות ל-transform/opacityבלבד - Critical CSS Pattern — הקטע של CSS שטוען מיד ב-
<head>(< 14KB), לעומת ה-CSS שנטען async, עם דוגמה מעשית של hero + navigation - Font Loading Strategy לעברית —
preconnectל-fonts.gstatic,preloadשל הפונט הקריטי,font-display: swap, ושימוש ב-size-adjust/ascent-overrideב-@font-facefallback כדי למנוע CLS בזמן החלפת הפונט - Skeleton Screen Component — HTML + CSS מלאים לכרטיס-שלד עם shimmer animation (pure CSS, ללא JS), עם הסבר למה זה מרגיש מהיר פי 2 למרות שה-wall time זהה
- Performance Audit Prompt + Performance Fix Prompt — שני פרומפטים באנגלית שגורמים ל-AI לעבור על הקוד ולסמן CSS שהורג performance, ואז לתקן עם אופטימיזציות ספציפיות — לא "make it faster" כללי
- מילון 16 מונחי Performance — Core Web Vitals, LCP, CLS, INP, FCP, TTFB, Lighthouse, Field Data, Lab Data, lazy loading, content-visibility, contain, will-change, critical CSS, render-blocking, font-display ועוד
- תוכלו להסביר מה זה LCP, CLS ו-INP בשפה פשוטה — מה הם מודדים, למה דווקא הם, מה היעד של כל אחד, ואיך כל אחד מהם מושפע מהחלטות CSS שעשיתם בפרקים הקודמים (תמונות, פונטים, אנימציות, layouts)
- תוכלו להריץ Lighthouse ולפרש את התוצאות — להבדיל בין "performance score" (מספר יחיד) לבין 5 המדדים שהוא מורכב מהם, לדעת מה "ירוק" (90+), מה "כתום" (50-89), מה "אדום" (פחות מ-50), ולהבין למה הרצה אחת היא מטעה — תמיד 3-5 פעמים ולקחת median
- תוכלו לבקש מ-AI אופטימיזציות ספציפיות במקום "עשה את זה מהיר" — עם פרומפט שמפרט:
lazy loadingלפי מיקום ב-fold,content-visibility: autoעל sections רחוקים,font-display: swap, skeleton screens במקום spinners, ודחיית CSS לא-קריטי - תוכלו לזהות CSS כבד שהורג performance ולבקש מ-AI לתקן — עם checklist של 8 סימנים אדומים (
backdrop-filterעל רקעים גדולים,will-changeעל כל אלמנט,box-shadowמרובה שכבות, אנימציה שלwidth/heightבמקוםtransform,filter: blur()כבד, פונטים שלא מוגדרים עםswap) ולהציע תחליפים
- פרקים קודמים: פרק 10 (Responsive Design — דרישת-קדם חובה:
<picture>,srcset, WebP/AVIF,loading="lazy",width/heightattributes — כולם חוזרים כאן בהקשר של Core Web Vitals). מומלץ גם פרק 4 (Typography —font-display, Google Fonts) ופרק 9 (Glassmorphism —backdrop-filterשיופיע כאן כ-performance killer אם לא זהירים) - מושגים שיחזרו:
font-display(פרק 4), Responsive Images עם srcset/sizes (פרק 10), WebP/AVIF (פרק 10),<picture>element (פרק 10), backdrop-filter (פרק 9),clamp()ו-custom properties (פרקים 4-5) - כלים: Chrome DevTools עם Lighthouse מובנה (F12 → Lighthouse tab), PageSpeed Insights (
pagespeed.web.dev— חינם), WebPageTest (webpagetest.org— חינם ל-3 בדיקות ליום), Google Chrome UX Report, ומכשיר אמיתי עם 4G/throttled connection - אופציונלי:
web-vitalsnpm package (למדידה ב-production), Chrome User Experience Report (CrUX) dashboard ב-BigQuery, Search Console של Google לראות Core Web Vitals לפי URL - זמן משוער: 130-160 דקות (כולל 4 התרגילים — התרגיל של Lighthouse audit לבד לוקח 25-30 דקות כי מריצים מספר פעמים)
לאורך הקורס אתם בונים את היכולת להפוך אתר גנרי שAI בנה לאתר שנראה כמו עבודת סטודיו — ה-capstone בפרק 13. עד כה: פרקים 1-2 (זיהוי גנריות + premium anatomy), פרק 3 (פלטת צבעים + design tokens), פרק 4 (טיפוגרפיה, כולל font-display), פרק 5 (Layout + 8px grid), פרק 6 (Modern CSS — Container Queries, :has()), פרקים 7-8 (Scroll-driven + View Transitions), פרק 9 (Glassmorphism + backdrop-filter), פרק 10 (Responsive + <picture> + srcset + width/height). בפרק הזה (11) — לוקחים את כל זה ומוסיפים את השכבה שעושה את ההבדל בין "נראה טוב" ל-"נראה טוב ונטען תוך 2 שניות": Performance ו-Core Web Vitals. זו לא שכבה דקורטיבית — זה תנאי סף לקידום אורגני (Google מתגמל אתרים מהירים ב-search rankings), לשימור משתמשים (מובייל ב-4G עוזב אחרי 3 שניות), ולחוויה מקצועית. בפרק הבא (12 — כלי עיצוב אופציונליים: Figma, Google Stitch, MCP) תכירו כלים שיכולים להאיץ את ה-workflow שלכם, אבל עם הבנה ברורה שהידע שבניתם בפרקים 1-11 (כולל פרק ה-Performance הזה) הוא מה שקובע את האיכות — הכלים הם אופציונליים, האופטימיזציה היא לא.
| מונח (English) | תרגום | הגדרה בשורה אחת |
|---|---|---|
| Core Web Vitals | אותות ליבת-ה-Web | 3 מדדי ביצועים רשמיים של Google שמשפיעים על דירוג SEO: LCP, CLS, INP |
| LCP (Largest Contentful Paint) | הצגת האלמנט הגדול | הזמן עד שהאלמנט הגדול ביותר ב-viewport (בד"כ תמונה או כותרת) מופיע; יעד פחות מ-2.5 שניות |
| CLS (Cumulative Layout Shift) | הזזת Layout מצטברת | כמה Layout "קופץ" תוך טעינה (0 = מושלם, 0.1 = גבול המותר, מעל 0.25 = גרוע) |
| INP (Interaction to Next Paint) | תגובה לאינטראקציה | הזמן בין קליק/הקשה של המשתמש לבין התגובה הוויזואלית הבאה (יעד פחות מ-200ms) |
| FCP (First Contentful Paint) | הצגת תוכן ראשון | מתי משהו — כל דבר — מופיע על המסך (יעד פחות מ-1.8 שניות) |
| TTFB (Time To First Byte) | זמן עד לבייט ראשון | כמה זמן השרת לוקח לשלוח את ה-byte הראשון של התגובה (יעד פחות מ-800ms) |
| Lighthouse | Lighthouse | כלי חינמי של Google ב-Chrome DevTools שמריץ audit ביצועים ומחזיר score 0-100 |
| PageSpeed Insights | תובנות מהירות דף | גרסת ענן של Lighthouse ב-pagespeed.web.dev + נתוני משתמשים אמיתיים (CrUX) |
| Field Data | נתוני שטח | מדידות מ-Chrome של משתמשים אמיתיים ב-28 הימים האחרונים (CrUX) — המציאות |
| Lab Data | נתוני מעבדה | מדידה סינתטית (Lighthouse) על מכונה מדומה — קבועה אבל לא בהכרח משקפת את המשתמשים |
| Lazy Loading | טעינה עצלה | דחיית טעינת תמונה/iframe עד שהמשתמש מתקרב אליו בגלילה — loading="lazy" |
| content-visibility: auto | שקיפות-תוכן אוטומטית | Property ב-CSS שגורמת לדפדפן לדלג על rendering של אלמנטים מחוץ ל-viewport |
| contain: paint | הגבלת paint | Property שמבטיחה לדפדפן שאלמנט לא "יצבע מחוץ לקווים" — משפר זמן render |
| will-change | יעבור שינוי | רמז לדפדפן שאלמנט עומד להשתנות — מעביר אותו ל-GPU layer; שימוש זהיר בלבד |
| Critical CSS | CSS קריטי | ה-CSS המינימלי הדרוש להצגת ה-above-the-fold — מוזרק inline ב-<head> (יעד < 14KB) |
| Render-Blocking Resource | משאב חוסם-render | קובץ (CSS, JS, font) שהדפדפן חייב לטעון לפני שהוא יכול להציג את הדף — מעכב FCP ו-LCP |
11.1 למה Performance = מקצועיות — והמציאות של 4G ישראלי
יש בישראל מיתוס של "בכל מקום יש 5G עם fiber". זה לא נכון. המציאות של הגולש הישראלי הממוצע, לפי נתוני CrUX (Chrome User Experience Report) של Google: 60-70% mobile traffic (כבר ראיתם את זה בפרק 10), מתוכם 35-50% על 4G אמיתי (לא 5G, לא WiFi ביתי), עם latency ממוצע של 60-110ms ו-bandwidth של 5-15 Mbps בתנאי עומס (ערב בתל-אביב, שבת ברעננה, פיקוק עירוני). זה אומר: תמונה של 2MB שאתם רואים נטענת תוך 0.3 שניות ב-WiFi שלכם — נטענת תוך 1.6-3.5 שניות אצל המשתמש האמיתי.
המסקנה: לבדוק performance רק ב-"Desktop + Fast 3G" של DevTools זה לא performance audit אמיתי — זה אשליה. הבדיקה האמיתית: Lighthouse ב-Mobile mode, עם CPU throttling של 4x, רשת 4G. זו המציאות שבה רוב המשתמשים שלכם חיים.
- Bounce rate עולה פי 2 כשזמן טעינה עולה מ-1 ל-3 שניות (מחקר של Google/SOASTA, 2017, עדיין תקף)
- 53% ממשתמשי מובייל נוטשים אתר שלוקח יותר מ-3 שניות לטעון (Google/DoubleClick, 2016-2023)
- Core Web Vitals הוא סיגנל דירוג רשמי ב-Google Search מאז יוני 2021
- 75% מהאתרים צריכים לעמוד ביעדים כדי להיחשב "Good" ב-CrUX — מספיק שה-75th percentile יעבור
- ישראל: מובייל ממוצע ב-4G — 3-5 שניות זמן טעינה לאתר לא-מאופטם; 1-2 שניות למאופטם
נתוני Google רשמיים ב-web.dev/vitals. נתוני 4G הישראלי משתנים לפי מיקום, שעה, מפעיל רשת, ועומס. הדרך היחידה לדעת את הערך שלכם: Search Console של Google → Experience → Core Web Vitals.
למה Google מתגמל אתרים מהירים
Google לא מתגמל אתרים מהירים מ"טוב-לב". הם מתגמלים אותם כי משתמשים אוהבים אותם, וזה מה ש-Google צריכה למכור: חוויית חיפוש טובה. אתר שנטען מהר → משתמש נשאר בו יותר → מצליח למצוא את מה שחיפש → חוזר ל-Google יותר. מעגל חיובי.
המשמעות המעשית ל-Vibe Coder: אם האתר שלכם מתחרה עם 10 אחרים על אותה keyword, וכולם סיפקו את אותו תוכן — ה-מהיר ביותר יעלה בדירוג. פעם זה היה "content is king". היום זה "content + performance is king". מי שיש לו רק את ה-content, מפסיד.
אם יש לכם אתר שמחובר ל-Google Search Console: לכו ל-Experience → Core Web Vitals. רשמו:
- Mobile — Good URLs: ____ / Poor URLs: ____ / Need improvement: ____
- Desktop — Good URLs: ____ / Poor URLs: ____
אם אין לכם Search Console — הקימו אותו עכשיו (חינם, 10 דקות). אם האתר חדש ואין נתונים עדיין — השתמשו ב-PageSpeed Insights על ה-URL הראשי ורשמו את הציונים.
אתם יושבים מול Mac Studio עם SSD, חיבור fiber 1Gbps, וב-Chrome DevTools הכל נראה מצוין. LCP של 0.8 שניות, CLS של 0, INP לא רלוונטי כי לא אינטראקטיביים. אתם חוגגים ו-deploy. אבל המשתמש האמיתי — הילד בן ה-16 שגולש באוטובוס עם Samsung A52, 4G של פרטנר — מקבל LCP של 4.8 שניות. זו לא "בעיה שלו". זו התוצאה שלכם על המכשיר שלו. מה לעשות במקום: תמיד להריץ Lighthouse ב-Mobile mode עם throttling של 4x CPU + Slow 4G, תמיד לבדוק ב-PageSpeed Insights שמציג גם Field Data (מציאות) וגם Lab Data (מעבדה), ולפחות פעם בחודש להריץ את האתר על מכשיר אמיתי שקניתם מאיביי לפני 3 שנים.
11.2 Core Web Vitals — 3 המדדים של Google בשפה פשוטה
Core Web Vitals הוא שם מותג ש-Google נתנה לשלושה מדדים רשמיים שמשפיעים על דירוג ה-SEO. הם נבחרו כי הם מה שהמשתמש מרגיש, לא כי הם קלים למדידה. שלושתם ביחד מכסים את שלושת השלבים של חוויה: טעינה, יציבות, אינטראקטיביות.
| מדד | מה הוא מודד | השאלה שהוא עונה | יעד Good | יעד Poor |
|---|---|---|---|---|
| LCP Largest Contentful Paint |
זמן הצגת האלמנט הגדול ביותר ב-viewport | "מתי המשתמש רואה את הדבר החשוב?" | < 2.5 שניות | > 4.0 שניות |
| CLS Cumulative Layout Shift |
כמה דברים קפצו תוך כדי טעינה | "כמה יציב המסך בזמן שנטען?" | < 0.1 | > 0.25 |
| INP Interaction to Next Paint |
זמן התגובה הכי גרוע לאינטראקציה | "כמה מהר האתר מגיב ללחיצה?" | < 200ms | > 500ms |
75th percentile — הכלל שצריך להבין
Google לא מסתכל על הממוצע של ה-Core Web Vitals — אלא על ה-75th percentile. המשמעות: 75% מהמשתמשים שלכם חייבים לקבל חוויה "Good". אם 74% מקבלים 2 שניות LCP אבל 26% מקבלים 5 שניות — אתם ב-"Needs Improvement". ה-25% הגרועים הם מה שקובע.
זה משפיע מעשית: לא מספיק ש-"ברוב המקרים זה עובד". צריך שזה יעבוד גם למשתמש עם Android ישן ב-4G עמוס. אם יש לכם תמונה של 3MB, ה-50% של המשתמשים שלכם ב-WiFi יראו אותה מהר, אבל ה-25% על 4G — יראו LCP גרוע. ואז האתר שלכם "Poor" ב-Google, גם אם ב-Lighthouse שלכם הוא מצוין.
Google מחלק כל מדד ל-3 קבוצות: Good (ירוק, מעודד), Needs Improvement (כתום, משתפר), Poor (אדום, מעניש). היעד המעשי: להיות ב-Good על 3 המדדים. זה לא בהכרח אומר להגיע ל-Lighthouse 100. Lighthouse 75 יכול להיות "Good" על 3 CWV, וזה מה שמשנה ל-Google. אל תתרכזו במספר הגדול — תתרכזו ב-3 המדדים הספציפיים.
מה לא נכלל ב-Core Web Vitals
להשלמת התמונה — יש מדדים שהיו פעם או מומלצים, אבל לא נכללים ב-Core Web Vitals הרשמי:
- FCP (First Contentful Paint) — חשוב, אבל "רק" תמיכה. מודד מתי משהו מופיע (כותרת, icon). יעד: < 1.8s.
- TTFB (Time To First Byte) — מדד של השרת, לא של ה-frontend. יעד: < 800ms.
- TBT (Total Blocking Time) — מדד מעבדה שהוחלף ב-INP (שהוא מציאותי יותר).
- FID (First Input Delay) — הוחלף רשמית ב-INP במרץ 2024. אם אתם רואים FID במקומות ישנים — הוא לא בשימוש יותר.
פתחו pagespeed.web.dev. הכניסו את ה-URL של האתר שלכם. המתינו 20-30 שניות. רשמו:
- Mobile — LCP: ____ / CLS: ____ / INP: ____
- Mobile — ציון כללי: ____ / 100
- Desktop — ציון כללי: ____ / 100
אם אין "Field Data" למעלה — זה אומר שאין מספיק תנועה אמיתית ל-CrUX. במקרה כזה, רק ה-Lab Data (Lighthouse) רלוונטי. זה לא שבר — פשוט פחות מדויק.
11.3 LCP — Largest Contentful Paint (יעד < 2.5 שניות)
LCP מודד את הזמן שחלף מהרגע שהמשתמש "נחת" על הדף (request התחיל) ועד שהאלמנט הגדול ביותר ב-viewport הופיע. ב-90% מהאתרים, האלמנט הזה הוא או תמונת ה-hero, או כותרת ה-h1, או background image של hero section. זה האלמנט שאומר למשתמש "הדף נטען, התוכן מוכן".
מה גורם ל-LCP גרוע — 4 הגורמים הנפוצים ביותר
- תמונת hero כבדה מדי. JPEG של 1.8MB שאפשר להיות 120KB ב-AVIF. זו הסיבה #1 באתרי ישראל.
- פונט עברי שחוסם render. Heebo עם 9 משקלים = 450KB. עד שהפונט נטען, הדפדפן לא מציג את הכותרת (אם
font-display: block) — וה-LCP נדחה. זו סיבה #2 באתרי ישראל. - Lazy loading על ה-hero image. הטעות שדיברנו עליה בפרק 10 —
loading="lazy"על תמונה שמופיעה במיקום הראשון. - Render-blocking CSS או JS. קובץ CSS של 300KB נטען סינכרונית ב-
<head>, חוסם את הכל.
איך מוצאים מה ה-LCP element של הדף שלכם
Chrome DevTools → Performance tab → Record → רענן את הדף → Stop. בתצוגת התוצאות תראו קו בציר הזמן עם "LCP". הקליקו עליו. בפינה הימנית התחתונה ("Related Node") תראו איזה אלמנט ספציפי היה ה-LCP. רוב הסיכויים — תמונה או כותרת.
דרך מהירה יותר: Lighthouse → Performance → Largest Contentful Paint → "View Trace" או לחיצה על ה-item. הוא יראה בדיוק איזה אלמנט.
איך מתקנים LCP — 5 אופטימיזציות בסדר חשיבות
- תמונה מאופטמת + preload. הקטינו את ה-hero image ל-AVIF + WebP (מפרק 10). הוסיפו
<link rel="preload" as="image">ב-<head>:<link rel="preload" as="image" href="hero-1200.avif" type="image/avif" imagesrcset="hero-400.avif 400w, hero-800.avif 800w, hero-1200.avif 1200w" imagesizes="(min-width: 1024px) 1200px, 100vw" fetchpriority="high" /> - fetchpriority="high" על ה-img tag. גם אם אין preload —
<img fetchpriority="high" loading="eager">אומר לדפדפן "זה החשוב". - Font loading עם swap.
font-display: swapאומר לדפדפן "תציג fallback מיד, תחליף כשהפונט נטען". כך ה-h1 מופיע תוך 100ms עם Arial, ואז מתחלף ל-Heebo — אבל LCP נרשם על ה-Arial, והוא מהיר. - CDN לתמונות. Cloudflare Images, Cloudinary, Vercel Image — כולם מחזירים את התמונה הנכונה לגודל המסך, מהשרת הקרוב ביותר ל-user.
- הסרת render-blocking resources. CSS קריטי inline, שאר ה-CSS בסוף ה-body או עם
media="print" onload="this.media='all'"(טריק ידוע).
| ה-LCP element שלכם הוא... | הבעיה הסבירה | התיקון הראשון לנסות |
|---|---|---|
| תמונה (hero, product) | משקל גדול / lazy loading / ללא preload | AVIF + fetchpriority="high" + <link rel="preload"> |
| Heading (h1) | פונט לא נטען מיד / font-display: block | font-display: swap + preload של font |
| Background image | לא ניתן ל-preload בקלות | להעביר ל-<img> עם position: absolute, ואז preload |
| Video / iframe | Autoplay כבד | Poster image כ-fallback + preload="none" על video |
| Text block (long paragraph) | Render-blocking CSS שוחק FCP | Critical CSS inline + Font swap |
פתחו את האתר שלכם. DevTools → Lighthouse → Mobile → Performance → Generate Report. כשסיים, לכו ל-"Largest Contentful Paint" → לחצו על ה-item. רשמו:
- ה-LCP element של הדף הוא: ____ (img / h1 / div / אחר)
- ה-LCP time: ____ שניות
- האם זה ב-Good (< 2.5s) / Needs Improvement / Poor (> 4s): ____
אם LCP מעל 2.5 שניות — המדד הזה הוא ה-priority הראשון לתיקון. בתרגיל 2 של הפרק תתקנו אותו.
11.4 CLS — Cumulative Layout Shift (יעד < 0.1)
CLS מודד כמה "הדף קופץ" תוך כדי טעינה. זה המדד הכי פחות מוכר אבל הכי מרגיז למשתמש: אתם עומדים לקרוא טקסט, ופתאום תמונה נטענת למעלה ומזיזה את כל התוכן למטה — ואתם לוחצים על הדבר הלא-נכון. CLS של 0 = מושלם. CLS של 0.1 = גבול "Good". מעל 0.25 = "Poor".
המספר מחושב כמכפלה של impact fraction (כמה שטח המסך השתנה) × distance fraction (כמה רחוק זז). לא חשוב להבין את הנוסחה — חשוב להבין את הסיבות.
5 הסיבות הנפוצות ל-CLS גרוע
- תמונות בלי
widthו-heightattributes. הדפדפן לא יודע איזה שטח להקצות. התמונה נטענת, התוכן קופץ למטה. הסיבה #1 בישראל. - פונט עם
swapשגורם ל-FOUT (Flash Of Unstyled Text). הפונט fallback רוחב שונה מהפונט האמיתי — הטקסט "זורם" אחרת כשהפונט מתחלף. תיקון:size-adjustב-@font-face. - Ads או embeds בלי מידות קבועות. iframe של YouTube / מודעות / טוויטר embed — כולם יכולים "להתרחב" אחרי שה-content שלהם נטען. תיקון:
aspect-ratioאוheightמפורש. - Cookie banner שמופיע בראש הדף אחרי שהתוכן כבר נטען. דוחף הכל למטה. תיקון:
position: fixedבתחתית, אוheightreserved בראש. - תוכן שמוזרק דינמית (fetch/AJAX) בתוך תוכן קיים. תגובות שנטענות, טופסי newsletter שמופיעים. תיקון: skeleton screens עם
heightקבוע שמוחלפים בתוכן.
איך מתקנים CLS — 3 תיקונים שמחסלים 80% מהבעיות
1. תמיד width ו-height על כל תמונה. לא בתור ציון גודל התצוגה — אלא בתור יחס. הדפדפן משתמש בהם לחשב aspect-ratio ולהקצות שטח לפני שהתמונה נטענת.
<!-- רע — גורם CLS -->
<img src="product.jpg" alt="מוצר" />
<!-- טוב — מונע CLS -->
<img
src="product.jpg"
alt="מוצר"
width="800"
height="600"
/>
/* CSS — ה-aspect-ratio נשמר גם כשהתמונה responsive */
img {
width: 100%;
height: auto;
/* aspect-ratio נגזר מ-attributes אוטומטית */
}
2. Reserve space לכל embed/iframe. שימוש ב-aspect-ratio:
.video-embed {
width: 100%;
aspect-ratio: 16 / 9; /* מקצה שטח לפני הטעינה */
}
.video-embed iframe {
width: 100%;
height: 100%;
border: 0;
}
3. Font metric override ב-@font-face. טיפ מתקדם ממש: שולט ב-fallback font להראות זהה למידות של הפונט האמיתי. נקרא "adjusted font fallback":
/* Fallback font עם metrics מותאמים ל-Heebo */
@font-face {
font-family: 'Heebo Fallback';
src: local('Arial');
size-adjust: 107%; /* מתאים רוחב */
ascent-override: 90%; /* מתאים גובה שורה */
descent-override: 25%;
line-gap-override: 0%;
}
body {
font-family: 'Heebo', 'Heebo Fallback', sans-serif;
}
התוצאה: הטקסט הראשוני (עם Arial) יתפוס בדיוק את אותו שטח כמו שהטקסט הסופי (עם Heebo) יתפוס. לא יהיה "קפיצה" כשהפונט מתחלף.
width?"
כשהתמונה היא width: 100% ב-CSS, מפתחים/AI מניחים שה-HTML attributes width ו-height מיותרים. טעות. ה-attributes האלה נותנים לדפדפן את היחס (aspect ratio) של התמונה לפני שהוא מתחיל להוריד אותה. בלעדיהם, הדפדפן מקצה 0×0, התמונה נטענת, ה-aspect ratio מתחשב, וכל הדף קופץ למטה — CLS של 0.15+. מה לעשות במקום: תמיד להוסיף width ו-height attributes שתואמים את יחס המימדים של התמונה (800×600, 1200×800 וכו'), גם אם ב-CSS התמונה תהיה 100% רוחב. זה מספיק.
פתחו את קובץ ה-HTML הראשי. Ctrl+F ו-חפשו <img. עברו על כל tag. רשמו:
- סה"כ
<img>tags: ____ - כמה יש להם
widthו-heightattributes: ____ - כמה חסרים לפחות אחד מהם: ____
כל תמונה שחסר לה width או height — candidate לגרום CLS. הוסיפו אותם. אם אתם לא יודעים את היחס — פתחו את התמונה ורשמו את המימדים בפיקסלים.
11.5 INP — Interaction to Next Paint (יעד < 200ms)
INP החליף את FID רשמית במרץ 2024. ההבדל: FID מדד רק את ה-interaction הראשון; INP מודד את ה-interaction הכי גרוע לאורך ביקור המשתמש. זה מציאותי הרבה יותר — כי משתמש שלחץ 10 פעמים על כפתורים וכל אחד הגיב תוך 100ms חוץ מאחד שלקח 800ms — INP שלו = 800ms.
ל-INP יש מרכיבים: Input delay (כמה זמן ה-browser עסוק ולא יכול לענות), Processing time (כמה זמן ה-JS רץ בתגובה), ו-Presentation delay (כמה זמן לוקח לצייר את השינוי).
איפה זה קשור ל-CSS (כי אתם Vibe Coders, לא מפתחי JS)
INP נחשב "בעיית JavaScript" — וברוב המקרים הוא אכן כזה (JS כבד שחוסם את ה-main thread). אבל יש סיבות ל-INP גרוע שקשורות ישירות ל-CSS:
- אנימציות שלא רצות על ה-GPU. אנימציה של
width,height,margin,top/left— כולן גורמות ל-reflow (חישוב layout מחדש). רצות על ה-main thread. INP מתפוצץ. backdrop-filterו-filter: blurכבדים. כל rerender של האלמנט מפעיל את ה-blur מחדש — אם זה קורה בזמן scroll או hover, INP מתארך.- Shadows מרובות שכבות על hover.
transition: box-shadow 0.3sעם 3 layered shadows — כל frame מחשב מחדש 3 shadows. - Hit testing ב-elements גדולים.
position: fixedעםoverflow: hiddenעל elements עצומים — הדפדפן צריך לחשב מי מקבל את הקליק.
Rule of Thumb ל-CSS שרץ על GPU
אנימציות שרצות על ה-GPU (לא חוסמות את ה-main thread, לא גורמות reflow): רק transform ו-opacity. זה הכל.
/* רע — גורם reflow, INP גבוה */
.card {
transition: width 0.3s, margin-top 0.3s;
}
.card:hover {
width: 320px;
margin-top: -10px;
}
/* טוב — GPU-accelerated, INP נמוך */
.card {
transition: transform 0.3s;
}
.card:hover {
transform: translateY(-10px) scale(1.02);
}
הטיפ הזה לבד — "רק transform ו-opacity באנימציות" — מחסל כ-60% מבעיות ה-INP ב-CSS.
| רוצים לשנות... | במקום... | השתמשו ב... |
|---|---|---|
| מיקום (נע) | top, left, margin | transform: translate() |
| גודל (גדל/קטן) | width, height | transform: scale() |
| רוטציה | rotation (ישן) | transform: rotate() |
| העלמה/הופעה | display: none | opacity: 0 + visibility: hidden |
| שקיפות | כל דבר אחר | opacity (אחד הבודדים שבאמת GPU-accelerated) |
| צבע/border | עם transition | אפשר transition, אבל מוגבל — לא לאנימציות ארוכות |
פתחו קובץ CSS. חפשו transition: ו-@keyframes. עברו על כל אחד:
- אנימציות של
transform/opacity: ____ (GPU-accelerated, טוב) - אנימציות של
width/height/margin/top/left: ____ (reflow, רע) - אנימציות של
box-shadow: ____ (paint-heavy, בינוני)
כל אנימציה בעייתית — רשמו את ה-selector. בתרגיל 3 תמירו אותן ל-transform/opacity.
11.6 Lighthouse — איך להריץ ומה המספרים אומרים
Lighthouse הוא הכלי הראשי לאודיט performance. הוא מובנה ב-Chrome DevTools (F12 → Lighthouse tab), הוא חינמי לגמרי, והוא נותן לכם ציון 0-100 על 5 קטגוריות: Performance, Accessibility, Best Practices, SEO, ו-PWA (לפעמים).
הריצה הנכונה — לא הריצה שעושים
- Incognito mode. Extensions של Chrome (uBlock, Grammarly) משפיעים על תוצאות. תמיד Lighthouse ב-Incognito.
- Device: Mobile (לא Desktop). זה מה ש-Google Search מסתכל עליו. Desktop הוא bonus אחרי שה-Mobile בסדר.
- Categories: רק Performance לבדיקה ראשונית. כל קטגוריה מאריכה את הזמן; מתחילים ב-Performance, אחרי שזה טוב עוברים לשאר.
- Mode: Navigation (default). יש גם "Timespan" ו-"Snapshot", אבל עבור performance הכלל הוא Navigation.
- הרצה 3-5 פעמים ולקחת את המדיאן. תוצאות Lighthouse יש להן שונות של 5-15 נקודות בין הרצות. הרצה אחת = מטעה. 3 הרצות ולקחת את האמצעית — אמין הרבה יותר.
איך לפרש את ה-Performance score
| Range | צבע | משמעות | מה לעשות |
|---|---|---|---|
| 90-100 | ירוק | Excellent | שמרו, ואל תעשו regressions |
| 50-89 | כתום | Needs improvement | תתרכזו ב-top 3 issues לפי ה-"Opportunities" |
| 0-49 | אדום | Poor | הפרויקט דורש עבודה רצינית — לפחות LCP, CLS, ו-JS bundle size |
ה-5 מדדים שמרכיבים את ה-Performance score
ה-score הוא ממוצע משוקלל של 5 מדדים:
- FCP (First Contentful Paint) — 10% מהציון. יעד: < 1.8s.
- LCP (Largest Contentful Paint) — 25% מהציון. יעד: < 2.5s.
- Total Blocking Time (TBT) — 30% מהציון. Lab metric שמחליף את INP בסיטואציית מעבדה. יעד: < 200ms.
- Cumulative Layout Shift (CLS) — 25% מהציון. יעד: < 0.1.
- Speed Index — 10% מהציון. מדד חלופי של "כמה מהר נראה שהדף נטען".
המשמעות: TBT + LCP = 55% מהציון. אם רוצים לשפר performance — מתחילים שם.
Opportunities ו-Diagnostics — איפה הזהב
אחרי ה-score, Lighthouse מציג 2 מדורים חשובים:
- Opportunities — "אם תעשו X, תחסכו Y שניות". ממוינים לפי החיסכון המשוער. דוגמאות: "Serve images in next-gen formats" (AVIF/WebP), "Eliminate render-blocking resources", "Properly size images", "Reduce unused JavaScript", "Preconnect to required origins".
- Diagnostics — תובנות שאין להן זמן ספציפי. דוגמאות: "Minimize main-thread work", "Avoid enormous network payloads", "Ensure text remains visible during webfont load".
המלצת זהב: לטפל ב-Opportunities לפי הסדר, מהחיסכון הגדול ביותר. כל טיפול אחד מחסן 0.5-2 שניות בדר"כ.
Lighthouse Mobile משתמש ב-"Slow 4G" + 4x CPU throttling. זה טוב לסטנדרט של Google. אבל אם תרצו לבדוק את החוויה של משתמש על מכשיר ישן ברשת גרועה: לכו ל-Network tab → Throttling → "Slow 3G", ואז ב-Performance tab → CPU → 6x slowdown. הריצו עמוד. תקבלו חוויה של משתמש עם Samsung A10 באוטובוס צפוף. אם עובר שם — עובר בכל מקום.
פתחו Chrome, ואז Incognito mode. נווטו לאתר שלכם. F12 → Lighthouse. בחרו: Mobile + Performance only + Navigation. הריצו 3 פעמים. רשמו את 3 ה-scores:
- הרצה 1: ____ / הרצה 2: ____ / הרצה 3: ____
- המדיאן (האמצעי): ____
- LCP מהמדיאן: ____ / CLS: ____ / TBT: ____
המדיאן זה ה-score האמיתי שלכם. אל תסתמכו על ההרצה הטובה ביותר — Google הוא המדיאן ברוב המקרים.
11.7 PageSpeed Insights — Field Data vs Lab Data
PageSpeed Insights (PSI) ב-pagespeed.web.dev הוא הכלי הרשמי של Google לבדיקת ביצועים. מה שמבדיל אותו מ-Lighthouse המקומי: הוא רץ מהשרת של Google ומציג שני מקורות נתונים — Field Data ו-Lab Data. הבנת ההבדל קריטית.
| Field Data (CrUX) | Lab Data (Lighthouse) | |
|---|---|---|
| מקור: | משתמשי Chrome אמיתיים ב-28 ימים אחרונים | הרצה סינתטית של Google |
| מה רואים: | 75th percentile של משתמשים אמיתיים | הרצה אחת במכונת בדיקה |
| יתרון: | המציאות — זה מה ש-Google Search מסתכל עליו | deterministic — תוצאות יציבות לפחות |
| חיסרון: | דורש תנועה מינימלית (אלפי משתמשים בחודש) | עלול לא לשקף את החוויה של משתמשים אמיתיים |
| מתי להסתכל: | אתר ב-production עם תנועה | אתר חדש / staging / לוודא שלא נשבר משהו |
מה קורה כשאין Field Data
בפתיחת PSI, אם האתר שלכם קטן או חדש — תראו "Real-user experience data is unavailable". זה בסדר. זה אומר: המשתמשים שלכם פחות מהמספר הנדרש ל-CrUX. במקרה הזה, הסתמכו רק על Lab Data (שזה הדבר היחיד שיש), ובנוסף — השתמשו ב-web-vitals npm package כדי לאסוף נתונים משלכם.
<!-- קוד מינימלי לאיסוף Core Web Vitals מדפדפני משתמשים -->
<script type="module">
import { onCLS, onINP, onLCP } from 'https://unpkg.com/web-vitals@4?module';
function sendToAnalytics(metric) {
// שלחו ל-Google Analytics, Plausible, או endpoint שלכם
console.log(metric.name, metric.value);
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
</script>
פער בין Field ל-Lab — מה זה אומר
- Field טוב, Lab גרוע: סביר שה-Lab הוא "worst case". המשתמשים שלכם נמצאים ב-conditions טובים יותר ממה ש-Lighthouse מדמה. תמשיכו לפקח אבל לא פאניקה.
- Field גרוע, Lab טוב: תמרור אדום. המציאות גרועה מהבדיקה. סביר שיש בעיית שרת (TTFB גבוה) או משתמשים ב-regions עם רשת גרועה. חפרו ב-Search Console לפי country/device.
- שניהם טובים: מצוין. המשיכו לפקח.
- שניהם גרועים: יש לכם עבודה. הסדר: LCP → CLS → TBT → INP.
ב-PSI (pagespeed.web.dev), הריצו על ה-URL שלכם. אם יש Field Data — רשמו:
- Field LCP: ____ / Lab LCP: ____ / פער: ____
- Field CLS: ____ / Lab CLS: ____ / פער: ____
- Field INP: ____ (Lab INP לא קיים — TBT במקום)
פער של פחות מ-20% — סביר. מעל 50% — לחפש מה שונה בתנאי המשתמשים שלכם (geography, device mix, network).
11.8 רוצחי Performance ב-CSS — מה להימנע ממנו
CSS נחשב "קל". זה לא נכון לגמרי. יש properties ודפוסים ב-CSS שהורגים performance שקטים — לא תראו אותם ב-JavaScript profiler, אבל תרגישו אותם ב-LCP ו-INP. הנה ה-8 הגדולים, לפי סדר חשיבות.
1. backdrop-filter על רקעים גדולים
בפרק 9 (Glassmorphism) למדתם backdrop-filter: blur(). הוא מדהים. הוא גם כבד. הדפדפן חייב לצייר את כל מה שמאחורי האלמנט, ואז להחיל blur על כל פיקסל. על אלמנט קטן (navbar, card קטן) — זה בסדר. על hero של 100vw × 70vh — זה קטסטרופה.
- בסדר:
backdrop-filter: blur(10px)על card של 400×300px. - רע:
backdrop-filter: blur(20px)על section של viewport מלא. - תחליף: להחליף ב-
background: rgba() + pseudo-element עם background-image blurred pre-baked.
2. will-change על כל אלמנט
AI אוהב להוסיף will-change: transform על כל אלמנט עם hover animation. זה הפוך מאופטימיזציה. will-change אומר לדפדפן "תרים את האלמנט ל-GPU layer עצמאי". זה צורך זיכרון GPU. אם יש לכם 50 אלמנטים עם will-change, הדפדפן יוצר 50 layers, RAM של ה-GPU נגמר, ואז הכל מאט.
will-change על כל אלמנט — זה הפוך מאופטימיזציה
Vibe Coders ש-"שמעו שזה מאיץ אנימציות" מוסיפים will-change: transform על כל .card, .button, .hero. זו טעות קריטית. will-change מאלץ את הדפדפן להקצות layer GPU קבוע לאלמנט — גם אם הוא לא מאונמטם כרגע. עם 50 אלמנטים כאלה, זיכרון ה-GPU נגמר, וכל האתר מאט (במיוחד על mobile). הכלל הנכון: will-change רק על אלמנט שבאמת עומד להשתנות בעוד רגע, ורק סביב האירוע. להסיר אותו אחרי. דוגמה:
.card:hover { will-change: transform; } — מפעיל רק ב-hover, לא תמידית.
או ב-JS:
el.style.willChange = 'transform'; / doSomething(); / el.style.willChange = 'auto';.
מה לעשות במקום של will-change קבוע: להשתמש ב-transform: translateZ(0) רק כשחייבים (זה "GPU hint" יותר עדין), או פשוט להסתמך על זה שהדפדפן אופטימלי בעצמו.
3. box-shadow מרובה שכבות מונפש
ב-premium design, אתם משתמשים ב-layered shadows (3-5 shadows יחד לעומק מציאותי). זה מצוין ויזואלית. אבל: transition: box-shadow 0.3s על hover של כל card — הדפדפן מצייר 3-5 shadows בכל frame. 60fps × 5 shadows = 300 paint operations לשנייה. אופציות:
- תחליף: אנמיש רק שקיפות של pseudo-element שמכיל את ה-shadow:
.card { position: relative; } .card::after { content: ""; position: absolute; inset: 0; box-shadow: 0 20px 40px rgba(0,0,0,0.15); opacity: 0; transition: opacity 0.3s; pointer-events: none; border-radius: inherit; } .card:hover::after { opacity: 1; } - התוצאה: אנימציה של
opacityבלבד (GPU-accelerated), box-shadow קבוע לא מחושב מחדש. חלק, מהיר.
4. אנימציה של width/height
כל שינוי של width, height, top, left, margin, padding — מפעיל reflow של כל הדף. reflow = דפדפן מחשב מחדש את ה-layout של כל האלמנטים. זה יקר. תחליף: transform: scale() ו-transform: translate() (ראו framework ב-section 11.5).
5. filter: blur() בזמן scroll
אפקט פופולרי: תמונה ברקע שעושה blur כשגוללים. בעיה: filter: blur() בזמן scroll מפעיל GPU work על כל פריים. ב-desktop זה בסדר; על mobile זה 5fps. תחליפים: להשתמש ב-backdrop-filter על overlay (קל יותר), או ל-pre-blur את התמונה ב-Photoshop/Squoosh ולאפשר אותה כ-background.
6. Gradients מונפשים (aurora background)
בפרק 9 ראיתם aurora backgrounds עם radial-gradients מונפשים. אפקט מדהים. אבל: gradient ב-CSS לא GPU-accelerated — כל frame מחשב אותו מחדש. פתרון: במקום background-position animation, השתמשו ב-transform: translate של pseudo-element עם gradient קבוע:
/* רע — animation של background-position, רץ על CPU */
.aurora {
background: radial-gradient(circle at 20% 50%, #8b5cf6, transparent);
animation: shift 10s infinite;
}
@keyframes shift {
50% { background-position: 80% 50%; }
}
/* טוב — transform של pseudo-element, רץ על GPU */
.aurora {
position: relative;
overflow: hidden;
}
.aurora::before {
content: "";
position: absolute;
inset: -20%;
background: radial-gradient(circle, #8b5cf6, transparent 60%);
animation: drift 10s infinite ease-in-out;
will-change: transform; /* כאן זה מוצדק — animation תמידית */
}
@keyframes drift {
50% { transform: translate(20%, 10%) scale(1.2); }
}
7. :hover על elements גדולים עם transition
לדוגמה: .section:hover { background: #f0f0f0; transition: 0.5s; } על section שהוא 100vw רוחב. בכל זיז של עכבר, הדפדפן בודק אם לצייר section מחדש. לרוב לא מורגש, אבל על mobile שה-hover = touch start — זה כן.
8. פונטים שלא מוגדרים עם font-display: swap
זה נושא הפרק הבא (section 11.15), אבל מספיק להגיד: אם הפונט לא מוגדר עם swap, הטקסט לא מופיע עד שהפונט נטען — זה LCP גרוע. הסיבה #2 ל-LCP גבוה בישראל.
פתחו קובץ CSS. חפשו כל אחד מהבאים:
backdrop-filter— מופיע על אלמנט גדול מ-500×500px? ____ (כן/לא)will-change— כמה מקומות: ____ (מעל 5 = בעיה)box-shadowבתוךtransition— כמה: ____transition: width/transition: height/transition: margin: ____
כל אחד מאלה הוא candidate לתיקון. בתרגיל 3 תטפלו בכולם.
11.9 Lazy Loading — תמונות, iframes, ו-content מתחת ל-fold
Lazy loading = "אל תטען את זה עד שהמשתמש מתקרב אליו". ב-2020 דרש JS (IntersectionObserver); ב-2026 זה native ב-HTML עם loading="lazy". Browser support ב-2026: 95%+ (Chrome, Edge, Firefox, Safari 15.4+).
מה לטעון lazy, ומה לא
| אלמנט | מיקום | Lazy? |
|---|---|---|
| Hero image | Above the fold | לא — loading="eager" fetchpriority="high" |
| Navigation logo | Above the fold | לא |
| Product images ב-grid | Above/Below the fold | העליונות = eager; מהשלישית והלאה = lazy |
| Article body images | Below the fold | כן — loading="lazy" |
| Footer images | Below the fold | כן — loading="lazy" |
| YouTube embed | כל מקום | כן — loading="lazy" על iframe (תמיד) |
| Map embed | כל מקום | כן |
| Third-party widgets (social) | כל מקום | כן |
הסינטקס המלא
<!-- תמונה מתחת ל-fold -->
<img
src="article-image.jpg"
srcset="article-400.jpg 400w, article-800.jpg 800w"
sizes="(min-width: 768px) 800px, 100vw"
alt="תיאור"
width="800"
height="500"
loading="lazy"
decoding="async"
/>
<!-- iframe (YouTube, Map) — תמיד lazy -->
<iframe
src="https://www.youtube.com/embed/xxx"
loading="lazy"
width="560"
height="315"
allowfullscreen
></iframe>
<!-- Hero (אל תסמנו lazy!) -->
<img
src="hero-1200.webp"
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
sizes="100vw"
alt="תיאור"
width="1200"
height="800"
loading="eager"
fetchpriority="high"
/>
decoding="async" — ה-attribute ששכחו ממנו
decoding="async" אומר לדפדפן "תפענח את ה-image ב-background thread, לא ב-main thread". זה לא משנה הרבה ב-desktop, אבל ב-mobile עם CPU חלש זה משפר INP משמעותית. הוסיפו אותו לכל תמונה מלבד ה-hero (שם אפשר decoding="sync").
loading="lazy" על תמונת hero — LCP נהרס
(חוזרים על זה כי זה הטעות השנייה-הכי-נפוצה של AI, אחרי will-change). AI בונה את ה-<img> של ה-hero, ומוסיף loading="lazy" כי "זה best practice". זה הפוך מ-best practice עבור hero. ה-hero הוא בדרך כלל ה-LCP element; אם הוא lazy, הדפדפן מחכה לו, ה-LCP מתעכב, והציון נופל מ-90 ל-55. מה לעשות במקום: תמיד loading="eager" + fetchpriority="high" על hero image, ו-<link rel="preload"> ב-<head> כחיזוק נוסף. Lazy loading הוא רק מתחת ל-fold.
פתחו את עמוד הבית של האתר. ספרו כמה <img> יש בו. לכל אחד, רשמו:
- Above the fold (נראה מיד): ____ (צריכים להיות
eager) - Below the fold (דורש גלילה): ____ (צריכים להיות
lazy) - כמה עם
loading="lazy"נכון: ____ - כמה עם
loading="lazy"שגוי (על hero): ____ ← בעיה
11.10 content-visibility: auto — הדפדפן לא מרנדר מה שלא רואים
content-visibility: auto היא אחת הפיצ'רות הכי עוצמתיות של CSS המודרני שרוב ה-Vibe Coders לא מכירים. הרעיון פשוט: הדפדפן יכול לדלג על rendering של אלמנטים שנמצאים מחוץ ל-viewport. זה לא lazy loading של תמונות — זה lazy loading של layout + paint של sections שלמים.
איך זה עובד
.section {
content-visibility: auto;
contain-intrinsic-size: 0 800px; /* החלקה ידנית של גובה משוער */
}
שני שורות. הדפדפן עושה:
- אם ה-
.sectionמחוץ ל-viewport: דלג על render, paint, layout. חוסך 30-70% מזמן ה-initial render. - אם ה-
.sectionקרוב ל-viewport (המשתמש גולל אליו): render מלא, שקוף למשתמש. contain-intrinsic-size: אומר לדפדפן "אני לא מרנדר כרגע, אבל תניח שזה 800px גובה" — כדי שה-scrollbar יהיה נכון.
מתי זה מועיל במיוחד
- דפי long-form (blog posts, docs). 10 sections, רק 1-2 נראות. שאר ה-8 לא צריכים render עד שהמשתמש מגלל.
- Landing pages עם הרבה sections. hero, features, testimonials, pricing, FAQ, footer — 6 sections, רוב המשתמשים רואים רק את ה-hero לפני שהם סוגרים. חיסכון עצום.
- Lists ארוכים. product grid של 50 items, רק 9 נראות. ה-41 האחרונות לא צריכות render.
מה לא לעשות איתו
- לא על elements קטנים. Overhead של
content-visibility(הדפדפן צריך לחשב מתי לרנדר) שווה רק על sections גדולים — 300px+ גובה. - לא על elements שמצייתים ל-accessibility focus. יש דיווחים על screen readers שלא קוראים תוכן עם
content-visibility: autoלפעמים. לבדוק. - לא בלי
contain-intrinsic-size. בלעדיו, כל section שלא מרונדר "נעלם" מה-scrollbar, וה-scroll position קופץ. תמיד להוסיף size estimate.
Browser support ב-2026
Chrome 85+, Edge 85+, Firefox 125+ (יחסית חדש, מ-2024), Safari 17.6+. בסה"כ 93%+ global. Fallback: הדפדפן הישן פשוט ירנדר הכל (בסדר — זה רק הפסד של אופטימיזציה, לא שבירה של פונקציונליות).
Hero section — בלי content-visibility (הוא תמיד ב-viewport). כל section אחר — content-visibility: auto + contain-intrinsic-size: 0 600px (התאמה לגובה ממוצע). במבחן אמיתי על landing page של 8 sections: time-to-interactive ירד מ-3.2s ל-2.1s. זה שיפור של כמעט שנייה שלמה מ-2 שורות CSS.
11.11 contain: paint — הגבלת rendering לאזור
contain הוא property שאומר לדפדפן "תנחש משהו על האלמנט הזה". יש 4 ערכים: size, layout, style, paint. רוב הזמן, contain: paint הוא מה שמעניין אותנו.
המשמעות: הדפדפן יכול להניח שהאלמנט לא "מצייר מחוץ לגבולות שלו". זה חותך את מחשבי ה-paint tree משמעותית.
.card {
contain: paint;
/* או משולב: */
contain: layout paint;
}
מתי להשתמש
- Cards עם
overflow: hidden. אתם כבר חותכים את ה-overflow —contain: paintאומר את זה גם לדפדפן. - Widgets מבודדים. chat box, modal, sidebar — אלמנטים שיש להם גבולות ברורים.
- אזורים עם אנימציות שאתם רוצים "לבודד" כך שהאנימציה לא מפעילה re-paint של שאר הדף.
ההבדל בין contain: paint ל-content-visibility: auto
contain: paint | content-visibility: auto | |
|---|---|---|
| מה הוא עושה: | חותך paint לאזור האלמנט | דולג על render מלא כשמחוץ ל-viewport |
| השפעה: | קטנה-בינונית, תמידית | גדולה, אבל רק מחוץ ל-viewport |
| מתי: | Cards, widgets, אזורים מבודדים | Sections גדולים בדף ארוך |
| Browser support: | 95%+ | 93%+ |
שילוב: על section של blog post, אפשר לשים גם content-visibility: auto וגם contain: paint — הם משלימים, לא מחליפים.
11.12 will-change — רמז עוצמתי, שימוש זהיר
דיברנו עליו ב-section 11.8 ובאזהרה הקודמת. כאן מרחיבים: מתי כן להשתמש, מתי לא, והחלופות.
מה will-change באמת עושה
הוא אומר לדפדפן: "האלמנט הזה עומד להשתנות בקרוב, תכין את עצמך". הדפדפן בתגובה:
- מרים את האלמנט ל-GPU layer עצמאי (composited layer).
- מקצה לו זיכרון GPU ייעודי.
- מפריד את ה-rendering שלו מ-rendering של שאר הדף.
זה מדהים עבור אלמנטים שעומדים לעבור אנימציה ברגע הקרוב — מוחק latency של "הכנה". אבל אם זה לא קורה — בזבוז GPU memory.
הכלל המעשי
- כברירת-מחדל: אל תשתמשו. הדפדפן בעצמו יודע לאופטם אנימציות של
transformו-opacity. - להשתמש רק אם ראיתם הוכחה ל-jank. פתחו DevTools → Performance. הקליטו אנימציה. אם יש "long tasks" או "frame drops" — שקלו
will-change. - אם בכל זאת צריך — להשתמש באופן ממוקד:
/* טוב — על hover event, לזמן קצר */ .button { transition: transform 0.3s; } .button:hover { will-change: transform; transform: scale(1.05); } /* רע — כל הזמן, בלי סיבה */ .button { will-change: transform; } - לכל היותר 3-5 אלמנטים בדף עם
will-changeקבוע. ולא כל card/button/link.
חלופה עדינה: transform: translateZ(0)
טריק ישן שעדיין עובד — transform: translateZ(0) גם מרים אלמנט ל-GPU layer, אבל בלי להצהיר על כוונה (פחות אגרסיבי). שימושי כשאתם באמת רוצים להבטיח GPU compositing בלי הטיה של הדפדפן לאופטים אגרסיביים.
11.13 Critical CSS — מה לטעון מיד, מה לדחות
Critical CSS = ה-CSS המינימלי הדרוש להציג את ה-above the fold של הדף. הרעיון: במקום לטעון CSS של 150KB סינכרונית (חוסם render ל-500ms), להזריק את ה-critical (14KB) ישירות ב-<head> עם <style> inline, ואת שאר ה-CSS לטעון async.
למה 14KB — מגבלה קסומה?
TCP slow start: החיבור הראשון של HTTP/2 ל-server שולח את ה-14KB הראשונים ב-round trip אחד. כל דבר מעל זה דורש round trip נוסף, שמוסיף 100-300ms. לכן אם ה-critical CSS שלכם מתחת ל-14KB, הוא מגיע בתוך ה-HTML הראשון, והדפדפן יכול להתחיל לצייר ברגע שה-HTML הגיע.
איך מחלצים critical CSS
- ידנית (רלוונטי לאתרים קטנים): פתחו את הדף. רשמו את כל ה-selectors שמופיעים ב-above the fold (hero, nav, logo, ה-h1). העתיקו רק את ה-CSS שלהם.
- אוטומטית (לאתרים גדולים): כלי כמו
criticalnpm package,Penthouse, או service כמוCriticalCSS.com. הם מריצים את הדף ב-headless browser, מזהים אילו selectors פעילים ב-above the fold, ומחלצים אותם.
הדפוס המעשי
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>עמוד הבית</title>
<!-- Critical CSS — inline, < 14KB -->
<style>
/* רק מה ש-above the fold צריך */
:root { --primary: #3b82f6; --text: #1a1a1a; }
body { font-family: 'Heebo Fallback', sans-serif; color: var(--text); }
.nav { display: flex; padding: 16px; }
.hero { min-height: 80vh; padding: 64px 16px; }
.hero h1 { font-size: clamp(32px, 6vw, 64px); }
/* ... */
</style>
<!-- Preload של font קריטי -->
<link rel="preload"
href="/fonts/Heebo-Regular.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<!-- שאר ה-CSS — async load -->
<link rel="preload"
href="/css/main.css"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
</head>
ה-rel="preload" + onload טריק הוא הדרך המקובלת לטעון CSS async. הוא טוען את ה-CSS ברקע, ורק כשסיים — מחיל אותו. <noscript> הוא fallback למשתמשים שכיבו JavaScript.
האם שווה את המאמץ ל-Vibe Coder?
תלוי. לאתר קטן-בינוני של Vibe Coder (landing page, portfolio), בדר"כ ה-CSS הכולל הוא 20-50KB. אם זה כבר נטען מהר, אז critical CSS הוא overkill. התחילו לדאוג ל-critical CSS כש:
- ה-CSS שלכם מעל 80KB gzipped.
- Lighthouse אומר במפורש "Eliminate render-blocking resources" עם חיסכון של 400ms+.
- אתם עושים deploy לפרויקט שלקוח משלם לכם עליו — זה מוסיף polish.
| מצב האתר | Critical CSS? | אלטרנטיבה |
|---|---|---|
| CSS total < 30KB | לא שווה | Tailwind JIT / purged CSS |
| CSS 30-80KB | אולי — אם Lighthouse אומר | Async load של main CSS |
| CSS 80KB+ | כן, עקרונית | Critical CSS + dynamic imports |
| Next.js / Astro / Gatsby | מובנה | הפרויקטים האלה מחלצים critical CSS אוטומטית |
| HTML סטטי + CSS file | רק אם הצטיין | ידני או כלי — 30-60 דקות חד-פעמית |
11.14 Render-Blocking Resources — fonts, CSS, JS שחוסמים
Render-blocking = משאב שהדפדפן חייב לטעון ולעבד לפני שהוא יכול להציג את הדף. ברירת המחדל של HTML: CSS ו-JS סינכרוני חוסמים. זה הסיבה #1 ל-LCP גבוה אחרי תמונות.
מה חוסם render — הרשימה המלאה
<link rel="stylesheet">ב-<head>— חוסם עד שהקובץ נטען ונפרס.<script src="...">(בליasync/defer) — חוסם את ה-parser עד שהקובץ נטען ורץ.<link rel="stylesheet">עם@importפנימי — ה-@import יוצר chain של render blocking.- פונטים עם
font-display: block(ברירת המחדל) — חוסם טקסט עד שהפונט נטען. document.write()ב-script — חוסם לגמרי, מיושן, לא להשתמש.
איך משחררים — 5 טכניקות
- JavaScript עם
defer.<script src="app.js" defer>— הסקריפט נטען בלי לחסום parsing, רץ אחרי שה-HTML סיים. שמור על סדר ביצוע בין scripts. - JavaScript עם
async.<script src="analytics.js" async>— סקריפט נטען ורץ ברקע, לא חוסם, אין ערובה לסדר. מושלם ל-analytics. - CSS עם preload + onload (ראו section 11.13).
- פונטים עם
font-display: swap(ראו section 11.15). - העברת scripts לסוף ה-body. אם אי אפשר defer/async, לפחות שהם יריצו אחרי הרבה HTML.
Preconnect ו-Preload — שני ההשלמות
preconnect: אומר לדפדפן "פתח חיבור לדומיין הזה עכשיו, גם אם אני עוד לא מבקש ממנו כלום". חוסך 100-300ms. שימושי ל-Google Fonts, CDN, analytics.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://cdn.example.com">
preload: אומר לדפדפן "תוריד את המשאב הזה בעדיפות גבוהה, אני אשתמש בו בקרוב". שימושי ל-hero image, font קריטי, critical CSS file (אם לא inline).
<link rel="preload" as="image" href="hero.avif" fetchpriority="high">
<link rel="preload" as="font" href="/fonts/Heebo.woff2" type="font/woff2" crossorigin>
ב-Lighthouse → Performance → "Eliminate render-blocking resources" (אם קיים). רשמו:
- כמה resources סומנו: ____
- חיסכון משוער (ms): ____
- איזה סוגים: CSS / JS / font / אחר: ____
לכל אחד, הוסיפו את ה-attribute המתאים (defer/async/preload). זה עבודה של 10-20 דקות שחוסכת 300-800ms.
11.15 Font Loading — font-display: swap ופונטים עבריים
פונטים עבריים הם מקור LCP גרוע #2 בישראל אחרי תמונות. הסיבה: glyphs עבריים כבדים יותר (כל מילה דורשת ligatures, combining marks לניקוד, Unicode ranges רחבים). קובץ WOFF2 של Heebo Regular + Bold = ~120KB. עם 4 משקלים = 480KB. על 4G איטי = 3-5 שניות לטעינה.
font-display: swap — חובה, לא רשות
ברירת המחדל של Google Fonts (עד 2020) הייתה font-display: block — הטקסט מוסתר עד שהפונט נטען (FOIT = Flash of Invisible Text). זה רוצח LCP. הפתרון: font-display: swap — הטקסט מופיע מיד עם fallback (Arial / system-ui), ואז מתחלף כשהפונט נטען (FOUT = Flash of Unstyled Text).
מאז 2022, Google Fonts מציעים &display=swap ב-URL:
<!-- חובה — &display=swap בסוף -->
<link
href="https://fonts.googleapis.com/css2?family=Heebo:wght@400;600;800&display=swap"
rel="stylesheet"
/>
ב-self-hosted fonts, השתמשו ב-@font-face:
@font-face {
font-family: 'Heebo';
src: url('/fonts/Heebo-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap; /* חובה! */
}
הטעינה האופטימלית של פונט עברי
- בחרו 2-3 משקלים מקסימום. לא 9. 400 (regular) + 700 (bold) + אופציונלי 500 או 600 למשקל ביניים. כל משקל נוסף = 120KB נוספים.
- Preconnect ל-Google Fonts. 2 השורות שכבר יש לכם ב-head:
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> - Preload את המשקל הקריטי (בדר"כ Regular שבהם נכתב ה-body):
<link rel="preload" as="font" type="font/woff2" href="https://fonts.gstatic.com/s/heebo/...Heebo-Regular.woff2" crossorigin /> - font-display: swap על הכל.
- Metric overrides ב-
@font-faceשל fallback — למניעת CLS בזמן swap (ראו section 11.4).
Variable Fonts — הפתרון של 2026
Variable fonts הם פונטים שיש בהם את כל המשקלים בקובץ אחד. במקום 3 קבצים של 120KB כל אחד = 360KB, יש קובץ אחד של 180KB שמכיל את כל המשקלים. Heebo יש variable font מאז 2023. שימוש:
@font-face {
font-family: 'Heebo VF';
src: url('/fonts/Heebo-VariableFont.woff2') format('woff2-variations');
font-weight: 100 900; /* טווח משקלים זמין */
font-display: swap;
}
body {
font-family: 'Heebo VF', sans-serif;
font-weight: 400; /* או כל מספר בין 100 ל-900 */
}
חיסכון: 50-60% במשקל כולל של פונטים. זו אופטימיזציה משמעותית לאתר עברי.
AI מקבל "use Heebo font" ומוסיף את כל המשקלים: 100, 200, 300, 400, 500, 600, 700, 800, 900. זה 9 × 120KB = 1.08MB של פונטים לפני שהמשתמש ראה תו אחד. המשתמש שלכם על 4G מחכה 8 שניות לפונט. מה לעשות במקום: (א) להחליט בפרומפט מראש על 2-3 משקלים בלבד לפי ה-hierarchy שבניתם בפרק 4 (בד"כ 400 + 700 מספיקים), (ב) לשקול variable font שמחליף את כל המשקלים בקובץ אחד קטן יותר, (ג) לעולם לא לכתוב family=Heebo:wght@300;400;500;600;700;800;900 — זה דגל אדום.
11.16 Skeleton Screens vs Spinners — למה skeleton מנצח
טעינה של משהו (תוכן, תמונה, data מ-API) לוקחת זמן. יש 2 דפוסים לראוות למשתמש ש"משהו קורה": Spinner (גלגל מסתובב) ו-Skeleton Screen (תבנית אפורה בצורת התוכן הסופי). המדע: skeleton מרגיש מהיר פי 2 למרות שה-wall time זהה.
למה skeleton עדיף
- Perceived performance. המוח רואה "משהו דמוי-תוכן" ומניח שהתוכן באמת נטען. עם spinner, המוח רואה "מערכת עסוקה" ומתחיל לספור שניות.
- אין CLS. Skeleton תופס את אותו שטח כמו התוכן — כשהתוכן נטען, אין layout shift. Spinner בדר"כ מתנדנד באמצע המסך ואז נעלם — לפעמים CLS.
- מבנה מוכר. המשתמש כבר רואה את ה-shape של מה שיגיע (card, רשימה, טופס) — יכול להתחיל "לעבד" את הדף עוד לפני שהתוכן האמיתי הגיע.
Skeleton Component — CSS בלבד, ללא JS
<div class="skeleton-card">
<div class="skeleton skeleton-image"></div>
<div class="skeleton skeleton-title"></div>
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text skeleton-text-short"></div>
</div>
.skeleton {
background: linear-gradient(
90deg,
#e5e7eb 0%,
#f3f4f6 50%,
#e5e7eb 100%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 6px;
}
.skeleton-card {
padding: 16px;
border-radius: 12px;
background: #fff;
border: 1px solid #e5e7eb;
}
.skeleton-image {
width: 100%;
aspect-ratio: 16 / 9;
margin-bottom: 16px;
}
.skeleton-title {
height: 24px;
width: 70%;
margin-bottom: 12px;
}
.skeleton-text {
height: 16px;
width: 100%;
margin-bottom: 8px;
}
.skeleton-text-short {
width: 40%;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* Prefers-reduced-motion — כיבוי shimmer */
@media (prefers-reduced-motion: reduce) {
.skeleton {
animation: none;
}
}
התוצאה: skeleton-card שמחליף את התוכן האמיתי עד שהוא נטען. ה-shimmer מסמן למשתמש "פעיל, נטען". ברגע שהתוכן הגיע — JavaScript מסיר את ה-.skeleton-card ומחליף ב-.real-card עם אותן מידות בדיוק.
מתי עדיין spinner
- פעולה מהירה (< 500ms) — skeleton מהבהב ונעלם, מבלבל. Spinner קטן יותר טוב.
- פעולות לא-ויזואליות — "שומר", "שולח" — spinner על כפתור (spinner קטן) עדיף.
- Full-page loads שאין להם מבנה ידוע מראש — פחות שכיח, אבל אפשרי.
11.17 Performance Audit Prompt + Performance Fix Prompt
שני פרומפטים שכל Vibe Coder צריך בכיס. הראשון לאודיט של אתר קיים — מוצא בעיות. השני לתיקון — מיישם אופטימיזציות.
Prompt 1: Performance Audit Prompt
העתיקו את הפרומפט הבא, הדביקו ל-Claude / Cursor / Copilot, והצמידו את קוד ה-HTML + CSS הראשי.
Please audit this website for performance issues that impact
Core Web Vitals (LCP, CLS, INP). Be specific — no generic advice.
Check for and report, in priority order:
1. LCP KILLERS:
- Find the likely LCP element (hero image, h1, or background).
- Is the hero image optimized? Format (JPEG/WebP/AVIF), width attribute?
- Is loading="lazy" on the hero image? (This is a BUG if yes.)
- Is there <link rel="preload" as="image"> for the hero?
- Is fetchpriority="high" on the hero img tag?
- Are fonts using font-display: swap? Or are they blocking?
2. CLS KILLERS:
- Find all <img> tags. Flag any missing width or height attributes.
- Find all <iframe>. Flag any missing aspect-ratio or height.
- Flag dynamic content injected above existing content (ads, banners).
- Are fonts using size-adjust/ascent-override metric fallbacks?
3. CSS PERFORMANCE KILLERS:
- Find backdrop-filter on elements larger than 500x500px.
- Find will-change applied to more than 5 elements.
- Find transitions on width, height, margin, top, left
(should be transform).
- Find transitions on box-shadow (should be opacity of ::after).
- Find animations of background-position on large elements.
4. LAZY LOADING STRATEGY:
- List all <img> with their loading attribute.
- Flag above-the-fold images with loading="lazy" (BUG).
- Flag below-the-fold images WITHOUT loading="lazy" (missing opt).
- Flag all <iframe> without loading="lazy" (always should).
5. RENDER-BLOCKING:
- List all <link rel="stylesheet"> in <head>.
- List all <script src> without async or defer.
- Flag any @import inside CSS files (chain blocking).
- Flag Google Fonts URL without &display=swap.
6. FONT LOADING:
- Count Hebrew font weights loaded. Flag if more than 3.
- Is there preconnect to fonts.googleapis.com and fonts.gstatic.com?
- Is there preload of the critical font weight?
- Is the font-family using a proper fallback chain?
7. MODERN OPTIMIZATIONS OPPORTUNITIES:
- Can content-visibility: auto be applied to sections below fold?
- Can contain: paint be applied to isolated widgets (cards, modals)?
- Are skeleton screens used instead of spinners?
Output: Prioritized list (Critical / High / Medium) with:
- Specific line numbers
- Exact current code
- Exact recommended code
- Estimated performance impact (LCP -X ms, CLS -X, INP -X ms)
Be concrete. Don't say "optimize images" — say
"Convert hero.jpg (380KB) to hero.avif (~80KB), estimated
LCP improvement of 800ms on Slow 4G."
Prompt 2: Performance Fix Prompt
אחרי ה-audit, הפרומפט הזה מבקש מ-AI ליישם את התיקונים. הדביקו את הקוד + ה-audit הקודם.
Based on the performance audit above, implement the fixes
with the following non-negotiable specs:
=== HERO IMAGE (LCP) ===
- Convert to <picture> with AVIF, WebP, JPEG fallback (3 sources).
- Add width and height attributes (aspect ratio preserved).
- Set loading="eager" fetchpriority="high" decoding="sync".
- Add <link rel="preload" as="image"> in <head> with imagesrcset.
- NO loading="lazy" on hero. Ever.
=== BELOW-THE-FOLD IMAGES ===
- Add loading="lazy" decoding="async" to every <img> below the fold.
- Add loading="lazy" to every <iframe> (YouTube, Maps, embeds).
- Ensure width and height attributes on every <img>.
=== FONTS (LCP + CLS) ===
- Load Hebrew font (Heebo) with max 2-3 weights (400, 700, optional 600).
- Use font-display: swap always.
- Add preconnect to fonts.googleapis.com and fonts.gstatic.com.
- Add preload of the Regular weight woff2 file.
- Add <@font-face> metric-adjusted fallback to prevent CLS on swap.
=== CSS PERFORMANCE ===
- Replace any transition: width/height/margin with transform.
- Replace transition: box-shadow with ::after + opacity pattern.
- Remove will-change from all elements except those with active animations.
- If backdrop-filter is on a large element, either scope it to a smaller
child or replace with pre-baked blurred background image.
=== MODERN CSS OPTIMIZATIONS ===
- Add content-visibility: auto + contain-intrinsic-size: 0 Xpx to
every section below the hero (estimate X from current heights).
- Add contain: paint to isolated widgets (cards, modals, sidebars).
- Replace spinners with skeleton screens for content that loads > 500ms.
=== RENDER-BLOCKING ===
- Add async or defer to all non-critical scripts.
- Add preconnect to external domains loaded in critical path.
- If CSS bundle > 80KB, implement critical CSS inline + async main CSS.
=== VERIFICATION ===
After implementing:
1. Provide updated HTML and CSS.
2. Explain each change and its CWV impact.
3. Flag any trade-offs (e.g., "will-change removed from .card
may cause 1-frame lag on first hover, acceptable trade-off").
העתיקו את Performance Audit Prompt למעלה. פתחו את האתר הנוכחי שלכם. הדביקו את ה-HTML + CSS לתוך Claude/Cursor עם הפרומפט. קבלו את רשימת הבעיות. רשמו את 3 הבעיות הגדולות ביותר שהוא זיהה:
- ____
- ____
- ____
אלה ה-priorities שלכם לתיקון בתרגיל 4.
11.18 תרגילים מעשיים
- פתחו Chrome, Incognito mode. נווטו לאתר האישי שלכם (אם אין — השתמשו באתר גנרי שבנה AI בקורס הקודם).
- F12 → Lighthouse. בחרו: Mobile + Performance only + Navigation. הריצו.
- כשסיים — שמרו screenshot של ה-scores. הריצו שוב 2 פעמים נוספות. רשמו את 3 ה-scores ב-spreadsheet.
- לקחו את המדיאן (הציון האמצעי). זה ה-baseline שלכם. רשמו: Performance Score Baseline: ____ / 100.
- לכו ל-section "Metrics" בתוך Lighthouse. רשמו את 5 המדדים: FCP: __s / LCP: __s / TBT: __ms / CLS: __ / Speed Index: __s.
- לכל אחד מהם, סמנו אם הוא Good (ירוק) / Needs Improvement (כתום) / Poor (אדום) לפי ה-color coding של Lighthouse.
- לכו ל-"Opportunities". רשמו את 3 ההזדמנויות הגדולות לפי "Estimated savings". לכל אחת: מה המשמעות שלה, וכמה היא חוסכת.
- לכו ל-"Diagnostics". רשמו את 3 האזהרות הגדולות ביותר.
- הריצו את אותם 3 ההרצות על עמוד שני באתר (לדוגמה: עמוד about או contact). רשמו את ההבדל.
מה צריך להיות בסוף: spreadsheet עם 2 עמודים × 3 הרצות × 5 מדדים, מדיאן מחושב לכל אחד, רשימה של Opportunities ו-Diagnostics — תמונה מלאה של מצב ה-performance של האתר. זה ה-baseline שמולו תשוו בתרגיל 4.
- מהתרגיל הקודם, רשמתם מה ה-LCP element שלכם. אם זה hero image — נתחיל שם.
- פתחו את התמונה המקורית. רשמו את ה-format (JPEG/PNG) וה-size (KB).
- לכו ל-Squoosh.app. ייצאו את התמונה ב-3 פורמטים × 3 רזולוציות (400w, 800w, 1200w) = 9 קבצים. השוו משקלים: JPEG 1200w: __KB / WebP 1200w: __KB / AVIF 1200w: __KB.
- העלו את 9 הקבצים ל-public folder / CDN.
- החליפו את ה-
<img>של ה-hero ב-<picture>מלא עם 3<source>tags +<img>fallback. ודאוwidth,height,loading="eager",fetchpriority="high". - הוסיפו ב-
<head>:<link rel="preload" as="image" href="hero-1200.avif" type="image/avif" imagesrcset="..." imagesizes="..." fetchpriority="high" />. - בדקו את ה-Google Fonts URL. ודאו ש-
&display=swapבסוף. ודאו שאין יותר מ-3 משקלים טעונים. אם יש — הסירו. - הוסיפו
<link rel="preload" as="font" type="font/woff2" href="..." crossorigin />של המשקל הקריטי (בדר"כ Regular). - הריצו Lighthouse 3 פעמים. מדיאן חדש: Performance Score: ____ / 100. LCP: ____ (צריך לרדת ב-500ms-1.5s).
מה צריך להיות בסוף: <picture> component מוכן, 9 קבצי תמונה ב-CDN, preload של image ו-font, ו-before/after של LCP עם שיפור של 500ms+.
- פתחו את קובץ ה-CSS הראשי. חפשו את כל ה-pattern-ים הבאים:
will-change— רשמו כל מופע. לרוב — הסירו, אלא אם יש סיבה ברורה.backdrop-filter— בדקו גודל האלמנט. מעל 500×500px? תחליפו ב-pre-baked background.transition:עםwidth,height,margin,top,left— המירו ל-transform.transition: box-shadow— המירו ל-::afterעםopacity.- Google Fonts URL בלי
&display=swap— הוסיפו.
- לכל תיקון, רשמו את ה-selector ואת השינוי. דוגמה:
.card — הסר will-change: transform;.button:hover — transition: margin-top → transform: translateY. - אחרי התיקונים, רענו את האתר. ודאו שהאנימציות עדיין עובדות ויזואלית (לפעמים
transformו-marginלא זהים מבחינת מיקום סופי — כיוונו). - הריצו Lighthouse 3 פעמים. התמקדו ב-TBT (Total Blocking Time). מדיאן חדש: ____ ms.
- פתחו את האתר ב-mobile אמיתי. בדקו 3 hover/tap interactions. האם הן חלקות? האם אין jank?
- הוסיפו
content-visibility: auto+contain-intrinsic-size: 0 600pxעל 2 sections שנמצאים מתחת ל-fold. הריצו שוב.
מה צריך להיות בסוף: רשימת 5-10 תיקונים עם before/after של קוד, TBT improvement של 50-150ms, והתחושה הסובייקטיבית במובייל שהאתר "חלק יותר".
- העתיקו את Performance Audit Prompt מ-section 11.17.
- פתחו את הקוד שלכם אחרי תרגילים 2-3 (יש לכם כבר שיפורים — זה הבסיס).
- הדביקו ל-Claude / Cursor. קבלו את רשימת הבעיות שעדיין קיימות.
- העתיקו את Performance Fix Prompt. בקשו מ-AI ליישם את התיקונים.
- עברו על כל תיקון. ודאו שה-AI לא שבר משהו (בעיקר לבדוק: האם ה-UI עדיין נראה זהה? האם אין regressions?).
- ב-cases שהאתר נראה אחרת — החזירו חלק מהתיקונים. עדיפות: אל תיצרו אופטימיזציה על חשבון העיצוב.
- הריצו Lighthouse סופי. 3 פעמים. מדיאן. השוו למדיאן של תרגיל 1:
| מדד | Baseline (תרגיל 1) | אחרי (תרגיל 4) | שיפור |
|---|---|---|---|
| Performance Score | ____ | ____ | ____ |
| LCP | ____ s | ____ s | ____ s |
| CLS | ____ | ____ | ____ |
| TBT | ____ ms | ____ ms | ____ ms |
| Speed Index | ____ s | ____ s | ____ s |
מה צריך להיות בסוף: טבלת before/after מלאה, screenshot של ה-Lighthouse הסופי, ותחושה שהאתר שלכם עכשיו נטען מהר אצל משתמש אמיתי ב-4G. אם הגעתם ל-Performance 90+ במובייל — אתם בקבוצה של ה-5% האתרים המובילים בישראל.
| תדירות | מה לעשות | כמה זמן |
|---|---|---|
| יומי | בסוף כל session של פיתוח — הריצו Lighthouse פעם אחת במובייל על העמוד שעבדתם עליו. רק בדיקה מהירה: Performance Score לא ירד? LCP עדיין מתחת ל-2.5s? אם כן — המשיכו. אם לא — טפלו לפני שתמשיכו לעמוד הבא. | 3-5 דקות |
| שבועי | הריצו את Performance Audit Prompt (section 11.17) על הפרויקט הפעיל. תקנו את 3 ה-Critical issues הראשונים. בנוסף — בדקו ב-Search Console את ה-Core Web Vitals של השבוע האחרון: יש URLs חדשים שהפכו ל-"Poor"? אם כן — חקרו למה. | 30-40 דקות |
| חודשי | הריצו Lighthouse על 3-5 עמודים עיקריים (homepage, 2 landing pages פופולריים, דף contact). רשמו ב-spreadsheet. השוו לחודש שעבר. אם LCP עלה — כנראה תמונה חדשה לא אופטמה. אם CLS עלה — כנראה חסר width/height על משהו. בנוסף: בדקו ב-PageSpeed Insights את ה-Field Data ב-CrUX. | 60-90 דקות |
תקנו את ה-LCP של ה-hero של העמוד הראשי. זה הדבר היחיד שיעשה את ההבדל הגדול ביותר בחוויה של המשתמשים שלכם: (1) המירו את תמונת ה-hero ל-AVIF + WebP ב-Squoosh, (2) הוסיפו width, height, loading="eager", fetchpriority="high", (3) הוסיפו <link rel="preload" as="image"> ב-<head>, (4) ודאו ש-Google Fonts URL מסתיים ב-&display=swap ויש לכם preconnect. 4 שינויים שלוקחים 25 דקות, מורידים LCP ב-800-1500ms, מעלים את ה-Performance Score ב-15-30 נקודות, ומוציאים אתכם מ-"Needs Improvement" ל-"Good" ב-Core Web Vitals. זה הטיפול הכי חסכוני-בזמן וחזק-בתוצאה בקורס כולו. אם אתם עושים רק את זה — הרווחתם.
- מה ההבדל בין Field Data ל-Lab Data ב-PageSpeed Insights, ולמה שניהם חשובים? תנו דוגמה למצב שבו הם סותרים. (רמז: CrUX של משתמשים אמיתיים מול Lighthouse סינתטי; Field טוב + Lab גרוע = lab מחמיר; Field גרוע + Lab טוב = בעיית שרת או רשת)
- למה אסור
will-change: transformעל כל אלמנט באתר? מה קורה כשמשתמשים בו נכון? (רמז: GPU memory exhaustion, 50 layers = אתר מאט, שימוש נכון = רק כשבאמת האלמנט עומד להשתנות, לזמן קצר,:hoverכ-trigger) - למה אסור
loading="lazy"על תמונת hero, ומה כן לעשות? תנו 3 אלמנטים שצריך להוסיף ל-hero image. (רמז: לא lazy כי זה ה-LCP element;loading="eager"+fetchpriority="high"+<link rel="preload">ב-head) - למה פונטים עבריים הם סיבה נפוצה ל-LCP גרוע בישראל, ואיך פותרים את זה בלי להיפרד מהפונט? (רמז: 9 משקלים × 120KB = 1MB; פתרונות:
font-display: swap, 2-3 משקלים בלבד, preload של Regular, variable font, metric-adjusted fallback) - מה ההבדל בין
content-visibility: autoל-contain: paint, ומתי משתמשים בכל אחד? האם אפשר לשלב אותם? (רמז: content-visibility = דילוג על render מחוץ ל-viewport, מתאים ל-sections גדולים; contain: paint = הגבלת paint לאזור, מתאים ל-widgets מבודדים; כן, אפשר לשלב על אותו section)
בפרק הזה עברתם מ-"האתר שלי נראה טוב" ל-"האתר שלי נראה טוב ונטען תוך 2 שניות גם על 4G של פרטנר". הבנתם שהמציאות של הגולש הישראלי הממוצע היא לא fiber של Mac Studio — זה Samsung A52 ב-4G של 5-15 Mbps, עם latency של 60-110ms. על המציאות הזו, אתר לא-מאופטם נטען תוך 4-5 שניות, ו-53% מהמשתמשים נוטשים. אתר מאופטם נטען תוך 1.5-2 שניות, והמשתמש נשאר.
למדתם את שלושת המדדים של Core Web Vitals — LCP (יעד < 2.5 שניות, מודד מתי האלמנט הגדול מופיע), CLS (יעד < 0.1, מודד עד כמה הדף "קופץ"), ו-INP (יעד < 200ms, מודד כמה מהר האתר מגיב לקליק). הבנתם את כלל ה-75th percentile של Google — לא מספיק שה-50% הטובים רואים חוויה טובה; גם ה-25% עם ה-conditions הכי גרועים חייבים.
תרגלתם Lighthouse ב-Mobile mode עם הריצה נכונה: Incognito, 3 הרצות, מדיאן. הכרתם את PageSpeed Insights וההבדל בין Field Data (מציאות מ-CrUX) ל-Lab Data (Lighthouse סינתטי). הבנתם את חמשת המדדים שמרכיבים את ה-Performance score, ושם TBT + LCP מהווים 55% מהציון.
זיהיתם את 8 רוצחי ה-Performance ב-CSS: backdrop-filter על רקעים גדולים, will-change על כל אלמנט (הטעות הנפוצה ביותר של AI), box-shadow מרובה שכבות מונפש, אנימציות של width/height/margin במקום transform, filter: blur בזמן scroll, gradients מונפשים על background-position, hover על elements גדולים, ופונטים בלי font-display: swap. למדתם את ה-rule הפשוט: אנימציות רק עם transform ו-opacity (השאר מפעילים reflow).
בניתם lazy loading strategy מעשית — eager + fetchpriority="high" על hero, lazy + decoding="async" על הכל מתחת ל-fold, תמיד lazy על iframes. הכרתם את content-visibility: auto + contain-intrinsic-size — 2 שורות CSS שחוסכות שנייה מ-TTI בדפים ארוכים. הוספתם contain: paint לווידג'טים מבודדים. הבנתם את will-change לעומק: הוא עוצמתי, אבל לשימוש ממוקד בלבד, לא כ-blanket optimization.
למדתם על Critical CSS — ה-14KB הראשונים שיכולים להיכנס ב-round trip אחד של TCP, וה-pattern של rel="preload" + onload לטעינת CSS async. הבנתם render-blocking resources ואיך לשחרר אותם: defer ו-async על scripts, preconnect לדומיינים חיצוניים, preload למשאבים קריטיים. טיפלתם בפונטים עבריים — מקור LCP גרוע #2 בישראל: מקסימום 2-3 משקלים, font-display: swap, preload של Regular, size-adjust ב-fallback, ואופציה של variable fonts לחיסכון של 50-60% במשקל.
החליפו spinners ב-skeleton screens — דפוס שמרגיש מהיר פי 2 למרות שה-wall time זהה, עם CSS בלבד (shimmer animation על linear-gradient), כולל respect ל-prefers-reduced-motion. קיבלתם שני פרומפטים מוכנים — Performance Audit Prompt שמוצא בעיות ספציפיות (לא "make it faster"), ו-Performance Fix Prompt שמיישם תיקונים עם specs ברורים. עברתם תרגיל מקיף של Before/After עם טבלה של 5 מדדים לפני ואחרי.
יש לכם עכשיו 8 deliverables מוחשיים: (1) Lighthouse Report עם ניתוח, (2) Core Web Vitals Cheat Sheet, (3) רשימת 10 אופטימיזציות ל-AI, (4) Critical CSS Pattern, (5) Font Loading Strategy לעברית, (6) Skeleton Screen Component, (7) Performance Audit + Fix Prompts, ו-(8) מילון 16 מונחים. יחד עם Responsive Design מפרק 10, Glassmorphism מפרק 9, Modern CSS מפרק 6, Typography מפרק 4, ופלטת צבעים מפרק 3 — יש לכם את כל ה-toolkit של מפתח Web מקצועי ב-2026: אתר שנראה כמו סטודיו, מתנהג כמו אפליקציה, ונטען מהר כמו אתר פרסום של חברת תשתית.
הגשר לפרק הבא: בפרק 11 השלמתם את ה-foundations של אתר מקצועי — עיצוב + responsive + מהירות. בפרק 12 — "כלי עיצוב (כוחות-על אופציונליים): Figma, Google Stitch ו-MCP" — תכירו כלי עיצוב מקצועיים שיכולים להאיץ את ה-workflow שלכם אבל הם אופציונליים. תבחנו את Figma (הסטנדרט של מעצבי UI בישראל) — איך לבצע inspect כדי לחלץ spacing, colors ו-fonts, איך למדוד מרחקים עם Option-hover, ואיך לייצא SVGs ואייקונים. תכירו את Google Stitch (text-to-UI) — כלי חדש שממיר תיאור טקסט לעיצוב מלא, עם היתרונות והמגבלות שלו. תלמדו על MCP (Model Context Protocol) — הפרוטוקול של Anthropic שמחבר כלי AI (Cursor, Claude Desktop) ישירות ל-Figma ול-Stitch. המסר המרכזי של הפרק: הידע שבניתם בפרקים 1-11, כולל פרק ה-Performance הזה, הוא מה שקובע את האיכות. Vibe Coder שמבין Performance, Responsive ו-Typography יכול לבנות אתר מקצועי גם בלי לפתוח Figma אף פעם — פשוט בתיאור טקסטואלי עשיר ל-AI. הכלים הם אצל מי שיודע; למי שלא יודע, הכלים לא מצילים. פרק 12 הוא power-up אופציונלי, פרק 11 היה חובה. ופרק 13 (ה-capstone) יחבר את הכל לעבודה אמיתית.
- הרצתם Lighthouse במובייל 3 פעמים ולקחתם את המדיאן (לא רק הרצה אחת)
- LCP מתחת ל-2.5 שניות במובייל (Good range)
- CLS מתחת ל-0.1 — כל תמונה עם width+height, כל iframe עם aspect-ratio
- INP/TBT מתחת ל-200ms — כל האנימציות עם
transformו-opacityבלבד - תמונת ה-hero היא AVIF או WebP, עם
<picture>fallback chain - Hero image יש לה
loading="eager"ו-fetchpriority="high"(לא lazy!) - יש
<link rel="preload" as="image">של ה-hero ב-<head> - Google Fonts URL מסתיים ב-
&display=swapוישpreconnectל-gstatic - לא יותר מ-3 משקלים של פונט עברי נטענים (400, 700, אופציונלי 600)
- אין
will-changeעל יותר מ-5 אלמנטים (ורק כשבאמת צריך) - אין
backdrop-filterעל אלמנטים גדולים מ-500×500px - כל תמונה מתחת ל-fold יש לה
loading="lazy" decoding="async" - כל
<iframe>(YouTube, Maps) יש לוloading="lazy" - Sections מתחת ל-fold משתמשים ב-
content-visibility: auto+contain-intrinsic-size - נבדקתם ב-PageSpeed Insights (Field Data + Lab Data) על מובייל, והציון הכולל מעל 75