סקירה כללית של אופן יצירת רכיבים רספונסיביים, נגישים ועם התאמה לצבעים ב-<button>.
בפוסט הזה אני רוצה לשתף את המחשבות שלי על בניית רכיב <button> שמותאם לצבעים, רספונסיבי ונגיש.
לצפייה בהדגמה ובמקור
אם אתם מעדיפים לצפות בסרטון, הנה גרסת YouTube של הפוסט הזה:
סקירה כללית
רכיב <button> מיועד לאינטראקציה עם המשתמש. הטריגרים של האירועים ב-click מגיעים מהמקלדת, מהעכבר, ממגע, מקול ועוד, עם כללים חכמים לגבי התזמון. בנוסף, כל דפדפן מגיע עם כמה סגנונות ברירת מחדל, כך שאפשר להשתמש בהם ישירות בלי לבצע התאמה אישית. אפשר להשתמש ב-color-scheme כדי להוסיף גם כפתורים בהירים וכהים שמופיעים בדפדפן.
יש גם סוגים שונים של לחצנים, כל אחד מהם מוצג בהטמעה של Codepen שמופיעה למעלה. <button> ללא סוג יותאם להיות בתוך <form> וישתנה לסוג submit.
<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>
<!-- button state -->
<button disabled></button>
<!-- input buttons -->
<input type="button" />
<input type="file">
באתגר ממשק המשתמש של החודש, לכל לחצן יוקצו סגנונות שיעזרו להבחין חזותית בין הכוונות שלהם. לחצני איפוס יהיו בצבעי אזהרה כי הם מבצעים פעולה הרסנית, ולחצני שליחה יהיו עם טקסט כחול מודגש כדי שהם ייראו קצת יותר בולטים מלחצנים רגילים.
ללחצנים יש גם פסאודו מחלקות שמשמשות את ה-CSS לקביעת סגנון. המחלקות האלה מספקות ווים של CSS להתאמה אישית של מראה הלחצן: :hover כשמעבירים את העכבר מעל הלחצן, :active כשלוחצים על הלחצן עם העכבר או המקלדת, ו-:focus או :focus-visible כדי לעזור בעיצוב של טכנולוגיה מסייעת.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Markup
בנוסף לסוגי הלחצנים שמופיעים במפרט HTML, הוספתי לחצן עם סמל ולחצן עם מחלקה בהתאמה אישית btn-custom.
<button>Default</button>
<input type="button" value="<input>"/>
<button>
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<path d="..." />
</svg>
Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">
לאחר מכן, לצורך בדיקה, כל לחצן מוצב בתוך טופס. כך אוכל לוודא שהסגנונות מתעדכנים בצורה מתאימה ללחצן ברירת המחדל, שמתנהג כמו לחצן שליחה. בנוסף, אני משנה את אסטרטגיית הסמלים מ-SVG מוטבע ל-SVG עם מסכה, כדי לוודא ששניהם פועלים באותה מידה.
<form>
<button>Default</button>
<input type="button" value="<input>"/>
<button>Icon <span data-icon="cloud"></span></button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom btn-large" type="button">Large Custom</button>
<input type="file">
</form>
בשלב הזה, מטריצת השילובים די מורכבת. יש יותר מ-20 שילובים של לחצנים, שנובעים מההבדלים בין סוגי הלחצנים, פסאודו-מחלקות והמיקום שלהם (בתוך טופס או מחוצה לו). טוב ששירות CSS יכול לעזור לנו להסביר כל אחד מהם בצורה ברורה.
נגישות
אלמנטים של כפתורים נגישים באופן טבעי, אבל יש כמה שיפורים נפוצים.
העברה של העכבר מעל פריט והתמקדות בו
אני רוצה לקבץ את :hover ו:focus יחד עם פסאודו-סלקטור פונקציונלי :is(). כך אוכל לוודא שהממשקים שלי תמיד יתחשבו בסגנונות של מקלדות וטכנולוגיות מסייעות.
button:is(:hover, :focus) {
…
}
הדגשת מיקוד המקלדת האינטראקטיבית
אני רוצה להנפיש את טבעת המיקוד למשתמשים במקלדת ובטכנולוגיה מסייעת. אני עושה את זה על ידי אנימציה של קו המתאר כך שהוא מתרחק מהלחצן ב-5px, אבל רק כשהלחצן לא פעיל. כך נוצר אפקט שגורם לטבעת המיקוד להתכווץ בחזרה לגודל של הלחצן כשלוחצים עליו.
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
איך מוודאים שמתקיימת ניגודיות צבעים שעומדת בדרישות
יש לפחות ארבעה שילובי צבעים שונים במצב בהיר ובמצב כהה שצריך להתייחס אליהם מבחינת ניגודיות הצבעים: לחצן, לחצן שליחה, לחצן איפוס ולחצן מושבת. במקרה הזה, השתמשנו ב-VisBug כדי לבדוק את כל הציונים ולהציג אותם בבת אחת:
הסתרת סמלים מאנשים שלא יכולים לראות
כשיוצרים לחצן עם סמל, הסמל צריך לספק תמיכה ויזואלית לטקסט של הלחצן. זה גם אומר שהסמל לא מועיל לאנשים עם לקות ראייה. למזלנו, הדפדפן מספק דרך להסתיר פריטים מטכנולוגיית קורא המסך, כך שאנשים עם אובדן ראייה לא יוטרדו מתמונות של לחצנים דקורטיביים:
<button>
<svg … aria-hidden="true">...</svg>
Icon Button
</button>
סגנונות
בקטע הבא, קודם כל אני יוצר מערכת של מאפיינים מותאמים אישית לניהול הסגנונות האדפטיביים של הלחצן. בעזרת המאפיינים המותאמים אישית האלה אפשר להתחיל לבחור רכיבים ולהתאים אישית את המראה שלהם.
אסטרטגיה מותאמת אישית של מאפיינים
האסטרטגיה של מאפיינים בהתאמה אישית שבה נעשה שימוש באתגר הזה של ממשק משתמש גרפי דומה מאוד לזו שבה נעשה שימוש בבניית ערכת צבעים. במערכת צבעים דינמית בהירה וכהה, מוגדר מאפיין מותאם אישית לכל עיצוב, והוא מקבל שם בהתאם. לאחר מכן משתמשים במאפיין מותאם אישית יחיד כדי להחזיק את הערך הנוכחי של ערכת הנושא, ומקצים אותו למאפיין CSS. אחר כך אפשר לעדכן את המאפיין המותאם אישית היחיד לערך אחר, וכך לעדכן את הסגנון של הלחצן.
button {
--_bg-light: white;
--_bg-dark: black;
--_bg: var(--_bg-light);
background-color: var(--_bg);
}
@media (prefers-color-scheme: dark) {
button {
--_bg: var(--_bg-dark);
}
}
מה שאהבתי זה שהעיצובים הבהיר והכהה הם הצהרתיים וברורים. ההפניה העקיפה וההפשטה מועברות אל המאפיין המותאם אישית --_bg, שהוא עכשיו המאפיין ה "ריאקטיבי" היחיד. המאפיינים --_bg-light ו---_bg-dark הם סטטיים. גם ברור מההסבר שהעיצוב הבהיר הוא העיצוב שמוגדר כברירת מחדל, ושהעיצוב הכהה מופעל רק בתנאים מסוימים.
הכנה לעיצוב עקבי
הבורר המשותף
הסלקטור הבא משמש לטירגוט של כל הסוגים השונים של לחצנים, ויכול להיות שהוא ייראה מורכב בהתחלה. השימוש ב-:where() מאפשר להתאים אישית את הלחצן בלי צורך לציין פרטים ספציפיים. לפעמים צריך להתאים את הלחצנים לתרחישים חלופיים, והבורר :where() מאפשר לבצע את המשימה בקלות. בתוך :where(), כל סוגי הלחצנים נבחרים, כולל ::file-selector-button, שאי אפשר להשתמש בו בתוך :is() או :where().
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
…
}
כל המאפיינים המותאמים אישית יהיו בתחום של בורר התגים הזה. הגיע הזמן לבדוק את כל המאפיינים המותאמים אישית! יש לא מעט מאפיינים מותאמים אישית שמשמשים בלחצן הזה. אני אפרט על כל קבוצה בהמשך, ואז אשתף את ההקשרים של מצב כהה ושל הפחתת תנועה בסוף הקטע.
צבע משני של הכפתור
לחצני שליחה וסמלים הם מקום מצוין להוסיף בו צבע:
--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);
צבע לטקסט של כפתור
צבעי הטקסט בכפתורים הם לא לבן או שחור, אלא גרסאות כהות או בהירות של --_accent באמצעות hsl(), והם תואמים לגוון 210:
--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);
צבע רקע כפתור
הרקעים של הלחצנים פועלים לפי אותו דפוס hsl(), למעט הלחצנים של העיצוב הבהיר – הם מוגדרים ללבן כדי שהמשטח שלהם ייראה קרוב למשתמש או לפני משטחים אחרים:
--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);
צבע רקע של כפתור
צבע הרקע הזה נועד ליצור מראה של משטח שנמצא מאחורי משטחים אחרים. הוא שימושי לרקע של קלט הקובץ:
--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);
ריווח פנימי של לחצן
הריווח מסביב לטקסט בכפתור מתבצע באמצעות היחידה ch, אורך יחסי לגודל הגופן. זה הופך להיות קריטי כשכפתורים גדולים יכולים פשוט להגדיל את font-size ואת קנה המידה של הכפתורים באופן יחסי:
--_padding-inline: 1.75ch;
--_padding-block: .75ch;
גבול הכפתור
רדיוס הגבול של הכפתור נשמר במאגר של מאפיין מותאם אישית, כדי שקלט הקובץ יתאים לכפתורים האחרים. צבעי הגבול מבוססים על מערכת הצבעים האדפטיבית שנקבעה:
--_border-radius: .5ch;
--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);
אפקט הדגשה כשמעבירים את העכבר מעל לחצן
המאפיינים האלה קובעים מאפיין גודל למעבר במצב אינטראקציה, והצבע המודגש נקבע לפי מערכת הצבעים האדפטיבית. בהמשך הפוסט נסביר איך הם פועלים יחד, אבל בסופו של דבר הם משמשים ליצירת אפקט box-shadow:
--_highlight-size: 0;
--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);
צללית טקסט של כפתור
לכל לחצן יש סגנון עדין של צל טקסט. כך הטקסט מופיע מעל הלחצן, מה שמשפר את הקריאוּת ומוסיף שכבת גימור נאה.
--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);
סמל של כפתור
הסמלים הם בגודל של שני תווים, בזכות יחידת האורך היחסי ch, שתעזור לשנות את גודל הסמל באופן יחסי לגודל הטקסט בלחצן. צבע הסמל מבוסס על --_accent-color כדי ליצור צבע מותאם וצבע שמשתלב עם העיצוב.
--_icon-size: 2ch;
--_icon-color: var(--_accent);
צל הלחצן
כדי שהצללים יותאמו בצורה נכונה למצב הבהיר והכהה, הם צריכים לשנות את הצבע ואת רמת האטימות שלהם. הצללים בעיצוב בהיר צריכים להיות עדינים ומוטים לכיוון צבע המשטח שהם מונחים עליו. הצללים בעיצוב הכהה צריכים להיות כהים יותר ורוויים יותר כדי שיוכלו להיות מוצגים על צבעי משטח כהים יותר.
--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);
--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);
בעזרת צבעים ועוצמות משתנים, אפשר ליצור שני עומקים של צללים:
--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));
--_shadow-2:
0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));
בנוסף, כדי לתת ללחצנים מראה תלת-ממדי קל, נעשה שימוש ב-1px box-shadow
כדי ליצור את האשליה:
--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);
מעברים בין לחצנים
בהתאם לדפוס של צבעים דינמיים, יצרתי שני מאפיינים סטטיים כדי להחזיק את האפשרויות של מערכת העיצוב:
--_transition-motion-reduce: ;
--_transition-motion-ok:
box-shadow 145ms ease,
outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);
כל הנכסים יחד בכלי הבחירה
:where( button, input[type="button"], input[type="submit"], input[type="reset"], input[type="file"] ), :where(input[type="file"])::file-selector-button { --_accent-light: hsl(210 100% 40%); --_accent-dark: hsl(210 50% 70%); --_accent: var(--_accent-light);--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);
--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);
--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);
--_padding-inline: 1.75ch; --_padding-block: .75ch;
--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);
--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);
--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);
--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));
--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;
--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);
--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

