הטקסט קריא יותר עם צבעי רקע דינמיים

תכונות אינטרנט: contrast-color()‎

כשיוצרים רכיבים של ממשק משתמש שאפשר לעשות בהם שימוש חוזר (כמו תגים או כפתורים) או כשמשתמשים בעיצובים דינמיים, יכול להיות קשה לוודא שהטקסט קריא על רקע בצבע לא צפוי. הפונקציה contrast-color() ב-CSS מחזירה את הערך black או white, ומגדילה למקסימום את יחס הניגודיות ביחס לצבע הרקע שצוין.

בחירת צבע הטקסט האופטימלי

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

חובה: מגדירים את המאפיין color באמצעות הפונקציה contrast-color(), ומעבירים את צבע הרקע (או המאפיין המותאם אישית שלו) כארגומנט.

.badge {
  /* Define the background color as a custom property */
  --badge-bg: #e02424;
  background-color: var(--badge-bg);
  /* MANDATORY: Dynamic contrasting color */
  color: contrast-color(var(--badge-bg));
}

לא: להשתמש ב-contrast-color() בשביל background-color. היא מיועדת במיוחד לצבעי חזית (כמו טקסט או גבולות) כדי ליצור ניגודיות עם צבע רקע נתון.

שילוב עם עיצוב

הפונקציה contrast-color() מקבלת כל ערך <color> תקין, כולל מאפיינים מותאמים אישית של CSS, ולכן היא שימושית במיוחד במערכות עיצוב. כשמרכזים את עיצובי הרקע כמשתנים, מוודאים שהניגודיות של התוכן בחזית מתעדכנת באופן אוטומטי בכל פעם שהעיצוב משתנה, אפילו לצבעים שהמשתמשים ציינו.

מה כן לעשות: להפנות למשתני רקע משותפים בתוך contrast-color() כדי להבטיח סנכרון באפליקציה.

.theme-card {
  background-color: var(--theme-surface-color);
  color: contrast-color(var(--theme-surface-color));
}

.theme-container[data-theme="light"] {
  --theme-surface-color: #f4f4f4;
}
.theme-container[data-theme="dark"] {
  --theme-surface-color: #1a1a1a;
}
.theme-container[data-theme="custom"] {
  --theme-surface-color: var(--user-custom-theme);
}

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

אסטרטגיות חלופיות

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

אסטרטגיה מתאים במיוחד ל… שיקולים
תחביר צבע יחסי חישוב ניגודיות אוטומטי ואיכותי באמצעות CSS בלבד. האיכות הגבוהה ביותר של חלופה ל-CSS בלבד.
צללית טקסט שיפור מהיר של הקריאוּת בכל רקע. יכול להיראות "מלוכלך" או "זוהר", ולא מתאים לכל העיצובים.
קו מתאר של טקסט שמירה על עובי הגופן תוך הבטחת ניגודיות בקצוות. אם האפשרות זמינה, כדאי להשתמש ב-paint-order כדי למנוע הצרת אותיות.
שכבת-על שקופה למחצה לוודא שיש אזור ניגודיות מינימלי מאחורי הטקסט. משנה את המראה של צבע הרקע מתחת לטקסט, נדרש רכיב טקסט נפרד.
מסנני SVG ניגודיות דינמית שמתעדכנת כשהרקע משתנה. נדרש רכיב טקסט נפרד; הטמעה לא מקצועית.

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

@supports (color: oklch(from red l c h)) {
  .badge {
    /* Highest threshold that passes WCAG. Higher values may be more legible. */
    --threshold: 0.623;
    --l: max(0, sign(var(--threshold) - l));
    color: oklch(from var(--badge-bg) var(--l) 0 h);
  }
}

@supports (color: contrast-color(red)) {
  .badge {
    color: contrast-color(var(--badge-bg));
  }
}

שירותי CSS חלופיים כגיבוי

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

אפשרות 1: קו מתאר של טקסט

.badge--stroke {
  -webkit-text-stroke: 4px black;
}

אפשרות 2: קו מתאר לטקסט עם paint-order כדי לשמור על צורת האותיות

.badge--stroke {
  -webkit-text-stroke: 4px black;
  paint-order: stroke fill;
}

אפשרות 3: שכבת-על של רקע שקוף למחצה

.badge--overlay {
  position: relative;
  color: #fff;
  overflow: hidden;
}
.badge--overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgb(0 0 0 / 0.4);
  z-index: 0;
}
.badge--overlay span {
  position: relative;
  z-index: 1;
}

אפשרות 4: צללית טקסט

.badge--shadow {
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}

אפשרות 5: מסנני SVG

  1. טעינת ההגדרה הזו של מסנן SVG. צריך להוסיף אותו ישירות למסמך ה-HTML אם אתם צריכים לתמוך בגרסאות של Safari שמושפעות מהבאג הזה ב-WebKit, שמונע הפניות לכתובות URL חיצוניות ולכתובות URL של נתונים בשביל מסננים. אחרת, צריך לטעון אותו מקובץ חיצוני, קובץ SVG או מוטבע ב-CSS.

    <!-- Technique from https://miunau.com/posts/dynamic-text-contrast-in-css/ -->
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0" style="display: none;">
      <defs>
        <filter id="contrast-filter" color-interpolation-filters="sRGB">
          <feColorMatrix type="matrix"
            values="0.2126 0.7152 0.0722 0 0
              0.2126 0.7152 0.0722 0 0
              0.2126 0.7152 0.0722 0 0
              0 0 0 1 0"/>
          <feMorphology operator="dilate" radius="2"/>
          <feComponentTransfer>
            <feFuncR type="linear" slope="-255" intercept="128"/>
            <feFuncG type="linear" slope="-255" intercept="128"/>
            <feFuncB type="linear" slope="-255" intercept="128"/>
          </feComponentTransfer>
          <feComposite operator="in" in2="SourceGraphic"/>
        </filter>
      </defs>
    </svg>
    
  2. עוטפים את הטקסט ב-<span>.

    <div class="badge--svg">
      <span>Badge content</span>
    </div>
    
  3. מפעילים את המסנן על <span>.

.badge--svg span{
  color: var(--badge-bg);
  filter: url(#contrast-filter);
}