External Publication
Visit Post

Two Typographic Tricks

Donnie D'Amato December 19, 2024
Source
I’ve been writing CSS for a long time and it’s really exciting to see the fast improvements to the language that we’ve received over that time. In this post, I’ll demonstrate two ideas that I always wanted to do natively with CSS alone. First, a warm-up before we get to the wild stuff. Grid centered line-height I know of plenty of designers who want to maintain a vertical rhythm for all content on the page. They’ll painstakingly adjust border widths and line-heights to ensure all of the little elements on the page align to some vertical grid such that there’s a rhythm to reading downward. As the person who wrote Gridless Design, you can imagine how I feel about this. In my opinion, the time spent trying to get this alignment would be more worthwhile on other things; say… improving the user experience as an example. However, now that we have some new CSS in browsers, getting the vertical rhythm to align with your grid can happen at any font size very easily. We’re going to need a bit of math for this. Let’s say that you have an grid. This means elements on your composition should be sized in multiples of . Let’s also say that your for paragraphs should be , meaning the resulting height of each line should be 1.4 times the size of the font so the space between lines helps readability. If your paragraph font is , this means the paragraph would result in each line of text being high. 18∗1.4\=25.218\1.4=25.218∗1.4\=25.2 Clearly, this doesn’t align to our grid. Historically, we’d curate the each time we introduce a new . In this case, we have to hardcode the knowing the such that it remains on the grid. Rounding to the nearest grid In order to determine the correct number here, we’ll need to round 25.2 to the nearest 8. Doing this in JavaScript would look like this, assuming the numbers are entered without units: The messy part is rounding to the nearest grid unit. We have to divide 25.2 by 8, then round that to the nearest integer and then multiply by 8 to get 32. This means that the should be set as when the font size is and the target line height is . As you can see, this is very cumbersome. We’d need to know the exact value, the grid unit, and the target for this kind of element to determine the final result. Luckily, the new CSS function can really help us out. This is effectively the same calculation that was demonstrated earlier in JavaScript. The function is fairly well supported and can take three arguments: The first can determine the rounding strategy, in this case we want to round up in the same way we used before. The next argument is the number we’re going to be rounding. This will represent the target ; basically the minimum allowed. Unfortunately, we can’t use the unitless here but we can use the version instead which would result in the same final pixel amount. Finally, the amount to round by. This part of the function is awesome. It avoids all of the weird division and multiplication to round by an amount in the JavaScript. Here, we want to round to the nearest grid unit. In this example, I simply set the default as in the second argument of the , and then it can accept any update in the page and fallback to . You can also use any value with units here instead. You’ll also notice I’m not explicitly setting the here. This is because this value will respect whatever this element is because it’s referencing units, even if it is inherited from a parent! If your target is meant to be tighter, as is normally the case for headings, you can adjust the target to be smaller like . Here is a codepen demonstrating the technique. The gray lines behind the text represent the grid unit intervals and the red background on the text shows how much space the text takes up. You’ll see that the gray lines will never be cut-off at the bottom of the container because the for this element is always on grid. The span is not important to the CSS, it’s there just to visualize the height of the text. See the Pen Line Height on grid by Donnie D’Amato (@fauxserious) on CodePen. Ok, that was a good warm-up. Now it’s time to get wild! Dynamic letter-spacing Like , I always felt that tweaking the was a waste of time. Especially as more custom fonts become normal, I felt setting the should be embedded in the font file itself. However, I saw a post by Mathieu Badimon, formerly leading efforts for the design system at Adobe, sharing a way to do this dynamically. The gist is that he’s developed a scale where the of the text will get tighter as the increases. Immediately, I wanted to try to do this in CSS alone. This took much longer than I hoped. The easy parts The first thing is that there is an upper and lower limit. This is pretty easy in CSS today using the function. So we’ll start with that using the values he recommends in the post; Sizes and below should be and for sizes above about . Since, doesn’t accept units, we’ll use instead which can be thought of as a percent of the . Remember that the lowest value goes first, that’s why is first and is last. Ok, so far so good. Now all we need is the rate of change. You’ll see that there’s a graph included in his post, but he mentions that the graph is actually inaccurate. That’s fine, we’re going to use the numbers he provided later in a comment. What we want is the rate of change between to points, this can be thought of as finding the slope of a line between points. If we think of the as the and the resulting percent as , we can find the slope () in the following way: m\=(y2−y1)/(x2−x1)m=(y\2-y\1)/(x\2-x\1)m\=(y2​−y1​)/(x2​−x1​) Plugging in some numbers from the chart, we get the following: m\=(28−25)/(−.1−0)\=−30m=(28-25)/(-.1-0)=-30m\=(28−25)/(−.1−0)\=−30 This shouldn’t be a surprise from Mathieu’s post: The is related to the every decrease. The next thing we need is the formula that produces all of the values based on a given . You might remember this formula from school: y\=mx+by=mx+by\=mx+b However, we want to solve for , so we need to rearrange the terms: x\=(y−b)/mx=(y-b)/mx\=(y−b)/m In this formula, is our , and is the slope we got earlier of . So what does represent? It’s where the slope crosses the x-axis. We could find this by moving terms around again, but Mathieu has already provided this number; (for where this calculation starts). Our formula now looks like this: percent\=(fontsize−25)/−30percent=(fontsize-25)/-30percent\=(fontsize−25)/−30 This doesn’t look too intimidating yet, but here’s where it get challenging. We need to turn this into CSS. Let’s try just making some variables for this first: Ok, so far all of this should work. We’re still missing the assignment but we can subtract unit values from each other, and we can divide a unit number by an unitless number. When we subtract units like this, the result is resolved into a pixel amount. This’ll be important later. The hard parts We’re about to begin using super new CSS properties in a very hacky way. Consider yourself warned. The first problem is that isn’t a unitless value, it’s a pixel amount. Setting this as the isn’t correct because in Mathieu’s formula, we want a percent of the . So we want to have the pixel units removed. There’s a recent trick made popular by Jane Ori which demonstrates how we might hack CSS to give us unitless values using . We’ll need to add a few things: The first thing we need is to effectively force the to give us a pixel amount. It might seem weird that we need to do this since we know it’s resolving as a pixel, but it’ll be important so we can use . You’ll see I’ve added the variable by using the approach in the blog post. You can essentially look at this as returning in terms of and return the unitless result. What we have will work, but there’s one small problem. I’ve explicitly set here which is assuming base font size as a fixed pixel amount. Entering in here doesn’t work (and admittedly I’m not entirely sure why even when updating the defaults). What we’ll need is in terms of pixels. Luckily, Jane has that example in her post. We’ll use another to get the unitless* number of pixels per () and expect to replace the with this result. This actually needs a number with a pixel unit so we can do that quickly by multiplying the unitless result of the new by to finally resolve to . Here’s the whole working declaration, followed by the codepen: See the Pen Dynamic letter spacing test by Donnie D’Amato (@fauxserious) on CodePen. I do wonder if there’s a setup that allows us to remove the second usage and insert the directly here but I haven’t found it yet. Whew, what a ride! Maybe one day, we’ll get a supported way of dividing values with units to return a unitless value. But for now, we can wish upon this proof-of-concept. Thanks to Mathieu and Jane for their resources!

Discussion in the ATmosphere

Loading comments...