התאמות של העיצוב הכהה
הערך של תבנית המאפיינים הסטטיים -light ו--dark הופך ברור כשמגדירים את מאפייני העיצוב הכהה:
@media (prefers-color-scheme: dark) {
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
--_bg: var(--_bg-dark);
--_text: var(--_text-dark);
--_border: var(--_border-dark);
--_accent: var(--_accent-dark);
--_highlight: var(--_highlight-dark);
--_input-well: var(--_input-well-dark);
--_ink-shadow: var(--_ink-shadow-dark);
--_shadow-depth: var(--_shadow-depth-dark);
--_shadow-color: var(--_shadow-color-dark);
--_shadow-strength: var(--_shadow-strength-dark);
}
}
הכפתורים המותאמים אישית האלה לא רק נראים טוב, אלא גם מאפשרים לצרכנים להשתמש במאפיינים הבסיסיים שלהם בביטחון, כי הם יודעים שהם יותאמו להעדפות המשתמשים.
התאמות של תנועה מופחתת
אם המשתמש האורח לא מתנגד לתנועה, מקצים את --_transition ל-var(--_transition-motion-ok):
@media (prefers-reduced-motion: no-preference) {
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
--_transition: var(--_transition-motion-ok);
}
}
כמה סגנונות משותפים
צריך להגדיר את הגופנים של הלחצנים ושל שדות הקלט ל-inherit כדי שהם יתאימו לגופנים של שאר הדף. אחרת, הדפדפן יגדיר את הסגנון שלהם. ההגדרה הזו רלוונטית גם ל-letter-spacing. הגדרה של line-height ל-1.5 מגדירה את גודל תיבת האותיות כך שיהיה רווח מעל ומתחת לטקסט:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
/* …CSS variables */
font: inherit;
letter-spacing: inherit;
line-height: 1.5;
border-radius: var(--_border-radius);
}

