שורות טקסט ברוחב שווה

תכונות אינטרנט: text-fit text-wrap: balance text-box

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

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

הטמעה בסיסית

לשורות מאולצות:

  • צריך לעטוף כל שורה ב-<span> עם display: block.
  • מחילים את white-space: nowrap על כל שורה מאולצת <span>.

הנחיות להטמעה:

  • צריך להשתמש ב-text-fit: grow per-line-all <percentage> בכותרת עצמה.
  • צריך להשתמש ב-per-line-all, לא ב-per-line. הערך per-line מדלג על השורה האחרונה ועל כל שורה שמסתיימת במעבר שורה מאולץ, כך שאם יש בלוק אחד בכל שורה, הוא לא משנה את הגודל של שום דבר.
  • אי אפשר לשלב את grow עם shrink. אפשר להגדיר את font-size הבסיסי כערך מקסימלי או מינימלי, בהתאם למה שיהיה קל יותר לחשב או מה שיהיה חלופה טובה יותר, ולהגדיר את text-fit כ-shrink או grow בהתאם. אם אין לכם סיבה להשתמש ב-shrink, עדיף להשתמש ב-grow ולהגדיר את font-size למינימום, כי זה בטוח יותר ברוב המקרים.
  • תמיד צריך להגביל את ההגדלה או ההקטנה באמצעות האחוז (למשל 300%) כגבולות גזרה.
  • למאגר צריך להיות גודל מוגדר בשורה. text-fit אף פעם לא משנה את הגודל הפנימי, ולכן לא עושה כלום ברוחב של fit-content/max-content או בפריטי flex/grid בגודל התוכן.
  • חיתוך המרווח מעל השורה הראשונה ומתחת לשורה האחרונה: ראו יישור טקסט מדויק.
  • הערך של line-height צריך להיות קטן, 1 או פחות, אחרת הרווחים בין שורות בגדלי גופן שונים יהיו גדולים מדי.
  • חשוב: שימו לב שהערך המחושב של font-size לא משתנה, ולכן המרווחים של em לא משתנים בהתאם.
  • כדי למנוע הדגשת יתר של מילים בודדות בשורה, כדאי להשתמש ב-text-wrap: balance או ב-text-wrap: pretty אם יש שורות פנויות.

ריווח

אם כל השורות מאולצות, זה מאפשר שליטה רבה יותר על הריווח:

  • מחילים את text-box: trim-both cap alphabetic על כל בלוק של שורה כדי שהתיבה שלו תקיף את הגליפים שלו. הוא חותך את הנתונים לפי המדדים המותאמים. פרטים נוספים זמינים במאמר יישור טקסט מדויק.
  • כדי ליצור רווחים בין שורות, משתמשים ב-Flexbox או ב-Grid + gap בכותרת, ולא ב-line-height. כך המרווחים אחידים ולא גדלים עם גודל הגופן של כל שורה.

אם חלק מהשורות ריקות, אל תשתמשו ב-text-box: הוא חותך רק את השורה הראשונה והאחרונה, כך שהשורות החיצוניות יקיפו את הגליפים, אבל המרווחים הפנימיים ישמרו על המרווח בין השורות. הגדרת כל המרווחים באמצעות line-height.

עיצוב חזותי

  • הלוקאפים נראים הכי טוב כשיש הבדל משמעותי בגודל הגופן בין השורות. אל תיצרו לוקאפים מטקסט עם שורות אחידות ברובן, כי זה יגרום לגודלי גופנים שהם לא זהים ולא שונים מספיק, וזה מפר את עקרון העיצוב של ניגודיות. כדי לעשות את זה, אפשר לאלץ שורות קצרות: להציג את המילים שרוצים להדגיש בשורה נפרדת, ואת שאר המילים בשורה אחרת. זה חשוב במיוחד כשמשלבים את זה עם text-wrap: balance.
  • עדיף לשלב את זה עם text-transform: uppercase כשמשתמשים בכתב מערבי, כי אותיות עם קווים עולים ויורדים נוטות ליצור רווחים כלואים או לחפוף לשורות סמוכות, מה שיוצר תוצאה פחות אסתטית.
  • כשמאלצים שורות קצרות, כדאי לבחור מילים שישפרו את המסר אם ידגישו אותן.
  • מגבלה: הגדלת הטקסט תגדיל גם את המשקל החזותי שלו, והקווים שלו ייראו עבים יותר. כרגע אין דרך לאזן את זה, למשל על ידי הפחתת font-weight לטקסט גדול יותר, כי אין יחידה לשימוש בחישוב, כי קנה המידה לא משפיע על יחידות שקשורות לגופן כמו em.

אסטרטגיות חלופיות

של text-box

ל-text-box אין צורך ב-fallback נפרד: צריך להשאיר את ה-line-height הקטן גם ב-lockups קבועים. היא לא פועלת ב-text-box ושומרת על מרווחים קטנים במקומות שבהם היא לא נתמכת, על חשבון מרווחים שמשתנים בהתאם לגודל הגופן של כל שורה.

של text-wrap: balance

של text-fit

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

@supports not (text-fit: grow) {
  .lockup > span {
    /* Shrink-wrap each line so its width is the text width */
    width: fit-content;
    /* --text-fit-scale is measured by the script; the cap mirrors the text-fit percentage */
    font-size: min(var(--text-fit-scale, 1) * 1em, 300%);
  }
}
if (!CSS.supports('text-fit', 'grow per-line-all')) {
  const fit = lockup => {
    const lines = [...lockup.querySelectorAll(':scope > span')];
    // Unscale first: on a refit, offsetWidth would otherwise include the previous scale
    for (const line of lines) line.style.removeProperty('--text-fit-scale');
    // MANDATORY: all reads, then all writes. Interleaving them (e.g. reading
    // lockup.clientWidth inside the write loop) forces one reflow per line.
    const scales = lines.map(line => lockup.clientWidth / line.offsetWidth);
    lines.forEach((line, i) => line.style.setProperty('--text-fit-scale', scales[i]));
  };
  // Refit on resize and font load
  for (const lockup of document.querySelectorAll('.lockup')) {
    new ResizeObserver(() => fit(lockup)).observe(lockup);
  }
}

לשורות חופשיות אין חלופה נאמנה (מעברי שורה לא ידועים עד לפריסה): שיפור הדרגתי (progressive enhancement) לכותרת מאוזנת עם גודל בסיס גמיש כמו clamp(2rem, 1rem + 5cqi, 5rem). במקבץ מעורב, הסקריפט שלמעלה עדיין מתאים לשורות המאולצות. בלוק גלישה נמדד לפי רוחב הקונטיינר, כך שהוא שומר על קנה מידה 1 ומקבל רק את גודל הבסיס הנוזלי.

אם התאמת הטקסט היא קריטית, כדאי להשתמש בספריית JS (למשל fitty), שנטענת באופן מותנה רק אם אין תמיכה ב-text-fit.