פיתוח רכיב של הגדרות

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

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

הדגמה

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

סקירה כללית

פירטתי את ההיבטים של הרכיב הזה בקטעים הבאים:

  1. פריסות
  2. צבע
  3. קלט של טווח בהתאמה אישית
  4. קלט של תיבת סימון בהתאמה אישית
  5. שיקולים בנושא נגישות
  6. JavaScript

פריסות

זוהי ההדגמה הראשונה של אתגר GUI שמבוססת כולה על CSS Grid. הנה כל רשת עם הדגשה באמצעות כלי הפיתוח ל-Chrome עבור רשתות:

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

רק בשביל הפער

הפריסה הנפוצה ביותר:

foo {
  display: grid;
  gap: var(--something);
}

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

חמישה פריסות משתמשות בשיטה הזו, והנה כולן מוצגות:

פריסות רשת אנכיות מודגשות בקווי מתאר ומרווחים מלאים

הרכיב fieldset, שמכיל כל קבוצת קלט (.fieldset-item), משתמש ב-gap: 1px כדי ליצור את הגבולות הדקים בין הרכיבים. אין פתרון מסובך לגבולות!

פער מלא
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
טריק עם גבול
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

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

הפריסה המורכבת ביותר הייתה פריסת המאקרו, הפריסה הלוגית בין <main> ל-<form>.

איך ממקמים במרכז תוכן שמופיע בכמה שורות

גם Flexbox וגם Grid מאפשרים align-items או align-content, וכשמדובר בפריסת רכיבים, פריסות content יחלקו את הרווח בין רכיבי הצאצא כקבוצה.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

האלמנט הראשי משתמש בplace-content: center קיצור דרך ליישור כדי שרכיבי הצאצא יהיו מיושרים למרכז בצורה אנכית ואופקית בפריסות של עמודה אחת ושתי עמודות.

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

חזרה על התאמה אוטומטית של גודל חלון

התבנית <form> משתמשת בפריסת רשת דינמית לכל קטע. הפריסה הזו משתנה מעמודה אחת לשתי עמודות בהתאם למקום הפנוי.

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;
}

לרשת הזו יש ערך שונה ל-row-gap (--space-xl) מאשר ל-column-gap (--space-xxl) כדי להוסיף את הטאץ' האישי הזה לפריסה הדינמית. כשמציגים את העמודות אחת מתחת לשנייה, אנחנו רוצים מרווח גדול, אבל לא גדול כמו במקרה של מסך רחב.

המאפיין grid-template-columns משתמש ב-3 פונקציות CSS: ‏ repeat(), ‏ minmax() ו-min(). Una Kravets כתבה פוסט מצוין בבלוג בנושא פריסות, שבו היא קוראת לזה RAM.

אם משווים את הפריסה שלנו לפריסה של Una, אפשר לראות 3 תוספות מיוחדות:

  • אנחנו מעבירים פונקציה נוספת min().
  • אנחנו מציינים align-items: flex-start.
  • יש סגנון max-width: 89vw.

הפונקציה הנוספת min() מתוארת היטב בבלוג של אוון מינטו, בפוסט Intrinsically Responsive CSS Grid with minmax() and min()‎. מומלץ לקרוא אותו. התיקון של flex-start היישור נועד להסיר את אפקט המתיחה שמוגדר כברירת מחדל, כך שגובה הרכיבים שמוצגים בפריסה הזו לא צריך להיות זהה, והם יכולים להיות בגובה הטבעי שלהם. בסרטון הזה ב-YouTube יש הסבר קצר על הוספת ההתאמה הזו.

כדאי להסביר בקצרה על max-width: 89vw בפוסט הזה. אראה לך את הפריסה עם הסגנון ובלעדיו:

מה קורה? כשמציינים את max-width, הוא מספק הקשר, גודל מפורש או גודל מוגדר לauto-fitאלגוריתם הפריסה כדי לדעת כמה חזרות אפשר להכניס למקום. למרות שברור שהרווח הוא 'בגודל מלא', לפי מפרט רשת ה-CSS, צריך לציין גודל או גודל מקסימלי. ציינתי גודל מקסימלי.

אז למה 89vw? כי זה התאים לפריסה שלי. אני ועוד כמה אנשים מצוות Chrome בודקים למה ערך סביר יותר, כמו 100vw, לא מספיק, ואם מדובר בבאג.

