תוכן עניינים מושלם עם HTML + CSS PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

תוכן עניינים מושלם עם HTML + CSS

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

ההרכבה של תוכן עניינים

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

  1. כותרת הפרק או הקטע
  2. מובילים (כלומר אותם נקודות, מקפים או קווים) המחברים חזותית את הכותרת למספר העמוד
  3. מספר העמוד

קל ליצור תוכן עניינים בתוך כלי עיבוד תמלילים כמו Microsoft Word או Google Docs, אבל מכיוון שהתוכן שלי היה ב-Markdown ולאחר מכן הומר ל-HTML, זו לא הייתה אפשרות טובה עבורי. רציתי משהו אוטומטי שיעבוד עם HTML כדי ליצור את תוכן העניינים בפורמט שמתאים להדפסה. רציתי גם שכל שורה תהיה קישור כך שניתן יהיה להשתמש בה בדפי אינטרנט ובקובצי PDF כדי לנווט ברחבי המסמך. רציתי גם מובילי נקודות בין הכותרת למספר העמוד.

וכך התחלתי לחקור.

נתקלתי בשני פוסטים מצוינים בבלוג על יצירת תוכן עניינים עם HTML ו-CSS. הראשון היה "בנה תוכן עניינים מה-HTML שלך" מאת ג'ולי בלאן. ג'ולי עבדה על PagedJS, polyfill עבור תכונות מדיה חסרות בדפדפני אינטרנט המעצב כראוי מסמכים להדפסה. התחלתי עם הדוגמה של ג'ולי, אבל גיליתי שזה לא ממש עבד בשבילי. לאחר מכן, מצאתי את Christoph Grabo's "קווים מנהיגים רספונסיביים של TOC עם CSS" פוסט, שהציג את הרעיון של שימוש ב-CSS Grid (בניגוד לגישה המבוססת על ציפה של ג'ולי) כדי להקל על היישור. שוב, עם זאת, הגישה שלו לא הייתה מתאימה בדיוק למטרות שלי.

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

בחירת הסימון הנכון

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

  • אפשרות אחת היא להשתמש בטבלה (<table>) עם עמודה אחת לכותרת ועמודה אחת לדף.
  • ואז יש את רשימת ההגדרות לעתים קרובות שאינה בשימוש ונשכחת (<dl>) אלמנט. היא פועלת גם כמפת מפתח-ערך. אז, שוב, הקשר בין הכותרת למספר העמוד יהיה ברור.

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

החלטתי להתבסס על הגישה של ג'ולי ולהשתמש ברשימה; עם זאת, בחרתי ברשימה מסודרת (<ol>) במקום רשימה לא מסודרת (<ul>). אני חושב שרשימה מסודרת מתאימה יותר במקרה הזה. תוכן עניינים מייצג רשימה של פרקים וכותרות משנה לפי סדר הופעתם בתוכן. הסדר חשוב ואסור ללכת לאיבוד בסימון.

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

להלן שלד HTML פשוט שיצר את הבסיס לסימון שלי:

<ol class="toc-list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol> <!-- subsection items --> </ol> </li>
</ol>

החלת סגנונות על תוכן העניינים

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

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

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

הנה ה-CSS שהגעתי אליו:

.toc-list, .toc-list ol { list-style-type: none;
} .toc-list { padding: 0;
} .toc-list ol { padding-inline-start: 2ch;
}

שרה סויידאן ציין בפניי שדפדפני WebKit מסירים סמנטיקה של רשימה כאשר list-style-type is noneאז הייתי צריך להוסיף role="list" לתוך ה-HTML כדי לשמר אותו:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>
CodePen Embed Fallback

עיצוב הכותרת ומספר העמוד

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

אולי אתה חושב, "אין בעיה, בשביל זה יש flexbox!" אתה לא טועה! Flexbox אכן יכול להשיג את היישור הנכון של עמוד השער. אבל יש כמה בעיות יישור מסובכות כאשר המנהיגים מתווספים, אז בחרתי במקום זאת ללכת עם הגישה של כריסטוף באמצעות רשת, שכבונוס היא גם עוזרת עם כותרות מרובות שורות. הנה ה-CSS עבור פריט בודד:

.toc-list li > a { text-decoration: none; display: grid; grid-template-columns: auto max-content; align-items: end;
} .toc-list li > a > .page { text-align: right;
}

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

השינוי הנוסף היחיד שעשיתי בשלב זה היה הסתרת הטקסט "דף". זה מועיל לקוראי מסך אבל מיותר מבחינה ויזואלית, אז השתמשתי ב-a מסורתי visually-hidden בכיתה כדי להסתיר את זה מהעין:

.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(100%); height: 1px; overflow: hidden; position: absolute; width: 1px; white-space: nowrap;
}