עיצוב כפתורים
שינוי הבחירה
הסלקטור input[type="file"] הוא לא החלק של הכפתור בקלט, פסאודו-האלמנט ::file-selector-button הוא החלק הזה, לכן הסרתי את input[type="file"] מהרשימה:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
}
התאמות של הסמן והמגע
קודם כל אני מגדיר את הסמן לסגנון pointer, כדי שהמשתמשים בעכבר יבינו שהלחצן אינטראקטיבי. אחר כך הוספתי touch-action: manipulation כדי שהקליקים לא יצטרכו לחכות ולבדוק אם מדובר בקליק כפול, וכך התחושה היא שהלחצנים מגיבים מהר יותר:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
cursor: pointer;
touch-action: manipulation;
}
צבעים וגבולות
לאחר מכן התאמתי אישית את גודל הגופן, הרקע, הטקסט וצבעי הגבול, באמצעות חלק מהמאפיינים המותאמים אישית שנקבעו קודם:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
font-size: var(--_size, 1rem);
font-weight: 700;
background: var(--_bg);
color: var(--_text);
border: 2px solid var(--_border);
}

אזורים כהים
הכפתורים כוללים כמה טכניקות מעולות. העיצוב text-shadow מותאם לבהיר ולכהה, ויוצר מראה נעים ועדין של טקסט הלחצן שמופיע בצורה יפה מעל הרקע. ל-box-shadow מוקצות שלוש הצללות. הראשון, --_shadow-2, הוא צל רגיל של תיבה.
הצל השני הוא טריק שגורם לכפתור להיראות כאילו הוא משופע קצת כלפי מעלה. הצל האחרון הוא להדגשה במעבר עכבר, והגודל שלו בהתחלה הוא 0, אבל בהמשך יוגדר לו גודל והוא יועבר כך שייראה כאילו הוא גדל מהלחצן.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
box-shadow:
var(--_shadow-2),
var(--_shadow-depth),
0 0 0 var(--_highlight-size) var(--_highlight)
;
text-shadow: var(--_ink-shadow);
}