ריווח

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

:root {
  --space-xxs: .25rem;
  --space-xs:  .5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-xxl: 6rem;
}

השימוש בתהליכי העבודה האלה משתלב בצורה טובה עם רשתות, CSS @nest ותחביר רמה 5 של ‎ @media. לדוגמה, <main>הפריסה המלאה של סגנונות.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
  padding: var(--space-sm);

  @media (width >= 540px) {
    & {
      padding: var(--space-lg);
    }
  }

  @media (width >= 800px) {
    & {
      padding: var(--space-xl);
    }
  }
}

רשת עם תוכן ממורכז, עם ריווח מתון כברירת מחדל (כמו בנייד). אבל ככל שיש יותר מקום באזור התצוגה, הוא מתרחב על ידי הגדלת הריווח הפנימי. ‫2021 CSS נראה טוב מאוד!

זוכרים את הפריסה הקודמת, 'רק בשביל הפער'? הנה גרסה מלאה יותר של האופן שבו הם נראים ברכיב הזה:

header {
  display: grid;
  gap: var(--space-xxs);
}

section {
  display: grid;
  gap: var(--space-md);
}

צבע

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

:root {
  --surface1: lch(10 0 0);
  --surface2: lch(15 0 0);
  --surface3: lch(20 0 0);
  --surface4: lch(25 0 0);

  --text1: lch(95 0 0);
  --text2: lch(75 0 0);
}

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

אני הופך אותם בשאילתת מדיה להעדפות, כך:

:root {
  ...

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --surface2: lch(100 0 0);
      --surface3: lch(98 0 0);
      --surface4: lch(85 0 0);

      --text1: lch(20 0 0);
      --text2: lch(40 0 0);
    }
  }
}

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

LCH?

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

צילום מסך של דף האינטרנט pod.link/csspodcast, עם הפרק Color 2: Perception
בפודקאסט CSS אפשר לקבל מידע על צבעים שנתפסים בחושים (ועוד!).

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

:root {
  --surface1: lch(10 0 0);
  --text1:    lch(95 0 0);

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --text1:    lch(40 0 0);
    }
  }
}

--surface1: lch(10 0 0) מתורגם ל-10% בהירות, 0 כרומה ו-0 גוון: אפור כהה מאוד ללא צבע. אחר כך, בשאילתת המדיה למצב בהיר, הבהירות מוחלפת ל-90% עם --surface1: lch(90 0 0);. זהו עיקרון האסטרטגיה. מתחילים בשינוי הבהירות בין שני העיצובים, תוך שמירה על יחסי הניגודיות שנדרשים בעיצוב או על יחסי הניגודיות שיאפשרו נגישות.

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

אם אתם רוצים, תוכלו לקרוא מידע נוסף על מרחבי צבעים ועל lch(). זה מגיע!

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

Lea Verou

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

בדפדפנים רבים יש אמצעי בקרה של ערכת נושא כהה, נכון לעכשיו ב-Safari וב-Chromium, אבל צריך לציין ב-CSS או ב-HTML שהעיצוב שלכם משתמש בהם.

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

<meta name="color-scheme" content="dark light">

מידע נוסף זמין color-schemeבמאמר הזה של Thomas Steiner. יש הרבה יותר יתרונות מאשר תיבות סימון כהות!

CSS accent-color

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

input[type="checkbox"] {
  accent-color: var(--brand);
}

צילום מסך מ-Chromium ב-Linux של תיבות סימון ורודות

הבלטת צבעים עם שינויי צבע הדרגתיים קבועים והתמקדות בתוך הרכיב

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

בסרטון שלמעלה יש הרבה שכבות של משוב ואינטראקציה בממשק המשתמש, שעוזרות להוסיף אישיות לאינטראקציה באמצעות:

  • הדגשת ההקשר.
  • הצגת משוב בממשק המשתמש לגבי מידת המלאות של הערך בטווח.
  • הצגת משוב בממשק המשתמש שמציין ששדה מסוים מקבל קלט.

כדי לספק משוב כשמתבצעת אינטראקציה עם אלמנט, CSS משתמש בפסאודו המחלקה :focus-within כדי לשנות את המראה של אלמנטים שונים. בואו נפרט על .fieldset-item, זה מעניין מאוד:

.fieldset-item {
  ...

  &:focus-within {
    background: var(--surface2);

    & svg {
      fill: white;
    }

    & picture {
      clip-path: circle(50%);
      background: var(--brand-bg-gradient) fixed;
    }
  }
}

כשאחד מרכיבי הצאצא של הרכיב הזה נמצא במיקוד:

  1. לרקע .fieldset-item מוקצה צבע משטח עם ניגודיות גבוהה יותר.
  2. התג svg המקונן מלא בלבן כדי ליצור ניגודיות גבוהה יותר.
  3. העיגול המקונן <picture> clip-path מתרחב לעיגול מלא והרקע מתמלא בשיפוע הקבוע הבהיר.

טווח מותאם אישית

בהינתן רכיב הקלט הבא של HTML, אראה לך איך התאמתי אישית את המראה שלו:

<input type="range">

יש 3 חלקים באלמנט הזה שצריך להתאים אישית:

  1. רכיב או מאגר של טווח
  2. Track
  3. Thumb

סגנונות של רכיב טווח

input[type="range"] {
  /* style setting variables */
  --track-height: .5ex;
  --track-fill: 0%;
  --thumb-size: 3ex;
  --thumb-offset: -1.25ex;
  --thumb-highlight-size: 0px;

  appearance: none;         /* clear styles, make way for mine */
  display: block;
  inline-size: 100%;        /* fill container */
  margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
  background: transparent;  /* bg is in the track */
  outline-offset: 5px;      /* focus styles have space */
}

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

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

input[type="range"]::-webkit-slider-runnable-track {
  appearance: none; /* clear styles, make way for mine */
  block-size: var(--track-height);
  border-radius: 5ex;
  background:
    /* hard stop gradient:
        - half transparent (where colorful fill we be)
        - half dark track fill
        - 1st background image is on top
    */
    linear-gradient(
      to right,
      transparent var(--track-fill),
      var(--surface1) 0%
    ),
    /* colorful fill effect, behind track surface fill */
    var(--brand-bg-gradient) fixed;
}

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

סגנון המילוי של הטראק

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

/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')

/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
  const max = slider.getAttribute('max') || 10;
  const percent = slider.value / max * 100;

  return `${parseInt(percent)}%`;
};

/* on page load, set the fill amount */
sliders.forEach(slider => {
  slider.style.setProperty('--track-fill', rangeToPercent(slider));

  /* when a slider changes, update the fill prop */
  slider.addEventListener('input', e => {
    e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
  })
})

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

במאמר הזה ב-CSS-Tricks מאת Ana Tudor מוצג פתרון שמבוסס על CSS בלבד למילוי של רצועת זמן. מצאתי גם את range element מאוד מעורר השראה.

סגנונות של תמונות ממוזערות

input[type="range"]::-webkit-slider-thumb {
  appearance: none; /* clear styles, make way for mine */
  cursor: ew-resize; /* cursor style to support drag direction */
  border: 3px solid var(--surface3);
  block-size: var(--thumb-size);
  inline-size: var(--thumb-size);
  margin-top: var(--thumb-offset);
  border-radius: 50%;
  background: var(--brand-bg-gradient) fixed;
}

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

@custom-media --motionOK (prefers-reduced-motion: no-preference);

::-webkit-slider-thumb {
  

  /* shadow spread is initally 0 */
  box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);

  /* if motion is OK, transition the box-shadow change */
  @media (--motionOK) {
    & {
      transition: box-shadow .1s ease;
    }
  }

  /* on hover/active state of parent, increase size prop */
  @nest input[type="range"]:is(:hover,:active) & {
    --thumb-highlight-size: 10px;
  }
}

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

חבל שאי אפשר להדגיש תיבות סימון בקלות כזו…

בוררים חוצי-דפדפנים

כדי להשיג עקביות בין דפדפנים, גיליתי שאני צריך את הבוררים -webkit- ו--moz-:

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

תיבת סימון מותאמת אישית

בהינתן רכיב הקלט הבא של HTML, אראה לך איך התאמתי אישית את המראה שלו:

<input type="checkbox">

יש 3 חלקים באלמנט הזה שצריך להתאים אישית:

  1. רכיב תיבת סימון
  2. תוויות משויכות
  3. אפקט הדגשה

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

