תחביר צבע יחסי של CSS

יצירת צבעים חדשים על סמך הערוצים והערכים של צבע אחר.

Adam Argyle
Adam Argyle

גרסה 119 של Chrome כוללת תכונת צבע חזקה מאוד מהגרסה CSS Color Level 5. תחביר צבעים יחסי יוצר נתיב חלק למניפולציית צבעים בתוך CSS, ומציע לכותבים ולמעצבים דרכים לבצע את הפעולות הבאות:

לפני תחביר הצבעים היחסי, כדי לשנות את השקיפות של הצבע צריך ליצור מאפיינים מותאמים אישית לערוצים של צבע, בדרך כלל HSL, ולהרכיב אותם לצבע סופי וצבע וריאציה סופי. כלומר, לנהל הרבה פיסות צבע, שעלולות להפוך במהירות למאמץ.

:root {
  --brand-hue: 300deg;
  --brand-saturation: 75%;
  --brand-lightness: 50%;

  --brand-hsl:
    var(--brand-hue)
    var(--brand-saturation)
    var(--brand-lightness);

  --brand-color: hsl(var(--brand-hsl));

  /* all this work just so I can set the opacity to 50% in a variant */
  --brand-color-variant: hsl(var(--brand-hsl) / 50%);
}

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

:root {
  --brand-color: hsl(300deg 75% 50%);
  --brand-color-variant: hsl(from var(--brand-color) h s l / 50%);
}

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

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

סקירה כללית בנושא תחביר

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

מוצגת תרשים של התחביר RGB(מ-R g b / alpha), עם חץ שמשאיר את החלק העליון בצבע ירוק וקשת לתוך תחילת הפונקציה RGB. החץ מתפצל ל-4 חיצים שמצביעים על המשתנה הרלוונטי. ארבעת החיצים הם אדום, ירוק, כחול ואלפא. לאדום ולכחול יש ערך 0, ירוק הוא 128 ואלפא הוא 100%.

בתרשים הקודם מוצג הצבע המקורי green מומר למרחב הצבעים של הצבע החדש, והופך למספרים בודדים שמיוצגים בתור המשתנים r, g, b ו-alpha, ולאחר מכן הם משמשים ישירות כערכי צבע rgb() חדש.

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

מילת המפתח from

החלק הראשון בתחביר שצריך ללמוד הוא החלק from <color> שמציין צבע. הוא עובר ממש לפני ציון הערכים. הנה דוגמה לקוד שבו כל מה שנוסף הוא from green, ממש לפני שמציינים את הערכים של rgb().

.syntax-introduction_same-colors {
  color: green;
  color: rgb(0 128 0);
  color: rgb(from green r g b);    /* result = rgb(0 128 0) */
}

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

המרת צבעים

במילים פשוטות יותר, הוא ממיר את הצבעים לערוצי r g ו-b כדי להשתמש בהם בצבע חדש.

rgb(from green r g b)           /* r=0 g=128 b=0 */
rgb(from rgb(0 128 0) r g b);   /* r=0 g=128 b=0 */

צבעים ממאפיינים מותאמים אישית

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

rgb(from rgb(255 105 180) r g b) /* ????? */
rgb(from var(--hotpink) r g b)   /* clear */

עבודה במרחב הצבעים המועדף עליך

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

rgb(from hsl(120 100% 25%) r g b)     /*  r=0   g=128  b=0    */
hsl(from hsl(120 100% 25%) h s l)     /*  h=120 s=100% l=25%  */
hwb(from hsl(120 100% 25%) h w b)     /*  h=120 w=0%   b=50%  */
lch(from hsl(120 100% 25%) l c h)     /*  l=46  c=68   h=134  */

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

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

שילוב, התאמה, השמטה וחזרה על המשתנים

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

rgb(from green g g g)    /* rgb(128 128 128) */
rgb(from green b r g)    /* rgb(0 0 128) */
rgb(from green 0 0 g)    /* rgb(0 0 128) */

שקיפות כמשתנה

התחביר גם מספק את השקיפות בתור משתנה בשם alpha. היא אופציונלית, ומופיעה אחרי / בסימון הצבעים הפונקציונלי.

