CSS dvh – גובה Viewport דינמי

אם בניתם אי פעם אזור hero במסך מלא בנייד וראיתם את החלק התחתון שלו נעלם מחוץ למסך, אתם כבר מכירים את הבעיה. נתקלתי בזה בעשרות פרויקטים, וזה אחד הבאגים שגורמים לכם לחשוב שיחידות vh פשוט לא נועדו לטלפונים. (אם יחידות CSS כמו vh, vw ו-rem עדיין חדשות לכם, המדריך ל-CSS למתחילים מסביר את כולן.)

היום יש לזה פתרון אמיתי ב-CSS. שלוש יחידות viewport חדשות (svh, lvh ו-dvh) נותנות לכם שליטה מלאה באופן שבו ה-chrome של הדפדפן בנייד משפיע על ה-layout.

Browser chrome הוא הכינוי לשורת הכתובת, לסרגל הכלים, ללשוניות ולשאר רכיבי הממשק שמסביב לתוכן הדף. אין לזה קשר לדפדפן Google Chrome.

הבעיה עם 100vh בנייד

הגדרת אלמנט עם height: 100vh עובדת מצוין בדסקטופ. האלמנט ממלא את חלון הדפדפן ושום דבר לא חורג ממנו.

בנייד זה נשבר.

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

Safari ב-iOS ו-Chrome באנדרואיד בטעינה ואחרי גלילה: סרגלי הכלים מתכווצים והשטח הנראה גדל מ-100svh ל-100lvh

ב-Safari ב-iOS שורת הכתובת נמצאת בתחתית, וב-Chrome באנדרואיד למעלה. בשני המקרים היא מתכווצת כשגוללים.

כשאתם כותבים 100vh, הדפדפן מחשב את הערך הזה לפי ה-viewport הגדול ביותר (כשכל סרגלי הכלים מוסתרים). אבל בטעינה הראשונה סרגלי הכלים מוצגים, כך שהשטח שהמשתמש רואה בפועל קטן יותר.

התוצאה: האלמנט ה"מסך מלא" שלכם גבוה יותר מהשטח שהמשתמש רואה. החלק התחתון של האלמנט לא נראה: ב-Safari ב-iOS הוא מוסתר מתחת לסרגל הכלים, וב-Chrome באנדרואיד הוא יורד מתחת לגבול המסך. כפתור CTA בתחתית ה-hero נדחף אל מחוץ למסך.

.hero {
    height: 100vh; /* Overflows on mobile! */
    display: flex;
    align-items: center;
    justify-content: center;
}

עד עכשיו הפתרון היה האק ב-JavaScript שמשתמש ב-window.innerHeight:

document.documentElement.style.setProperty(
    '--vh', window.innerHeight * 0.01 + 'px'
);
// Then in CSS: height: calc(var(--vh, 1vh) * 100);

זה עבד, אבל זה היה שביר, דרש resize listener ופשוט הרגיש לא נכון. זה משהו ש-CSS אמור לפתור בעצמו.

שלושת הסוגים החדשים של יחידות Viewport

ה-CSS Working Group הגדיר שלוש דרכים חדשות למדוד את ה-viewport, במקום ההתנהגות היחידה של vh. כל אחת מהן מגדירה אחרת מה נחשב "100% מגובה ה-viewport".

יחידה מודדת מתאימה ל-
svh ה-viewport הקטן ביותר (סרגלי הכלים מוצגים) אזורי hero, מסכי פתיחה, תוכן above the fold
lvh ה-viewport הגדול ביותר (סרגלי הכלים מוסתרים) Layouts אימרסיביים, גלריות במסך מלא, app shells
dvh ה-viewport הנוכחי (מתעדכן בזמן אמת) Layouts שמתאימים את עצמם, sticky footers, ווידג'טים של צ'אט

לכל יחידה יש גם גרסאות לרוחב, ל-inline ול-block. גרסאות ה-inline וה-block עובדות לפי אותו היגיון צירים של CSS logical properties:

מימד Small Large Dynamic
Height svh lvh dvh
Width svw lvw dvw
Inline svi lvi dvi
Block svb lvb dvb
Min svmin lvmin dvmin
Max svmax lvmax dvmax

The small viewport-percentage units (sv*) are defined with respect to the small viewport size: the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be expanded.

The large viewport-percentage units (lv*) are defined with respect to the large viewport size: the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be retracted.

– W3C CSS Values and Units Module Level 4

איך dvh (גובה Viewport דינמי) עובד

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

כששורת הכתובת מוצגת, 100dvh שווה לשטח הנראה הקטן יותר. כשהמשתמש גולל ושורת הכתובת מתכווצת, 100dvh גדל וממלא את השטח שהתפנה.

