Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      CodeSOD: A Unique Way to Primary Key

      July 22, 2025

      BrowserStack launches Figma plugin for detecting accessibility issues in design phase

      July 22, 2025

      Parasoft brings agentic AI to service virtualization in latest release

      July 22, 2025

      Node.js vs. Python for Backend: 7 Reasons C-Level Leaders Choose Node.js Talent

      July 21, 2025

      The best CRM software with email marketing in 2025: Expert tested and reviewed

      July 22, 2025

      This multi-port car charger can power 4 gadgets at once – and it’s surprisingly cheap

      July 22, 2025

      I’m a wearables editor and here are the 7 Pixel Watch 4 rumors I’m most curious about

      July 22, 2025

      8 ways I quickly leveled up my Linux skills – and you can too

      July 22, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025
      Recent

      The Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025

      Zero Trust & Cybersecurity Mesh: Your Org’s Survival Guide

      July 22, 2025

      Execute Ping Commands and Get Back Structured Data in PHP

      July 22, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025
      Recent

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025

      “I don’t think I changed his mind” — NVIDIA CEO comments on H20 AI GPU sales resuming in China following a meeting with President Trump

      July 22, 2025

      Galaxy Z Fold 7 review: Six years later — Samsung finally cracks the foldable code

      July 22, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»Setting Line Length in CSS (and Fitting Text to a Container)

    Setting Line Length in CSS (and Fitting Text to a Container)

    July 14, 2025

    First, what is line length? Line length is the length of a container that holds a body of multi-line text. “Multi-line” is the key part here, because text becomes less readable if the beginning of a line of text is too far away from the end of the prior line of text. This causes users to reread lines by mistake, and generally get lost while reading.

    Luckily, the Web Content Accessibility Guidelines (WCAG) gives us a pretty hard rule to follow: no more than 80 characters on a line (40 if the language is Chinese, Japanese, or Korean), which is super easy to implement using character (ch) units:

    width: 80ch;

    The width of 1ch is equal to the width of the number 0 in your chosen font, so the exact width depends on the font.

    Setting the optimal line length

    Just because you’re allowed up to 80 characters on a line, it doesn’t mean that you have to aim for that number. A study by the Baymard Institute revealed that a line length of 50-75 characters is the optimal length — this takes into consideration that smaller line lengths mean more lines and, therefore, more opportunities for users to make reading mistakes.

    That being said, we also have responsive design to think about, so setting a minimum width (e.g., min-width: 50ch) isn’t a good idea because you’re unlikely to fit 50 characters on a line with, for example, a screen/window size that is 320 pixels wide. So, there’s a bit of nuance involved, and the best way to handle that is by combining the clamp() and min() functions:

    • clamp(): Set a fluid value that’s relative to a container using percentage, viewport, or container query units, but with minimum and maximum constraints.
    • min(): Set the smallest value from a list of comma-separated values.

    Let’s start with min(). One of the arguments is 93.75vw. Assuming that the container extends across the whole viewport, this’d equal 300px when the viewport width is 320px (allowing for 20px of spacing to be distributed as you see fit) and 1350px when the viewport width is 1440px. However, for as long as the other argument (50ch) is the smallest of the two values, that’s the value that min() will resolve to.

    min(93.75vw, 50ch);

    Next is clamp(), which accepts three arguments in the following order: the minimum, preferred, and maximum values. This is how we’ll set the line length.

    For the minimum, you’d plug in your min() function, which sets the 50ch line length but only conditionally. For the maximum, I suggest 75ch, as mentioned before. The preferred value is totally up to you — this will be the width of your container when not hitting the minimum or maximum.

    width: clamp(min(93.75vw, 50ch), 70vw, 75ch);

    In addition, you can use min(), max(), and calc() in any of those arguments to add further nuance.

    If the container feels too narrow, then the font-size might be too large. If it feels too wide, then the font-size might be too small.

    Fit text to container (with JavaScript)

    You know that design trend where text is made to fit the width of a container? Typically, to utilize as much of the available space as possible? You’ll often see it applied to headings on marketing pages and blog posts. Well, Chris wrote about it back in 2018, rounding up several ways to achieve the effect with JavaScript or jQuery, unfortunately with limitations. However, the ending reveals that you can just use SVG as long as you know the viewBox values, and I actually have a trick for getting them.

    Although it still requires 3-5 lines of JavaScript, it’s the shortest method I’ve found. It also slides into HTML and CSS perfectly, particularly since the SVG inherits many CSS properties (including the color, thanks to fill: currentColor):

    CodePen Embed Fallback
    <h1 class="container">
      <svg>
        <text>Fit text to container</text>
      </svg>
    </h1>
    h1.container {
      /* Container size */
      width: 100%;
    
      /* Type styles (<text> will inherit most of them) */
      font: 900 1em system-ui;
      color: hsl(43 74% 3%);
    
      text {
        /*
          We have to use fill: instead of color: here
          But we can use currentColor to inherit the color
        */
        fill: currentColor;
      }
    }
    /* Select all SVGs */
    const svg = document.querySelectorAll("svg");
    
    /* Loop all SVGs */
    svg.forEach(element => {
      /* Get bounding box of <text> element */
      const bbox = element.querySelector("text").getBBox();
      /* Apply bounding box values to SVG element as viewBox */
      element.setAttribute("viewBox", [bbox.x, bbox.y, bbox.width, bbox.height].join(" "));
    });

    Fit text to container (pure CSS)

    If you’re hell-bent on a pure-CSS method, you are in luck. However, despite the insane things that we can do with CSS these days, Roman Komarov’s fit-to-width hack is a bit complicated (albeit rather impressive). Here’s the gist of it:

    • The text is duplicated a couple of times (although hidden accessibly with aria-hidden and hidden literally with visibility: hidden) so that we can do math with the hidden ones, and then apply the result to the visible one.
    • Using container queries/container query units, the math involves dividing the inline size of the text by the inline size of the container to get a scaling factor, which we then use on the visible text’s font-size to make it grow or shrink.
    • To make the scaling factor unitless, we use the tan(atan2()) type-casting trick.
    • Certain custom properties must be registered using the @property at-rule (otherwise they don’t work as intended).
    • The final font-size value utilizes clamp() to set minimum and maximum font sizes, but these are optional.
    <span class="text-fit">
      <span>
        <span class="text-fit">
          <span><span>fit-to-width text</span></span>
          <span aria-hidden="true">fit-to-width text</span>
        </span>
      </span>
      <span aria-hidden="true">fit-to-width text</span>
    </span>
    .text-fit {
      display: flex;
      container-type: inline-size;
    
      --captured-length: initial;
      --support-sentinel: var(--captured-length, 9999px);
    
      & > [aria-hidden] {
        visibility: hidden;
      }
    
      & > :not([aria-hidden]) {
        flex-grow: 1;
        container-type: inline-size;
    
        --captured-length: 100cqi;
        --available-space: var(--captured-length);
    
        & > * {
          --support-sentinel: inherit;
          --captured-length: 100cqi;
          --ratio: tan(
            atan2(
              var(--available-space),
              var(--available-space) - var(--captured-length)
            )
          );
          --font-size: clamp(
            1em,
            1em * var(--ratio),
            var(--max-font-size, infinity * 1px) - var(--support-sentinel)
          );
          inline-size: var(--available-space);
    
          &:not(.text-fit) {
            display: block;
            font-size: var(--font-size);
    
            @container (inline-size > 0) {
              white-space: nowrap;
            }
          }
    
          /* Necessary for variable fonts that use optical sizing */
          &.text-fit {
            --captured-length2: var(--font-size);
            font-variation-settings: "opsz" tan(atan2(var(--captured-length2), 1px));
          }
        }
      }
    }
    
    @property --captured-length {
      syntax: "<length>";
      initial-value: 0px;
      inherits: true;
    }
    
    @property --captured-length2 {
      syntax: "<length>";
      initial-value: 0px;
      inherits: true;
    }
    CodePen Embed Fallback

    Watch for new text-grow/text-shrink properties

    To make fitting text to a container possible in just one line of CSS, a number of solutions have been discussed. The favored solution seems to be two new text-grow and text-shrink properties. Personally, I don’t think we need two different properties. In fact, I prefer the simpler alternative, font-size: fit-width, but since text-grow and text-shrink are already on the table (Chrome intends to prototype and you can track it), let’s take a look at how they could work.

    The first thing that you need to know is that, as proposed, the text-grow and text-shrink properties can apply to multiple lines of wrapped text within a container, and that’s huge because we can’t do that with my JavaScript technique or Roman’s CSS technique (where each line needs to have its own container).

    Both have the same syntax, and you’ll need to use both if you want to allow both growing and shrinking:

    text-grow: <fit-target> <fit-method>? <length>?;
    text-shrink: <fit-target> <fit-method>? <length>?;
    • <fit-target>
      • per-line: For text-grow, lines of text shorter than the container will grow to fit it. For text-shrink, lines of text longer than the container will shrink to fit it.
      • consistent: For text-grow, the shortest line will grow to fit the container while all other lines grow by the same scaling factor. For text-shrink, the longest line will shrink to fit the container while all other lines shrink by the same scaling factor.
    • <fit-method> (optional)
      • scale: Scale the glyphs instead of changing the font-size.
      • scale-inline: Scale the glyphs instead of changing the font-size, but only horizontally.
      • font-size: Grow or shrink the font size accordingly. (I don’t know what the default value would be, but I imagine this would be it.)
      • letter-spacing: The letter spacing will grow/shrink instead of the font-size.
    • <length> (optional): The maximum font size for text-grow or minimum font size for text-shrink.

    Again, I think I prefer the font-size: fit-width approach as this would grow and shrink all lines to fit the container in just one line of CSS. The above proposal does way more than I want it to, and there are already a number of roadblocks to overcome (many of which are accessibility-related). That’s just me, though, and I’d be curious to know your thoughts in the comments.

    Conclusion

    It’s easier to set line length with CSS now than it was a few years ago. Now we have character units, clamp() and min() (and max() and calc() if you wanted to throw those in too), and wacky things that we can do with SVGs and CSS to fit text to a container. It does look like text-grow and text-shrink (or an equivalent solution) are what we truly need though, at least in some scenarios.

    Until we get there, this is a good time to weigh-in, which you can do by adding your feedback, tests, and use-cases to the GitHub issue.


    Setting Line Length in CSS (and Fitting Text to a Container) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleHello Robo’s Rebrand: Distilling Complex Tech Into Interfaces Anyone Can Use
    Next Article The art of cutting Test Maintenance in Half Welcome AI-Driven Performance Testing

    Related Posts

    News & Updates

    The best CRM software with email marketing in 2025: Expert tested and reviewed

    July 22, 2025
    News & Updates

    This multi-port car charger can power 4 gadgets at once – and it’s surprisingly cheap

    July 22, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Finally, an Android tablet that I wouldn’t mind putting my iPad Pro away for

    News & Updates

    CVE-2025-3527 – WordPress EventON Pro Stored Cross-Site Scripting (XSS)

    Common Vulnerabilities and Exposures (CVEs)

    ASUS Urges Windows 11 Upgrade: The Dawn of AI-Powered PCs and the End of Windows 10

    Security

    InstallAware releases flexible installer source code under BSL

    Tech & Work

    Highlights

    CVE-2025-47585 – Mage People Team Booking and Rental Manager Missing Authorization Vulnerability

    June 2, 2025

    CVE ID : CVE-2025-47585

    Published : June 2, 2025, 8:15 p.m. | 3 hours, 10 minutes ago

    Description : Missing Authorization vulnerability in Mage people team Booking and Rental Manager allows Accessing Functionality Not Properly Constrained by ACLs.This issue affects Booking and Rental Manager: from n/a through 2.3.8.

    Severity: 6.5 | MEDIUM

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    CVE-2025-49258 – ThemBay Maia PHP Remote File Inclusion Vulnerability

    June 17, 2025

    Sam Altman doesn’t want his son to have an AI “bestie” — as Microsoft plans to turn Copilot into an AI friend and companion

    May 12, 2025

    KB5002700 crashes Office 2016 Word, Excel, Outlook on Windows

    April 9, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.