וכמובן, יש לעדכן את ה-HTML כדי להשתמש במחלקה הזו:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

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

CodePen Embed Fallback

יצירת מובילי נקודות

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

יש למעשה א leader() פונקציה המוגדרת ב תוכן שנוצר ב-CSS עבור מפרט מדיה דפדפת. עם זאת, כמו בחלק גדול ממפרטי המדיה המדפים, פונקציה זו אינה מיושמת באף דפדפן, ולכן אינה כוללת אותה כאופציה (לפחות בזמן שאני כותב זאת). זה אפילו לא רשום ב caniuse.com, ככל הנראה כי אף אחד לא יישם את זה ואין תוכניות או איתותים שיעשו זאת.

למרבה המזל, גם ג'ולי וגם כריסטוף כבר התייחסו לבעיה הזו בפוסטים שלהם. כדי להכניס את מובילי הנקודות, שניהם השתמשו ב-a ::after פסאודו-אלמנט עם שלו content מאפיין מוגדר למחרוזת ארוכה מאוד של נקודות, כך:

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .title::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

השמיים ::after pseudo-element מוגדר למיקום מוחלט כדי להוציא אותו מזרימת העמוד ולהימנע מגליפה לשורות אחרות. הטקסט מיושר לימין מכיוון שאנו רוצים שהנקודות האחרונות של כל שורה יהיו צמודות למספר שבסוף השורה. (עוד על המורכבות של זה מאוחר יותר.) .title אלמנט מוגדר למיקום יחסי כך שה ::after פסאודו-אלמנט אינו פורץ מהקופסה שלו. בינתיים, ה overflow מוסתר כך שכל הנקודות הנוספות האלה בלתי נראות. התוצאה היא תוכן עניינים יפה עם מובילי נקודות.

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

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

הפתרון הוא להכניס אלמנט נוסף עם aria-hidden מכוון ל true ולאחר מכן השתמש ברכיב זה כדי להכניס את הנקודות. אז ה-HTML הופך:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title<span class="leaders" aria-hidden="true"></span></span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

וה-CSS הופך:

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .leaders::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

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

CodePen Embed Fallback

נגיעות גימור

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

.toc-list > li > a { font-weight: bold; margin-block-start: 1em;
}

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

מספרים ונקודות לא מיושרים בתוכן העניינים.
תוכן עניינים מושלם עם HTML + CSS

כדי לתקן את הבעיה הזו, הגדרתי font-variant-numeric ל tabular-nums כך שכל המספרים מטופלים באותו רוחב. על ידי הגדרת הרוחב המינימלי ל 2ch, וידאתי שכל המספרים בעלי ספרה אחת או שתיים מיושרים בצורה מושלמת. (ייתכן שתרצה להגדיר זאת ל 3ch אם לפרויקט שלך יש יותר מ-100 עמודים.) הנה ה-CSS הסופי עבור מספר העמוד:

.toc-list li > a > .page { min-width: 2ch; font-variant-numeric: tabular-nums; text-align: right;
}
נקודות מובילות מיושרות בתוכן העניינים.
תוכן עניינים מושלם עם HTML + CSS

ובכך, תוכן העניינים הושלם!

CodePen Embed Fallback

סיכום

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

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


תוכן עניינים מושלם עם HTML + CSS פורסם במקור ב CSS-טריקים. אתה צריך לקבל את הניוזלטר.

בול זמן:

עוד מ טריקים של CSS