.adaptive-panel {
    height: 100dvh;
    /* Shrinks when address bar appears */
    /* Grows when address bar hides */
}

זה נשמע מושלם, אבל יש כאן trade-off. dvh מפעיל חישוב layout מחדש בכל פעם שסרגל הכלים זז, ולכן הוא עלול לגרום ל-reflow שרואים בעין באלמנטים שתלויים בו.

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

מתי להשתמש ב-dvh

  • Sticky footers או אלמנטים שצמודים לתחתית וצריכים להישאר בתחתית השטח הנראה בפועל
  • ממשקי צ'אט או סרגלי כלים שצריכים תמיד למלא בדיוק את השטח הנראה
  • Overlays של מודאלים שצריכים לשנות גודל יחד עם ה-chrome של הדפדפן

מתי להימנע מ-dvh

  • אזורי hero ומסכי פתיחה. כאן עדיף svh, שנותן תוצאה יציבה בלי חריגה מהמסך
  • אלמנטים עם תוכן כבד או אנימציות, שעלולים לגמגם בזמן reflow
  • כל layout שבו גובה קבוע בטעינה הראשונה חשוב יותר מהתאמה בזמן אמת

דוגמה אינטראקטיבית: vh מול svh מול lvh מול dvh

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

Viewport Unit Comparison
vh
9:41
5G
example.com
overflow
Overflows
svh
9:41
5G
example.com
overflow
Fits
lvh
9:41
5G
example.com
overflow
Overflows
dvh dynamic
9:41
5G
example.com
overflow
Fits

מקרי שימוש מעשיים

בואו נראה איך כל יחידה עובדת ב-layouts אמיתיים.

אזורי hero עם svh

באזורי hero במסך מלא, svh הוא הבחירה הנכונה. הוא מבטיח שהאלמנט ייכנס לשטח הנראה גם כששורת הכתובת מוצגת. זה חשוב במיוחד ב-layouts עם scroll snapping, שבהם כל סקשן אמור למלא בדיוק מסך אחד.

.hero {
    min-height: 100svh;
    display: flex;
    align-items: center;
    justify-content: center;
}

Sticky footer עם dvh

אם אתם צריכים layout שבו ה-footer צמוד לתחתית ה-viewport הנראה, dvh ישאיר אותו במקום גם כשה-chrome של הדפדפן משתנה.

