הרכיב <progress> הוא הדרך הסמנטית לייצג את התקדמות ההשלמה של משימה, כמו הורדה או העלאה של מידע או השלמת חלק מתהליך רב-שלבי. שימוש ברכיב המקורי עוזר לנגישות, כי לקוראי מסך יש role="progressbar" משתמע והם יכולים להקריא ערכים.
במדריך הזה מוסבר איך להטמיע סרגל התקדמות אופקי עם עיצוב מלא והתאמות אישיות של הסגנון.
סרגל התקדמות או מעגל התקדמות?
- אם המקום מוגבל או אם עדיף יחס גובה-רוחב ריבועי, כדאי להשתמש בסרגל התקדמות מעגלי (מעגל התקדמות): מעגל התקדמות
- ברוב התרחישים של התקדמות לא מוגדרת, עדיף להשתמש בסימנים גרפיים (סימן גרפי של טעינה). השתמשו בסרגלי התקדמות לא מוגדרים כשהמצב הלא מוגדר הוא זמני ויוחלף בקרוב בסרגל התקדמות מוגדר (למשל, המתנה למטא-נתונים של העלאה לפני שאפשר יהיה להציג את אחוז ההתקדמות)
Markup
- להשתמש ברכיב
<progress>מקורי: הוא מספק נגישות מובנית והתנהגות עקבית בפלטפורמה. - אם אתם צריכים סולם שונה מסולם ברירת המחדל של 0-1, השתמשו ב-
max. - כדי להגדיר ערך התקדמות ספציפי, מגדירים מאפיין
value. אפשר להשמיט אתvalueבמצב לא מוגדר (למשל, לפני שמתחיל משוב קונקרטי יותר). - כדי לשייך את רכיב ההתקדמות לתווית, משתמשים ב-
<label for="...">, ב-aria-labelledbyאו ב-aria-label.
איזה סוג של התאמה אישית נדרש?
כדי להגדיר עיצוב מוגבל, המאפיינים האלה מספיקים:
accent-colorכדי לשנות את הצבע של סרגל ההתקדמות-
widthאוinline-sizeכדי לשנות את הרוחב של סרגל ההתקדמות -
height/block-sizeלא חל באופן עקבי – צריך לבדוק קודם writing-mode: vertical-lrלעמודות אנכיות.- אפקטים שמוחלים אחרי הציור:
opacity,filter,clip-path, מסכות, טרנספורמציות,box-shadowוכו'.
אם עיצוב מוגבל מספיק, אפשר לדלג על הקטע הבא.
אזהרה: מאפיינים מסוימים (למשל border-radius, background, border) ישביתו את העיצוב של סרגל ההתקדמות שמוגדר כברירת מחדל בלי להציג הודעה. אם אתם רוצים להוסיף עיצוב מעבר למאפיינים שלמעלה, אתם צריכים להטמיע עיצוב בהתאמה אישית מלאה, כמו שמתואר בקטע הבא. אל תנסו להוסיף עיצוב נרחב יותר "רק למקרה שזה יעבוד".
עיצוב בהתאמה אישית מלאה
1. הגדרה בסיסית
- חובה: צריך להשתמש ב-
appearance: noneכדי להפעיל סגנון אישי. - איפוס הגבולות של UA עם
border: 0 solid - כדי לחתוך את הסרגל הפעיל לפי רדיוס הגבול של הרכיב, צריך להשתמש ב-
overflow: clipאו להחיל את אותוborder-radiusעל הסרגל. אל תשתמשו ב-border-radius: inheritבסרגל, כי הוא תלוי במבנה הספציפי של הרכיבים ב-shadow DOM.
progress {
/* Reset default browser styles */
appearance: none;
border: 0 solid;
/* Clip bar to element’s border-radius */
overflow: clip;
}
2. עיצוב
- מעצבים את הרצועה ברכיב
progressעצמו. - משתמשים ברכיב המדומה (pseudo-element) המתאים שמטרגט את הדפדפן כדי לטרגט את סרגל ההתקדמות עצמו:
::-webkit-progress-valueל-WebKit/Blink ו-::-moz-progress-barל-Firefox. - חובה: אל תקבוצו את הרכיבים המדומים
-webkit-ו--moz-באותו כלל. הכלל ייחשב כלא תקין והמערכת תתעלם ממנו.:is()ו-:where()לא עוזרים כאן, כי הם לא תומכים ברכיבי פסאודו. - כל רכיב מדומה שמטרגט דפדפן צריך להופיע פעם אחת בדיוק. התאמות אישיות ספציפיות למצב (כמו גודל הקטע הלא מוגדר והאנימציה) צריכות לעבור דרך מאפיינים מותאמים אישית שמוגדרים ברכיב
progressעצמו. - אופציונלי: מעבר
inline-sizeבמילוי כדי שהשינויים בערך המוגדר יונפשו במקום לקפוץ. ב-Firefox, המילוי מוגדר לפי גודל הפריסה והמערכת מתעלמת ממנו, וזה לא מזיק.
progress {
--progress-bar-radius: 1e5px;
border-radius: var(--progress-bar-radius);
/* Apply color for custom progress track (background) */
background: var(--progress-bar-track, var(--color-neutral-90));
/* Subtle depth on the empty part of the track */
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
}
/* Let <progress> styling show through */
progress::-webkit-progress-bar {
background: transparent;
}
/* Webkit, Chrome */
progress::-webkit-progress-value {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
/* Firefox */
progress::-moz-progress-bar {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
3. עיצוב של מצב לא מוגדר
הוספת אנימציה מותאמת אישית למצב הלא מוגדר: הופכים את הרכיב המדומה של המילוי למקטע קצר ומחליקים אותו לאורך המסלול.
- צריך לעצב את המילוי עצמו, ולא ליצור אותו מחדש כרקע ב-
progress. - המילוי הלא מוגדר קיים רק דרך האנימציה שלו: הפריימים המרכזיים מגדירים את האורך שלו באמצעות
inline-sizeאמיתי (זה עדיף עלinline-sizeבתוך השורה של סוכן המשתמש של Chromium) ומזיזים אותו באמצעותtranslate. אל תשתמשו ב-scaleלאורך, כי זה מעוות את התבנית שמצוירת על המילוי. - אחוזי
translateנפתרים ביחס לרוחב של המילוי עצמו, לכן צריך לבטא מיקומים ביחידות של טראק במקום זאת: הופכים אתprogressלמאגר בגודל מוטבע ומשתמשים ב-cqiבפריימים המרכזיים. צריך לכלול אתmargin-right: autoב-from, toכדי ש-Chromium יציג את המילוי בצד שמאל הפיזי גם ב-RTL. - כדי להזיז את המילוי, משתמשים בטרנספורמציות ולא בשוליים.
- הטרנספורמציות שומרות את האנימציה ב-compositor (אלא אם גם
inline-sizeמונפש) - השוליים לא מוצגים כמו שצריך ב-RTL, משתי סיבות נפרדות:
- דפדפן Firefox ממקם את המילוי הלא מוגדר באמצעות השוליים הפיזיים השמאליים בלבד, כך של-
margin-inline-startאין השפעה על כתיבה מימין לשמאל והמילוי אף פעם לא זז. - ב-Chromium וב-WebKit, שבהם הפריסה של המילוי היא כבלוק רגיל, ברגע שהשוליים דוחפים את המילוי מעבר לסוף המסלול, השוליים מצטברים ליותר מהמסלול. ב-CSS רגיל, הבעיה נפתרת על ידי התעלמות מ-
margin-leftב-RTL, כך שהקטע קופץ לקצה במקום להחליק ממנו. - המאפיין
translateמוחל אחרי הפריסה, ולכן שתי הבעיות לא רלוונטיות.
- הטרנספורמציות שומרות את האנימציה ב-compositor (אלא אם גם
- כדי לשקף את התנועה ב-RTL (כמו בסרגל המקורי של Chrome), צריך להפוך את האנימציה בקטע
:dir(rtl):
progress:dir(rtl) {
--progress-bar-indeterminate-animation: progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear reverse;
}
- מגדירים את המאפיינים הציבוריים של
--progress-bar-indeterminate-*ב-progress(השם שלהם כבר מגדיר את ההיקף שלהם למצב) כדי שהצרכנים יוכלו לשנות אותם בלי לדעת על:indeterminate. - כדי לשנות את אורך הקטע (למשל, הקצה המוביל נע קדימה והקצה הנגרר מדביק את הפער), מגדירים את
--progress-bar-indeterminate-animationלשתי אנימציות בו-זמניות: אחת שבה הקיפריימים מנפישים אתtranslateב-cqi(מיקום) ואחת שבה הקיפריימים מנפישים אתinline-size(אורך), כך שכל אחת מקבלת קיפריימים ופונקציית easing משלה. אל תנסו לעצב את שני הקצוות ברשימת פריים-מפתח אחת.animation-timing-functionלכל פריים-מפתח חל על כל מאפיין בפריים-המפתח הזה. - הערך
--progress-bar-animationחל בשני המצבים, ואפשר להשתמש בו לאפקטים כמו נצנוץ מוגדר. המאפייןrevert-ruleמשמש לשינוי רק כשהוא מוגדר, כדי למקסם את יכולת ההרכבה. - אף פעם אל תשביתו את האנימציה הלא מוגדרת (
animation: noneמשאיר מילוי ברוחב אפס ב-Chromium). כדי להפחית את התנועה, אפשר להאט אותה.
progress {
/* Lets the fill position itself in track units (cqi) */
container-type: inline-size;
/* Segment length relative to the track */
--progress-bar-indeterminate-size: 30%;
--progress-bar-indeterminate-animation-duration: 1.5s;
/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
--progress-bar-indeterminate-animation-duration: 10s;
}
}
progress:indeterminate {
--progress-bar-animation: var(
--progress-bar-indeterminate-animation,
progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear
);
}
/* Add to the existing pseudo-element rules */
progress::-webkit-progress-value {
animation: var(--progress-bar-animation, revert-rule);
}
progress::-moz-progress-bar {
animation: var(--progress-bar-animation, revert-rule);
}
/* Physical: left to right regardless of direction (reverse under :dir(rtl) to mirror). */
@keyframes progress-bar-indeterminate {
from, to {
inline-size: var(--progress-bar-indeterminate-size);
/* Pin to the physical left; Chromium would otherwise lay the fill out at the inline start */
margin-right: auto;
}
from { translate: -100%; } /* Own width: fully outside the left edge */
to { translate: 100cqi; } /* Track width: fully outside the right edge */
}
שיקולים נוספים בנושא נגישות
בנוסף להנחיות שצוינו למעלה:
- הכרזה על השלמה בלי להעביר את המיקוד: אל תגדירו את
tabindexואל תפעילו את.focus()ב-<progress>, כי הוא לא אינטראקטיבי והעברת המיקוד אליו מפריעה למשתמשים במקלדת. כדי להודיע כשמשימה ברקע מסתיימת, מעדכנים רכיב סטטוס מנומס (role="status"אוaria-live="polite"). - אל תוסיפו טקסט חלופי בתוך
<progress>: דפדפנים מודרניים מתעלמים מטקסט בתוך<progress>, וטכנולוגיות מסייעות לא משתמשות בו. - הימנעו משימוש ב-
aria-busy+aria-describedbyב-<div>כללי ללא תווית. התמיכה שלaria-busyבקורא מסך לא עקבית, וטכנולוגיות מסייעות מתעלמות מ-aria-describedbyב-<div>ללא שם וללא תפקיד. אם התוכן של אזור מסוים לא מוכן בזמן הטעינה, צריך להסתיר אותו באמצעותhiddenאוaria-hidden="true". - חשוב לוודא שיש ניגודיות מתאימה בין סרגל ההתקדמות לבין הרצועה כשמוסיפים סגנונות בהתאמה אישית.
- שקלו חלופות לייצוג מצב לא מוגדר: אנימציות של סרגל התקדמות לא מוגדר שמוצגות במקביל לתוכן אחר יכולות להיחשב כמסיחות את הדעת עבור חלק מהמשתמשים.
אסטרטגיות חלופיות
תמיכה בדפדפן וחלופות ל-accent-color
המאפיין accent-color הוא שיפור הדרגתי (progressive enhancement).
דפדפנים שלא תומכים במאפיין הזה יתעלמו ממנו וישתמשו בצבעי ברירת המחדל של ממשק המשתמש שלהם.
אם accent-color לא נתמך וצריך לעצב את סרגל ההתקדמות, אפשר להשתמש בשיטת העיצוב בהתאמה אישית כדי להחיל את העיצוב המועדף על סרגל ההתקדמות.
תמיכה בדפדפן וחלופות ל-revert-rule
אם אין תמיכה ב-revert-rule, animation: var(--progress-bar-animation, revert-rule) חוזר ל-animation-name: revert-rule עם משך זמן של 0s כש---progress-bar-animation לא מוגדר, וזו פעולה לא מזיקה כשאין @keyframes revert-rule.