פריסה
הגדרתי לחצן עם פריסת flexbox, ספציפית פריסת inline-flex שתתאים לתוכן שלו. אחר כך מרכזים את הטקסט ומיישרים את הילדים אנכית ואופקית למרכז. כך הסמלים ורכיבי לחצנים אחרים ייושרו בצורה נכונה.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
}

ריווח
כדי להגדיר את הריווח בין הלחצנים, השתמשתי ב-gap כדי למנוע חפיפה בין רכיבים באותה רמה, ובמאפיינים לוגיים לריווח פנימי, כדי שהריווח בין הלחצנים יפעל בכל פריסות הטקסט.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
gap: 1ch;
padding-block: var(--_padding-block);
padding-inline: var(--_padding-inline);
}

חוויית משתמש במגע ובעכבר
החלק הבא מיועד בעיקר למשתמשים במכשירי מגע בניידים. המאפיין הראשון, user-select, מיועד לכל המשתמשים. הוא מונע את הדגשת הטקסט של הכפתור. הבעיה הזו בולטת בעיקר במכשירי מגע, כשמקישים על לחצן ומחזיקים אותו, ומערכת ההפעלה מדגישה את הטקסט של הלחצן.
בדרך כלל, חוויית המשתמש עם לחצנים באפליקציות מובנות לא כזו, לכן אני משבית את ההגדרה על ידי שינוי הערך של user-select ל-none. הקשה על צבעי הדגשה (-webkit-tap-highlight-color) ותפריטי הקשר של מערכת ההפעלה (-webkit-touch-callout) הם עוד תכונות של כפתורים שמתמקדות באינטרנט ולא תואמות לציפיות של משתמשים מכפתורים באופן כללי, ולכן גם אותן הסרתי.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
מעברים.
המשתנה --_transition של המעבר מוקצה למאפיין transition:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
transition: var(--_transition);
}
כשמעבירים את העכבר מעל הלחצן, בלי שהמשתמש לוחץ עליו, משנים את הגודל של ההדגשה בצל כדי ליצור מראה ממוקד שמתרחב מתוך הלחצן:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
):where(:not(:active):hover) {
--_highlight-size: .5rem;
}
כשמעבירים את המיקוד לכפתור, מגדילים את ההיסט של קו המתאר של המיקוד מהכפתור, וגם נותנים לו מראה נחמד של מיקוד שמתרחב מתוך הכפתור:
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
סמלים
כדי לטפל בסמלים, לסלקטור נוסף סלקטור :where() עבור רכיבי SVG משניים ישירים או רכיבים עם המאפיין המותאם אישית data-icon. גודל הסמל מוגדר באמצעות מאפיין מותאם אישית, תוך שימוש במאפיינים לוגיים מוטבעים ובמאפיינים לוגיים של בלוקים. צבע הקו מוגדר, וגם drop-shadow כדי להתאים ל-text-shadow. האפליקציה flex-shrink מוגדרת כ-0, כך שהסמל אף פעם לא נדחס. לבסוף, אני בוחר סמלים עם קווים ומקצה להם את הסגנונות האלה כאן עם fill: none ו-round קצוות וחיבורים של קווים:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
) > :where(svg, [data-icon]) {
block-size: var(--_icon-size);
inline-size: var(--_icon-size);
stroke: var(--_icon-color);
filter: drop-shadow(var(--_ink-shadow));
flex-shrink: 0;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}