rgb(from #00800080 r g b / alpha)             /* alpha=50% */
rgb(from rgba(0,128,0,.5) r g b / alpha)      /* alpha=50% */
rgb(from rgb(0 128 0 / 50%) r g b / alpha)    /* alpha=50% */

להשתמש ב-calc() או בפונקציות CSS אחרות על המשתנים

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

green                              /*  h=120 s=100% l=25%  */
hsl(from green calc(h * 2) s l)    /*  h=240 s=100% l=25%  */

חיל הים עכשיו! הגוון הוכפל, קיבל גוון של 120 והפך אותו ל-240, תוך שינוי מוחלט של הצבע. כך שיניתי את הגוון לאורך גלגל הצבעים, טריק פשוט מאוד עם מרחבי צבע גליליים כמו HSL, HWB, LCH ו-OKLCH.

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

חיפוש תמיכה בדפדפן

@supports (color: rgb(from white r g b)) {
  /* safe to use relative color syntax */
}

תרחישים לדוגמה והדגמות

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

בנוסף, בהרבה דוגמאות יוצגו התאמות של צבעים עם דרגת המלל by ו-to. צבע שהשתנה by הוא שינוי יחסי בצבע – שינוי שמשתמש בערך של המשתנה ומבצע התאמה על סמך הערך הנוכחי שלו. to שהצבע השתנה הוא שינוי מוחלט בצבע. שינוי שלא משתמש בערך של המשתנה, ובמקום זאת מציין ערך חדש לגמרי.

כל ההדגמה נמצאת באוסף Codepen הזה.

הבהרת צבע

מרחבי הצבעים OKLCH, OKLAB, XYZ או sRGB מספקים את התוצאות הצפויות ביותר כשהצבעים בהירים יותר.

הבהרת כמות

בדוגמה הבאה .lighten-by-25 לוקחת את הצבע blue וממירה אותו ל-OKLCH, ולאחר מכן מבהיר את הכחול על ידי הגדלה של ערוץ l (בהירות) על ידי הכפלת הערך הנוכחי ב-1.25. זה מזיז את התאורה הכחולה לכיוון לבן ב-25%.

.lighten-by-25 {
  background: oklch(from blue calc(l * 1.25) c h);
}

הבהרת ערך ספציפי

בדוגמה הבאה, .lighten-to-75 לא משתמש בערוץ l כדי להבהיר את הערך blue, אלא מחליף לחלוטין את הערך ב-75%.

.lighten-to-75 {
  background: oklch(from blue 75% c h);
}

כהה יותר צבע

אותם אזורי צבע יעילים להבהרת הצבע, מתאימים גם לכהה של צבע.

האפלה במידה מסוימת

בדוגמה הבאה .darken-by-25 לוקחת את הצבע הכחול וממירה אותו ל-OKLCH, ולאחר מכן מחשיכה את הכחול על ידי הקטנת הערוץ l (בהירות) ב-25% על ידי הכפלת הערך ב-.75. הפעולה הזו דוחפת את הצבע הכחול לכיוון השחור ב-25%.

.darken-by-25 {
  background: oklch(from blue calc(l * .75) c h);
}

כהה לערך שצוין

בדוגמה הבאה, .darken-to-25 לא משתמש בערוץ l כדי להכהות את blue, אלא מחליף לחלוטין את הערך ב-25%.

.darken-to-25 {
  background: oklch(from blue 25% c h);
}

רוויה של צבע

רוויה בכמות מסוימת

בדוגמה הבאה, ב-.saturate-by-50 נעשה שימוש ב-s מ-hsl() כדי להגביר את חיוניות של orchid בשיעור של 50% יחסי.

.saturate-by-50 {
  background: hsl(from orchid h calc(s * 1.5) l);
}

רוויה עד לסכום ספציפי

בדוגמה הבאה, .saturate-to-100 לא משתמש בערוץ s מ-hsl(), אלא מציין את ערך הרוויה הרצוי. בדוגמה הזו, הרוויה מועלית ל-100%.

.saturate-to-100 {
  background: hsl(from orchid h 100% l);
}

הפחתת הרוויה של צבע

הפחתת הרוויה בסכום

בדוגמה הבאה .desaturate-by-half משתמש ב-s מ-hsl() כדי להפחית את הרוויה של indigo בחצי.

.desaturate-by-half {
  background: hsl(from indigo h calc(s / 2) l);
}

הפחתת הרוויה לערך ספציפי

במקום להפחית את הרוויה בסכום מסוים, אפשר להפחית את הרוויה לערך ספציפי. בדוגמה הבאה .desaturate-to-25 נוצר צבע חדש על סמך indigo, אבל הרוויה מגדירה את הערך ל-25%.

.desaturate-to-25 {
  background: hsl(from indigo h 25% l);
}

Chroma שיפור צבע

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

.increase-chroma {
  background: oklch(from orange l calc(c + .1) h);
}

התאמת מידת השקיפות של צבע

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

כוונון השקיפות לפי כמות

.decrease-opacity-by-25 {
  background: rgb(from lime r g b / calc(alpha / 2));
}

התאמת השקיפות לערך ספציפי

.decrease-opacity-to-25 {
  background: rgb(from lime r g b / 25%);
}

היפוך צבע

היפוך צבעים הוא פונקציה נפוצה של התאמת צבעים שניתן למצוא בספריות צבעים. דרך אחת לעשות זאת היא להמיר צבע ל-RGB ואז לחסר את הערך של כל ערוץ מ-1.

.invert-each-rgb-channel {
  background: rgb(from yellow calc(255 - r) calc(255 - g) calc(255 - b));
}

הוספת צבע

אם המטרה שלכם לא הייתה להפוך צבע אלא להשלים אותו, סביר להניח שאתם מחפשים סיבוב גוון. בוחרים מרחב צבעים שמספק את הגוון כזווית, ומשתמשים ב-calc() כדי לסובב את הגוון במידה הרצויה. כדי למצוא התאמה של צבע, צריך לסובב את המסך בחצי סיבוב. במקרה הזה, כדי לקבל את התוצאה אפשר להוסיף או להוריד מהערוץ h עד 180.

.complementary-color {
  background: hsl(from blue calc(h + 180) s l);
}

ניגוד צבע

כשיטה להשגת יחסי ניגודיות של צבעים נגישים, שקול להשתמש ב-L&midast; (Lstar). הפעולה הזו משתמשת בערוץ בהירות אחיד (בערך) של בהירות אחידה (L) מ-LCH ו-OKLCH, ב-calc(). בהתאם לניגודיות הנמוכה, הבינונית או הגבוהה, ערך הדלתא של L&midast הוא בערך 40, ~50 או 60~.

השיטה הזו פועלת היטב בכל גוון ב-LCH או ב-OKLCH.

ניגודיות צבע כהה יותר

המחלקה .well-contrasting-darker-color מדגימה L* עם דלתא של 60. מכיוון שהצבע המקורי הוא צבע כהה (בהירות ערך נמוכה), 60% (.6) נוסף לערוץ הבהירות. משתמשים בשיטה הזו כדי למצוא טקסט עם ניגודיות טובה, באותו גוון וצבע כהה על רקע בהיר.

.well-contrasting-darker-color {
  background: darkred;
  color: oklch(from darkred calc(l + .60) c h);
}

השוו לצבע בהיר יותר

המחלקה .well-contrasting-lighter-color מדגימה גם L* עם דלתה של 60%. מכיוון שהצבע המקורי הוא צבע בהיר (בהירות ערך גבוהה), .60 מוחרג מערוץ הבהירות.

.well-contrasting-lighter-color {
  background: lightpink;
  color: oklch(from lightpink calc(l - .60) c h);
}

לוחות צבעים

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

פתחו את קוד המקור לדוגמה של הלוחות ונסו לשנות את --base-color, כדי לראות עד כמה הלוחות האלה דינמיים. כיף!

אם אהבת את הסרטון, אוכל לתת לך מידע מפורט על בניית לוחות צבעים ב-CSS באמצעות OKLCH ב-YouTube.

לוחות צבעים מונוכרומטיים

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

:root {
  --base-color: deeppink;

  --color-0: oklch(from var(--base-color) calc(l + .20) c h); /* lightest */
  --color-1: oklch(from var(--base-color) calc(l + .10) c h);
  --color-2: var(--base-color);
  --color-3: oklch(from var(--base-color) calc(l - .10) c h);
  --color-4: oklch(from var(--base-color) calc(l - .20) c h); /* darkest */
}
התנסות במספר לוחות צבעים עם תחביר צבעים יחסי ו-OKLCH

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

לוחות צבעים אנלוגיים

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

:root {
  --base-color: blue;

  --primary:   var(--base-color);
  --secondary: oklch(from var(--base-color) l c calc(h - 45));
  --tertiary:  oklch(from var(--base-color) l c calc(h + 45));
}

לוחות צבעים טריאדיים

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

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

:root {
  --base-color: yellow;
  --triad-1: oklch(from var(--base-color) l c calc(h - 120));
  --triad-2: oklch(from var(--base-color) l c calc(h + 120));
}

לוחות צבעים של טטרדי

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

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

:root {
  --base-color: lime;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) l c calc(h + 90));
  --color-3: oklch(from var(--base-color) l c calc(h + 180));
  --color-4: oklch(from var(--base-color) l c calc(h + 270));
}

מונוכרומטי עם סיבוב גוונים קל

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

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

:root {
  --base-color: deeppink;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) calc(l - .10) c calc(h - 10));
  --color-3: oklch(from var(--base-color) calc(l - .20) c calc(h - 20));
  --color-4: oklch(from var(--base-color) calc(l - .30) c calc(h - 30));
  --color-5: oklch(from var(--base-color) calc(l - .40) c calc(h - 40));
}
כדאי לנסות את ה-Leaderboard הזה, שמבוסס על OKLCH וסיבוב גוונים

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

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

li {
  --_bg: oklch(
    /* decrease lightness as list grows */
    calc(75% - (var(--i) * 5%))

    /* decrease chroma as list grows */
    calc(.2 - (var(--i) * .01))

    /* lightly rotate the hue as the list grows */
    calc(var(--hue) - (var(--i) + 5))
  );
}