input[type="checkbox"] {
  inline-size: var(--space-sm);   /* increase width */
  block-size: var(--space-sm);    /* increase height */
  outline-offset: 5px;            /* focus style enhancement */
  accent-color: var(--brand);     /* tint the input */
  position: relative;             /* prepare for an absolute pseudo element */
  transform-style: preserve-3d;   /* create a 3d z-space stacking context */
  margin: 0;
  cursor: pointer;
}

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

תוויות של תיבות סימון

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

קלט
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
תווית
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

בתווית, מוסיפים מאפיין for שמפנה לתיבת סימון לפי מזהה: <label for="text-notifications">. בתיבת הסימון, צריך להוסיף את השם והמזהה פעמיים כדי לוודא שהם יימצאו באמצעות כלים וטכנולוגיות שונים, כמו עכבר או קורא מסך: <input type="checkbox" id="text-notifications" name="text-notifications">. :hover, ‏ :active ועוד כלים כלולים בחיבור ללא תוספת תשלום, וכך יש יותר דרכים ליצור אינטראקציה עם הטופס.

הדגשת תיבת סימון

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

הצלחתי להשיג את אותו אפקט חזותי באמצעות פסאודו אלמנט, וכמות גדולה של CSS מסובך:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

input[type="checkbox"]::before {
  --thumb-scale: .01;                        /* initial scale of highlight */
  --thumb-highlight-size: var(--space-xl);

  content: "";
  inline-size: var(--thumb-highlight-size);
  block-size: var(--thumb-highlight-size);
  clip-path: circle(50%);                     /* circle shape */
  position: absolute;                         /* this is why position relative on parent */
  top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
  left: 50%;
  background: var(--thumb-highlight-color);
  transform-origin: center center;            /* goal is a centered scaling circle */
  transform:                                  /* order here matters!! */
    translateX(-50%)                          /* counter balances left: 50% */
    translateY(-50%)                          /* counter balances top: 50% */
    translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
    scale(var(--thumb-scale))                 /* value we toggle for animation */
  ;
  will-change: transform;

  @media (--motionOK) {                       /* transition only if motion is OK */
    & {
      transition: transform .2s ease;
    }
  }
}

/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
  --thumb-scale: 1;
}

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

זו בהחלט אינטראקציה מיקרו, אבל חשוב לי לשמור על העקביות החזותית. טכניקת שינוי הגודל של האנימציה זהה לזו שבה השתמשנו במקומות אחרים. אנחנו מגדירים מאפיין בהתאמה אישית לערך חדש ומאפשרים למעבר CSS להנפיש אותו על סמך העדפות התנועה. התכונה העיקרית כאן היא translateZ(-1px). ההורה יצר מרחב תלת-ממדי, והצאצא של פסאודו-האלמנט נכנס אליו על ידי הצבה מעט אחורה במרחב z.

נגישות

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

אפשרויות של רכיבי HTML

<form>
<header>
<fieldset>
<picture>
<label>
<input>

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

מאפייני HTML

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

<picture aria-hidden="true">

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

קובץ ה-SVG הוא אוסף של נתונים מתמטיים. נוסיף רכיב <title> כדי ליצור כותרת שמופיעה כשמעבירים את העכבר מעל התמונה, ותגובה שקל לקרוא שמסבירה מה הנתונים המתמטיים יוצרים:

<svg viewBox="0 0 24 24">
  <title>A note icon</title>
  <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>

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

JavaScript

כבר הסברתי איך הצבע של המילוי של הרצועה נוהל מ-JavaScript, אז עכשיו נסתכל על ה-JavaScript שקשור ל-<form>:

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

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

צילום מסך של התוצאות של console.table(), שבו נתוני הטופס מוצגים בטבלה

סיכום

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

כדאי לגוון את הגישות שלנו וללמוד את כל הדרכים לבנות אתרים. תצור דמו, תצייץ לי קישורים ואוסיף אותו לקטע Community remixes שבהמשך!

רמיקסים מהקהילה

  • @tomayac עם הסגנון שלו לגבי אזור ההשהיה של תוויות תיבות הסימון! בגרסה הזו אין רווח בין הרכיבים כשמעבירים את העכבר מעליהם: הדגמה ומקור.