התאמה אישית של לחצני שליחה
רציתי שכפתורי השליחה ייראו קצת יותר בולטים, והשגתי את זה על ידי הגדרת צבע הטקסט של הכפתורים כצבע ההדגשה:
:where(
[type="submit"],
form button:not([type],[disabled])
) {
--_text: var(--_accent);
}

התאמה אישית של לחצני האיפוס
רציתי שכפתורי האיפוס יכללו סימני אזהרה מובנים כדי להזהיר את המשתמשים מפני התנהגות הרסנית פוטנציאלית. בחרתי גם לעצב את הלחצן של העיצוב הבהיר עם יותר הדגשות אדומות מאשר בעיצוב הכהה. ההתאמה האישית מתבצעת על ידי שינוי הצבע הבסיסי המתאים (בהיר או כהה), והלחצן יעדכן את הסגנון:
:where([type="reset"]) {
--_border-light: hsl(0 100% 83%);
--_highlight-light: hsl(0 100% 89% / 20%);
--_text-light: hsl(0 80% 50%);
--_text-dark: hsl(0 100% 89%);
}
חשבתי גם שיהיה נחמד אם צבע קו המתאר של המיקוד יתאים לצבע המשנה האדום. צבע הטקסט משתנה מאדום כהה לאדום בהיר. I make the outline color
match this with the keyword
currentColor:
:where([type="reset"]):focus-visible {
outline-color: currentColor;
}

התאמה אישית של כפתורים מושבתים
בדרך כלל, הניגודיות בין הצבעים של לחצנים מושבתים נמוכה מדי, כי מנסים להחליש את הצבעים שלהם כדי שהם ייראו פחות פעילים. בדקתי כל קבוצת צבעים ודאגתי שהיא תעבור את הבדיקה. שיניתי את ערך הבהירות של HSL עד שהציון עבר את הבדיקה בכלי הפיתוח או ב-VisBug.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
)[disabled] {
--_bg: none;
--_text-light: hsl(210 7% 40%);
--_text-dark: hsl(210 11% 71%);
cursor: not-allowed;
box-shadow: var(--_shadow-1);
}

