שימוש במאפיינים לוגיים נותן למפתחים אפשרות ליצור אתרים דינמיים ורספונסיביים ולאפשר שליטה במבנה האתר תוך שימוש בכיונים לוגיים, בניגוד לכיוונים פיזיים. למען האמת, זה נשמע הרבה יותר מסובך ממה שזה באמת. הדבר היחיד שצריך לזכור כשניגשים לשימוש במאפיינים לוגיים הוא אותו דבר שאנדר גילה בבית הספר ללחימה בבאגים: באפס כבידה אין למעלה ולמטה – רק קדימה (וסליחה על הרפרנס הגיקי). אותו דבר בשימוש במאפיינים לוגיים. אין ימין, שמאל, למעלה ולמטה. יש inline ו block, ויש התחלה וסוף.
כל מי שעובד עם CSS מכיר את השימוש שאנחנו עושים בכיוונים השונים, כמו למעלה, למטה, ימין ושמאל. קחו לדוגמה את הדוגמה הבאה ליישור קונטיינר בחלל העמוד שלנו.
<body>
<header>
some content
</header>
<main>
main content including:
<div>
</div>
</main>
</body>
body {
width: min(1250px, 95vw);
min-height: 100dvh;
margin: 15px auto;
}
header {
margin-top: 25px;
margin-left: 15px;
}
main {
margin-top: 15px;
padding-left: 10px;
}
div {
margin: auto;
}
עכשיו כשאני מסתכל על זה, אני רואה שיכולתי לחשוב על דוגמאות הרבה יותר פשוטות, אבל היי, אנחנו כבר כאן, אז בואו נהנה מזה כמה שרק אפשר, לא?
בקיצור, מה שאנחנו רואים כאן, אם נתעלם מזה שהשימוש בפיקסלים במקום בערכים רלטיבים הוא לא פרקטיקה מומלצת, הוא עמוד קלאסי שמחולק לראש העמוד ולתוכן הראשי של העמוד. ה CSS של העמוד מפריד בין החלקים השונים באמצעות התכונה margin-top
, והמיקום שלהם ביחס לצד שמאל של העמוד מוגדר על ידי התכונות margin-left
ו- padding-left
. אבל מה אם אנחנו רוצים לבנות את העמוד שלנו בצורה מודולרית, שתתאים לתכנים בשפות שונות, או אפילו בכיוונים שונים?
דמיינו שאתם בונים עכשיו אתר מולטי-לשוני, שאמור לתמוך בעברית, צרפתית ויפנית מסורתית. במקרה הזה, העיצוב של העמוד ייראה טוב בצרפתית, שנכתבת משמאל לימין, אבל בעברית, היישור לשמאל ייראה מוזר, וגם ביפנית ליישור הזה לא תהיה משמעות הגיונית. במקום לכתוב עמוד CSS נפרד לכל אחת מהשפות (בהנחה שהיפנית שלכם נכתבת בצורה העתיקה והמסורתית מלמעלה למטה, ולא המודרנית שנכתבת משמאל לימין), אתם יכולים לבנות את העמוד פעם אחת באמצעות מאפיינים לוגיים, שלוקחים בחשבון את הכיוון היחסי של העמוד במקום את המיקום האבסולוטי.
בשלב הזה נכנסים לבמה שני חברים וותיקים שלנו, שיקבלו מקום של כבוד בגישת החשיבה החדשה הזאת שאנחנו מנסים להטמיע לעצמנו בראש: inline ו- block. כמו שאנחנו כבר מכירים את הבלוק ואת האינליין משימושים קודמים שעשינו בהם בעבר (display: block
לדוגמה), בלוק מייצג לנו שורה שלמה של העמוד, בעוד אינליין נכנס בתוכה. אם נכנסים לתוך הלוגיקה הזאת, אפשר לומר שתחילתו של הבלוק היא יחסית לתחילת העמוד, בעוד שתחילתו של האינליין יחסית לתחילת השורה. בכוונה אני לא נכנס כאן להגדרות של ״למעלה״ או ״שמאלה״, ומיד נבין גם למה.
אז אם אנחנו לוקחים את החשיבה הלוגית החדשה שלנו אנחנו יכולים כבר להחליף חלק מהתכונות בקובץ ה CSS שלנו, ולקבל את הדבר הבא:
body {
width: min(1250px, 95vw);
min-height: 100dvh;
margin: 15px auto;
}
header {
margin-block-start: 25px;
margin-inline-start: 15px;
}
main {
margin-block-start: 15px;
padding-inline-start: 10px;
}
div {
margin: auto;
}
שימו לב שבמקום margin-top
כתבנו margin-block-start
, בעוד שבמקום margin-left
או padding-left
, ההתייחסות היא ל inline-start
. כלומר – במקום למעלה: התחלת הבלוק; במקום שמאל: התחלה האינליין.
אבל איפה כל זה עוזר לנו? אתם עשויים לשאול. אוה, מזל ששאלתם, אחרת היינו נשארים כאן בלי תשובה וסתם נותנים לנושא לנקר לנו באחורי הראש. קחו לכם חמש נקודות על השתתפות, ותחשבו על התרחיש הבא. נגיד שסיימתם לבנות את העיצוב של עמוד שאמור להיות מיושר לשמאל, ועכשיו אתם מעלים עמוד נוסף, שאמור לשמור על אותו עיצוב, אבל להיות מיושר לימין כי הוא בעברית. במידה והשתמשתם במאפיינים לוגיים כל מה שתצטרכו לעשות, הוא לאותת לעמוד שלכם שהוא מיושר לימין, וכל ההתייחסות של המאפיינים הלוגיים שלכם תהיה בהתאם. כלומר, ההתחלה של האינליין תהיה בצד ימין במקום בשמאל, ולהיפך. כדי לעשות את זה, כל שעליכם לעשות, הוא להוסיף לתגית ה HTML שלכם את שם השפה והכיוון שלה כך:
<html lng="he" dir="trl">
וזהו, העמוד שלכם מותאם ליישור לימין, בלי שום עבודה נוספת.
אלמנטים מדומים, או Pseudo Elements הם סלקטורים שנותנים לנו אפשרות ליצור אלמנטים חדשים על הדף, או לשלוט באלמנטים קיימים בצורה שבה היינו צריכים להוסיף אלמנטים כדי להגיע לאותה תוצאה. בהמשך המשפט הזה יישמע אולי יותר מובן. אלמנטים מדומים מסומנים בסימון נקודותיים כפולים לפני האלמנט שאתם מוסיפים.
האלמנטים הנפוצים ביותר
::before
כשמו כן הוא. מייצר אלמנט לפני התוכן בתוך האלמנט שאתם מטרגטים.
.parent::before {
content: 'first content';
}
כך שהתוצאה שלנו תהיה:
<div class="parent">
::before
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
כפי שניתן לראות מהדוגמה, על מנת שהאלמנט יתקיים ברמת ה HTML של האתר, הוא חייב לכלול את התכונה content
, גם אם הערך שלה יהיה בסופו ריק בסופו של דבר (content=""
).
::after
תדמיינו את ההיפך המושלם מהאלמנט הקודם ותקבלו את הסלקטור הזה, שמייצר אלמנט מדומה אחרי התוכן בתוך האלמנט שאתם מטרגטים.
.parent::after {
content: 'last content';
}
במקרה הזה, התוצאה תהיה כזאת:
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
::after
</div>
::placeholder
רוב האלמנטים המדומים די מסבירים את עצמם. Before מופיע לפני האלמנט, After מופיע אחריו. אם תנסו מספיק זמן לנחש מה התפקיד של Placeholder, בטח תצליחו לעלות על זה שמדובר באלמנט שומר המקום בטפסים שלכם
See the Pen
Untitled by Yoav Shai (@yoav-shai)
on CodePen.
כמו שאתם יכולים לראות בדוגמה הזאת, באמצעות שימוש ב ::placeholder
, הצלחנו די בקלות לשנות את העיצוב של השדה הראשון בטופס.
::marker
בניגוד לשאר החברים שלו ברשימה הזאת, השם של האלמנט הזה פחות ברור מאליו, אבל אני בטוח שאם תשקיעו בזה כמה דקות, תצליחו אולי לחשוב מה הייעוד שלו. אבל למקרה שאין לכם כוח, או זמן, או שאולי לא הצלחתם (שזה גם בסדר גמור), ה ::marker
נותן לכם את האפשרות לשלוט בסמן של רשימות לא מסודרת (ul – unordered lists). כמו שניתן לראות ברשימת הקניות שבדוגמה, בה החלטתי לתת לגביע לכל מוצר מנצח שברשימה. אפשר אפילו לקחת את השימוש בו צעד או שניים קדימה ולהתאים לכל פריט אייקון ייחודי לו באמצעות שילוב של data-attribute
אם :has()
, שעל שניהם נדבר בפוסטים נפרדים וייעודיים (חחח) להם.
See the Pen
Marker pseudo element example by Yoav Shai (@yoav-shai)
on CodePen.
::selection
אלמנטים פחות נפוצים
::first-letter
מכירים את זה שאתם פותחים ספר ישן והאות הראשונה של הפרק היא בעיצוב גדול ומרשים, עם גילופי עץ מטורפים שמתפשטים לכל עבר? אז האלמנט הזה הוא גרסת ה CSS שלהם. אתם יכולים לעשות איתו (כמעט) ככל העולה על רוחכם כדי לעצב את האות הראשונה בפסקה.
See the Pen
First-letter pseudo element example by Yoav Shai (@yoav-shai)
on CodePen.
::first-line
אלמנט זה נותן לכם את האפשרות לעצב אך ורק את השורה העליונה בפסקה. לדוגמה, כך:
See the Pen
Untitled by Yoav Shai (@yoav-shai)
on CodePen.
שימו לב שבדומה למקרה של אלמנט האות הראשונה ואלמנט שומר המקום, ניתן להשתמש באלמנט זה רק בחלק מהתכונות האפשריות. בין התכונות המותרות לשימוש: כל תכונות הפונט, כל תכונות הרקע, צבע (מן הסתם), מרווחי טקסט למיניהם, עיטורי טקסט ועוד.
למה שתרצו לעשות את זה? טוב, זה כבר עניין שלכם. אני לא נכנס להנאות המוזרות שלכם, ואתם אל תכנסו לשלי.
מאז ש Flex ו Grid נכנסו לחיינו, אחת השאלות שכל מפתח שואל את עצמו, ואחר כך את האינטרנט, היא באיזה מהם עדיף להשתמש. תיכנסו לכל אחד מהפורומים המקצועיים ולכל אחת מהקבוצות שמתמחות בבניית אתרים ותמצאו שרשורים על גבי שרשורים לצד ויכוחים סוערים יותר וסוערים פחות על היתרונות של השימוש באחד על פני האחר, ולהיפך.
התשובה היא כמובן פחות חד משמעית ממה שאנשים אוהבים לשמוע, ומסתכמת בדרך כלל במילים "זה תלוי", אז כדי לעשות קצת סדר בעניינים, וכדי למנוע מלחמות מיותרות וריבים חסרי תוחלת, הנה כל מה שאתם צריכים לדעת על שני הערכים האלה, ומתי (לדעת כותב שורות אלה), כדאי לכם להשתמש בכל אחד מהם.
גמישות לפני הכל
כמו שהרבה מפתחים אוהבים להגיד לכם, פלקס הוא חד ממדי, בעוד שגריד הוא דו ממדי. אבל זה לא מדויק, בגלל שאחת התכונות הכי חשובות של פלקס, כמו שהשם שלו מרמז, היא גמישות. מה שאומר שאפשר להגיע לעיצובים דו ממדיים באמצעות שימוש בפלקס, בעוד שלפעמים תגלו שהרבה יותר נוח לכם להגיע לעיצוב של שורה או טור דווקא באמצעות גריד.
אבל בואו לא נקפוץ ישר לסוף ונתחיל מההתחלה. וכשאני אומר מההתחלה, אני מתכוון לעיצוב של שורה שנוצרת כאן באמצעות פלקס פשוט.
See the Pen
Simple Flex Layout by Yoav Shai (@yoav-shai)
on CodePen.
אם תגידו שהיינו יכולים להגיע לעיצוב כזה בקלות גם עם תצוגת בלוק רגילה אתם תהיו צודקים לחלוטין, אבל מה שכל כך כיף בשימוש בפלקס בתבניות פשוטות כאלה, הוא הגמישות שמאפשרת לנו לשנות את כיון הזרימה של האלמנטים שלנו באמצעות שורת קוד אחת, כמו בדוגמה שלפנינו, כששימוש ב flex-direction: column
הופך את השורה שלנו לטור בלי יותר מדי מאמץ.
See the Pen
Simple Flex – Column by Yoav Shai (@yoav-shai)
on CodePen.
הגמישות של אותו פלקס חביב ופשוט נותנת לנו עוד המון אפשרויות לשחק עם התוכן שלנו. דוגמה אחת שאני אוהב להשתמש בה, היא כדי ליצור סליידר או תצוגת קרוסלה קלה לביצוע באמצעות שלוש פקודות CSS שאנחנו נותנים לאלמנט האב שלנו.
See the Pen
Flex – nowrap by Yoav Shai (@yoav-shai)
on CodePen.
עד כאן באמת השתמשנו בפלקס עבור תבניות חד ממדיות, אבל אם אנחנו רוצים ליצור עיצובים טיפה יותר רספונסיביים כמו בדוגמה שלפנינו, אנחנו יכולים ליצור בקלות מבנה של שתי שורות תוכן שממלאות חלל מוגדר מראש על ידי הגדרת flex-wrap: wrap
על אלמנט האב שלנו.
See the Pen
Flex – Wrap by Yoav Shai (@yoav-shai)
on CodePen.
אחד המאפיינים העיקריים של קופסת Flexbox, הוא שהגודל שלה גמיש ושהיא גדלה וקטנה לפי הגודל של התוכן שלה. אנחנו יכולים לנצל את התכונה הזאת כשאנחנו ניגשים לייצר עיצובים מעט יותר מסובכים, כמו בדוגמה הבאה, בה האלמנט הראשון והאחרון בתוך הקונטיינר מכילים בעצמם אלמנט פנימי בעל רוחב גדול יותר, שמגדיל אותם לגודל שאנחנו רוצים להגיע אליו. כמובן ששימוש בגישה הזאת יכול להוביל לבעיות בעיצוב, במידה והתוכן שלנו חורג מהכוונה המקורית שלנו, וגורם לשינויים לא צפויים במבנה העמוד.
See the Pen
Complex flex wrap by Yoav Shai (@yoav-shai)
on CodePen.
תבניות מסובכות ורספונסיביות בקלות
גריד, לעומת פלקס, יודע לייצר תבניות מסובכות ומורכבות הרבה יותר ובקלות רבה יחסית, כמו העיצוב הזה לדוגמה, שפעם כדי לייצר אותו היינו צריכים להשתמש ב float
וב clearfix
See the Pen
Classic Grid by Yoav Shai (@yoav-shai)
on CodePen.
היתרון של גריד על פני פלקס ביצירת תבניות מורכבות נובע מכך שבמקרה שלו הגודל של התיבה נקבע על פי ההגדרות של אלמנט האב, בלי קשר לגודל של התוכן (אלא אם הגדרנו אחרת), וכך המבנה שלנו לא נשבר בקלות.
בנוסף, השימוש בגריד מאפשר לנו ליצור תבניות רספונסיביות בקלות על ידי שימוש בשורת קוד אחת, כמו בדוגמה שלפנינו שבמסכים רחבים תציג שתי עמודות, ובמסכים צרים – עמודה אחת.
See the Pen
Responsive Grid by Yoav Shai (@yoav-shai)
on CodePen.
אבל זה לא עונה לנו על השאלה האם עדיף להשתמש בגריד או בפלקס, והתשובה הפשוטה היא לא. רגע, מה? איך לא? אז ככה. התשובה היא שאין דרך להגיד מה עדיף. זה תלוי מה הצרכים שלכם באותו רגע. האם אתם צריכים לייצר עיצוב חד ממדי, או תבניות מסובכות? האם אתם רוצים שהעיצוב יהיה גמיש ויתאים את עצמו לתוכן? יש כל כך הרבה שאלות שאתם יכולים לשאול את עצמכם, וכל אחת מהן תוביל אתכם למסקנה אחרת לגבי הצרכים שלכם. אבל אם תשאלו אותי, או מפתחי CSS אחרים, הדרך הכי טובה להשתמש בגריד ובפלקס היא בשילוב של שניהם, כי הם עובדים מעולה ביחד.
בואו נודה על האמת, יש מומחים גדולים ממני בתחום. יש אנשים שמלמדים CSS כבר שנים ומדברים בכנסים בינלאומיים, אחרים שיודעים איך לייצר יצירות אמנות באמצעות Div אחד וכמות מטורפת של CSS, וכאלה שמפתחים ומעצבים אתרים עוד מהימים שנטסקייפ היה שם נרדף לאינטרנט. אז למה שבכלל תרצו לקרוא את ההגיגים שלי ואת מה שיש לי להגיד על פיתוח אתרים בכלל, ועל CSS בפרט?
זאת באמת שאלה טובה, וכזו שאני מתמודד איתה מהרגע שהחלטתי להקים את האתר הזה. מה כבר יש לי לתרום שהקוראים של האתר הזה לא יוכלו לקבל במקום אחר?
יש לזה כמה תשובות. הראשונה היא שכבר עשר שנים שאני בונה אתרים ועושה הכל כדי ללמוד כל מה שאני יכול על התחום. אני קורא מאמרים באופן יומיומי, מנוי לכל הניוזלטרים הנכונים, עוקב אחרי שמות דבר, ומנסה לשמור על גחלת הידע בוערת. סיבה נוספת, היא שאני מגיע מתחום התוכן. לפני שבניתי אתרים, כתבתי להם את התוכן. יש לי בלוג ספרות (יחסית) מצליח, ניהלתי תוכן למספר דו-ספרתי של אתרים, הייתי מבקר ספרות באתר תוכן ישראלי גדול. בקיצור, אני לא זר למילה הכתובה, מה שיכול לעזור כשאתה מנסה ליצור תוכן לאתר, גם אם אותו אתר מדבר על פיתוח אתרים.
אחת הסיבות שהחלטתי להעלות את האתר הזה לאוויר הייתה כדי לעזור למי שנכנסים לתחום ורוצים ללמוד CSS. כשהתחלתי ללמוד CSS לפני כמה שנים, לא מצאתי שום תוכן בעברית בנושא. אמנם זו לא בעיה חמורה, כי לא חסרים תכנים מקצועיים מעניינים באנגלית, שפה שדי שגורה בפיו של הישראלי הממוצע. אבל בסופו של דבר, עברית היא שפת האם שלנו, ולמה שלא יהיה לנו קצת קל יותר למצוא תשובות לשאלות שעשויות לצוץ מדי פעם כשאנחנו בדיוק מנסים להבין למה אנחנו לא מצליחים למרכז את התוכן שלנו במרכז הדף, או איך למען השם עובדת שאילתת קונטיינר.
אבל האתר הזה הוא לא רק למען מי שרק נכנס לתחום. CSS, כמו כל שאר שפות התכנות, לא מפסיק להתפתח ולהשתנות, וכדי להישאר מעודכנים, גם מי שכבר עוסק שנים בתחום צריך להמשיך ללמוד כל הזמן. אחת הדרכים בהן הכי נוח לי לעבד מידע ולהבין אותו היא על ידי כתיבה, כך שהאתר הזה הוא גם בשבילי, ואני מקווה שגם מומחי CSS אחרים ימצאו בו תועלת במהלך הזמן.