לדלג לתוכן

איך מממשים מצב כהה - Dark Mode - מדריך מעשי

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

נקודת ההתחלה - prefers-color-scheme

הדפדפן כבר יודע להגיד לכם מה המשתמש מעדיף במערכת ההפעלה שלו, דרך media query פשוט:

@media (prefers-color-scheme: dark) {
  body {
    background: #111;
    color: #eee;
  }
}

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

בניית מתג ידני עם משתני CSS

הדרך הנקייה ביותר לממש החלפה ידנית היא עם משתני CSS (CSS Custom Properties). מגדירים את הצבעים כמשתנים ברמת השורש, ומחליפים אותם לפי attribute שמוגדר על ה-html:

:root {
  --bg: #ffffff;
  --text: #111111;
}

[data-theme="dark"] {
  --bg: #111111;
  --text: #eeeeee;
}

body {
  background: var(--bg);
  color: var(--text);
}

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

איך שומרים על הבחירה של המשתמש

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

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

שיקולי נגישות וקונטרסט

מצב כהה לא אומר סתם להפוך שחור ולבן. צריך לשים לב:

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

מה עם ספריות ופריימוורקים

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

מה עושים במעבר בין דפים - Multi-Page Apps

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

מאיפה ממשיכים ללמוד

מימוש Dark Mode הוא תרגיל מצוין שמשלב CSS, JavaScript ואחסון בצד הלקוח. אם אתם רוצים ללמוד את כל הבסיס הזה בצורה מסודרת, יש לנו קורס צד לקוח בחינם שמכסה בדיוק את הנושאים האלה.

לסיכום

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

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

הצטרפו לקהילה בדיסקורד