התאמה אישית של כפתורים להוספת קבצים
כפתור להוספת קובץ הוא קונטיינר של span וכפתור. אפשר להשתמש ב-CSS כדי להגדיר סגנון לשדה הקלט וללחצן המקונן, אבל לא לרכיב span. הגודל של מאגר התמונות הוא max-inline-size כדי שהוא לא יהיה גדול יותר ממה שצריך, ואילו הגודל של inline-size: 100% יתכווץ ויתאים למאגרים קטנים יותר. צבע הרקע מוגדר לצבע דינמי שכהה יותר מצבעים אחרים, כך שהוא נראה מאחורי לחצן בחירת הקובץ.
:where(input[type="file"]) {
inline-size: 100%;
max-inline-size: max-content;
background-color: var(--_input-well);
}
הלחצן לבחירת קבצים והלחצנים של סוגי הקלט מקבלים במיוחד את הערך appearance: none כדי להסיר סגנונות שסופקו על ידי הדפדפן ולא הוחלפו על ידי סגנונות הלחצנים האחרים.
:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
appearance: none;
}
לבסוף, מוסיפים שוליים ל-inline-end של הלחצן כדי להרחיק את הטקסט של ה-span מהלחצן וליצור רווח.
:where(input[type="file"])::file-selector-button {
margin-inline-end: var(--_padding-inline);
}

חריגים מיוחדים לעיצוב הכהה
נתתי לכפתורי הפעולה הראשיים רקע כהה יותר כדי שהטקסט יהיה בניגודיות גבוהה יותר, וכך הם נראים בולטים יותר.
@media (prefers-color-scheme: dark) {
:where(
[type="submit"],
[type="reset"],
[disabled],
form button:not([type="button"])
) {
--_bg: var(--_input-well);
}
}

יצירת וריאציות
לשם הכיף, וגם כי זה פרקטי, בחרתי להראות איך ליצור כמה וריאציות. אחד מהווריאציות הוא מאוד בולט, בדומה למראה של כפתורים ראשיים. עוד וריאציה היא גדולה. לגרסה האחרונה יש סמל עם מילוי הדרגתי.
כפתור עם צבעים עזים
כדי להשיג את הסגנון הזה של הכפתור, החלפתי את מאפייני הבסיס ישירות בצבעים כחולים. השיטה הזו מהירה ופשוטה, אבל היא מסירה את המאפיינים האדפטיביים והמראה של הרכיב זהה גם במצב בהיר וגם במצב כהה.
.btn-custom {
--_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
--_border: hsl(228 89% 63%);
--_text: hsl(228 89% 100%);
--_ink-shadow: 0 1px 0 hsl(228 57% 50%);
--_highlight: hsl(228 94% 67% / 20%);
}

כפתור גדול
כדי ליצור כפתור בסגנון הזה, צריך לשנות את המאפיין המותאם אישית --_size.
השוליים הפנימיים ורכיבי רווח אחרים הם יחסיים לגודל הזה, ומשתנים באופן יחסי לגודל החדש.
.btn-large {
--_size: 1.5rem;
}

כפתור של סמל
לאפקט הסמל הזה אין קשר לסגנונות הלחצנים שלנו, אבל הוא מדגים איך אפשר להשיג אותו באמצעות כמה מאפייני CSS, ועד כמה הלחצן מטפל בסמלים שלא מוצגים בפורמט SVG מוטבע.
[data-icon="cloud"] {
--icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;
-webkit-mask: var(--icon-cloud);
mask: var(--icon-cloud);
background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}
![]()
סיכום
עכשיו כשאתה יודע איך עשיתי את זה, איך היית עושה את זה‽ 🙂
בואו נגוון את הגישות שלנו ונלמד את כל הדרכים לבנות אתרים.
אצור הדגמה, תייג אותי בטוויטר עם קישורים, ואוסיף אותה לקטע של רמיקסים מהקהילה שבהמשך!
רמיקסים מהקהילה
עדיין אין מה לראות כאן.
משאבים
- קוד המקור ב-Github