.page-wrapper {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

.main-content {
    flex: 1;
}

.footer {
    /* Always at the bottom of the visible area */
}

Overlay במסך מלא עם lvh

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

.overlay {
    position: fixed;
    inset: 0;
    height: 100lvh;
    background: rgba(0, 0, 0, 0.8);
}

איך להוסיף Fallback

היחידות האלה נתמכות בכל הדפדפנים המודרניים (Chrome 108+, Safari 15.4+, Firefox 101+), אבל דפדפנים ישנים פשוט מתעלמים מהן. לכן תמיד הוסיפו fallback עם vh.

.hero {
    height: 100vh;        /* Fallback for older browsers */
    height: 100svh;       /* Modern browsers use this */
}

ה-cascade של CSS עושה כאן את העבודה. דפדפנים שמכירים את svh דורסים את ההצהרה הראשונה, ואלה שלא נשארים עם ערך ה-vh.

אפשר גם להשתמש ב-@supports ללוגיקת fallback מורכבת יותר:

.hero {
    height: 100vh;
}

@supports (height: 100svh) {
    .hero {
        height: 100svh;
    }
}

טעויות נפוצות

אלה הטעויות שאני רואה שוב ושוב כשמפתחים מתחילים לעבוד עם יחידות ה-viewport החדשות.

שימוש ב-dvh באזורי hero

dvh משנה גודל בזמן הגלילה, ולכן אזור ה-hero "קופץ" כששורת הכתובת מתכווצת. ב-hero השתמשו ב-svh, שנשאר יציב.

להניח ש-dvh מתחשב במקלדת הווירטואלית

אף אחת מיחידות ה-viewport החדשות לא מתחשבת במקלדת שעל המסך. כשמשתמש נוגע בשדה קלט, המקלדת דוחפת תוכן למעלה ו-100dvh לא מתכווץ בהתאם.

ב-layouts עם הרבה שדות קלט תצטרכו קוד JavaScript נוסף, או את הערך interactive-widget בתגית ה-viewport meta (נתמך ב-Chrome וב-Firefox באנדרואיד, Safari ב-iOS מתעלם ממנו):

<meta name="viewport"
    content="width=device-width, initial-scale=1,
    interactive-widget=resizes-content">

לדלג על ה-fallback

התמיכה רחבה, אבל חלק קטן מהתעבורה עדיין מגיע מדפדפנים ישנים שלא תומכים ב-svh/dvh. תמיד הצהירו על height: 100vh לפני היחידה החדשה.

שימוש ב-dvh באנימציות או transitions

מכיוון ש-dvh משנה ערך במהלך הגלילה, אנימציה של גובה אלמנט מ-0 ל-100dvh עלולה לגרום לריצוד לא צפוי. השתמשו ביחידות קבועות או ב-svh/lvh באנימציות.

תמיכת דפדפנים

כל שלושת סוגי היחידות הגיעו לסטטוס Baseline Widely Available ביוני 2025, כלומר הם נתמכים בכל מנועי הדפדפנים הגדולים.

Data on support for the viewport-unit-variants feature across the major browsers from caniuse.com

לפי caniuse, כ-94% מהמשתמשים בעולם גולשים בדפדפנים שתומכים ביחידות האלה. רוב השאר משתמשים בגרסאות ישנות של Chrome ו-UC Browser.

שאלות נפוצות

שאלות נפוצות על גובה viewport דינמי ב-CSS:

מה ההבדל בין vh ל-dvh?
vh שקול ל-lvh בדפדפנים מודרניים. הוא משתמש בגודל ה-viewport הגדול ביותר (כשסרגלי הכלים מוסתרים). dvh משתנה בזמן אמת כשה-chrome של הדפדפן מופיע או נעלם, ותואם בכל רגע לשטח שנראה בפועל.
במה עדיף להשתמש ב-hero במסך מלא, svh או dvh?
השתמשו ב-svh. הוא מייצג את ה-viewport הקטן ביותר (עם שורת הכתובת גלויה), כך שה-hero ייכנס במלואו למסך כבר בטעינה הראשונה. עם dvh ה-hero ישנה גודל כשהמשתמש גולל, וזה עלול להרגיש קופצני.
האם dvh עובד בדפדפני דסקטופ?
כן. בדסקטופ, שבו ה-chrome של הדפדפן לא משנה גודל באופן דינמי, dvh, svh ו-lvh מקבלות את אותו ערך כמו vh. ההבדל רלוונטי רק בנייד, בדפדפנים עם סרגלי כלים שמתכווצים.
האם dvh ו-svh מתחשבים במקלדת וירטואלית?
לא. אף אחת מיחידות ה-viewport החדשות לא מגיבה למקלדת שעל המסך. אם אתם צריכים layout שמתאים את עצמו כשהמקלדת נפתחת, השתמשו בערך interactive-widget=resizes-content בתגית ה-viewport meta (Chrome ו-Firefox באנדרואיד, Safari ב-iOS מתעלם ממנו), או טפלו בזה ב-JavaScript.
אפשר להשתמש ב-svh וב-dvh בתוך calc()?
כן. הם עובדים כמו כל יחידת אורך אחרת בתוך calc(). לדוגמה, height: calc(100svh - 60px) נותן לכם את גובה ה-viewport הקטן פחות header של 60px.
באילו דפדפנים נתמכות dvh, svh ו-lvh?
כולם נתמכים ב-Chrome 108+, Firefox 101+, Safari 15.4+ ו-Edge 108+. הם הגיעו לסטטוס Baseline Widely Available ביוני 2025. והוסיפו תמיד fallback עם vh בשביל האחוז הקטן של המשתמשים בדפדפנים ישנים.
האם dvh פוגע בביצועים?
dvh מפעיל חישובי layout מחדש בכל פעם שסרגל הכלים של הדפדפן משנה גודל. באלמנטים פשוטים ההשפעה זניחה, אבל ב-layouts מורכבים עם הרבה אלמנטים פנימיים זה עלול לגרום לגמגום שרואים בעין. svh ו-lvh הם ערכים סטטיים, בלי שום עלות בביצועים.

סיכום

לבאג ה-100vh בנייד יש סוף סוף פתרון. השתמשו ב-svh לסקשנים יציבים במסך מלא שנכנסים למסך כבר בטעינה הראשונה, ב-lvh ל-layouts אימרסיביים שממלאים את כל השטח האפשרי, וב-dvh כשצריך להגיב בזמן אמת לשינויים בסרגל הכלים. ואל תשכחו fallback עם vh לדפדפנים ישנים.

מאז ש-Chrome 108 יצא אני משתמש ב-svh כברירת מחדל באזורי hero, ובעיית החריגה מהמסך פשוט נעלמה. ברוב ה-layouts, svh היא היחידה שאתם באמת צריכים. dvh שימושי, אבל רק במקרים מסוימים כמו sticky footers ו-page wrappers מבוססי flexbox.

דיון ותגובות
[  0 תגובות  ]

השאירו תגובה

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