Submind YouTube summaries
Thumbnail for Fixing fluid typography

Fixing fluid typography

Watch on YouTube

Video summary

Fluid typography is a persistent trend in web design that offers dynamic scaling based on viewport size, yet it often encounters issues when content containers reach their maximum dimensions. The primary problem arises when text continues to grow even after its container has stopped expanding, creating an awkward visual effect where the font size exceeds the available space. This occurs because standard clamp functions rely on the viewport width rather than the specific container's size. To resolve this, developers can utilize container query units, which allow elements to scale relative to their immediate parent container instead of the entire screen. By explicitly defining a wrapper element as a container, the typography system correctly references that specific boundary, ensuring that font sizes stop growing precisely when the wrapper hits its limit, thus maintaining a clean and proportional layout. However, implementing container queries across multiple nested elements introduces a new challenge regarding consistency. When different containers within a layout are defined as separate query scopes, declaring identical font size rules for each can result in inconsistent visual weights, which often causes anxiety among design system practitioners who prefer uniformity. For instance, if cards inside a wrapper are also defined as individual containers, they might calculate their own sizes independently, leading to mismatched typography even when the same CSS declaration is used. To address this inconsistency without sacrificing the benefits of container queries, the video introduces the use of registered custom properties via the `@property` rule. This approach allows developers to define a specific type for a property, such as a length, which ensures that the browser computes and stores a precise numerical value rather than treating it as a raw string or unitless number. The solution involves registering a custom property with an initial value and setting inheritance to true, enabling the system to dynamically compute the correct font size based on the specific container context while maintaining visual consistency across different levels of the hierarchy. When a child element redeclares this registered property, the browser recognizes it as a computed length derived from the parent's container query units, effectively synchronizing the scaling behavior across the entire layout. This method allows for granular control where specific containers can override the default behavior if needed, while still inheriting the correct calculated values elsewhere. Although the syntax requires an extra step of registration and careful handling of inheritance rules, it provides a robust way to ensure that fluid typography remains both responsive to container changes and visually consistent throughout complex, multi-container layouts.
Read the full video transcript
Hello, my friend and friends. Fluid typography on the web is something I really like. I know not everyone's a huge fan of it, but I think it's here to stay even if you're not the biggest fan of it, but there's some problems that can come up when we're using it that I think I found a fix for. Let's look at the first problem here is that as this is getting bigger, my font size continues to grow even though I don't necessarily want it to. The reason I don't want it to is because my wrapper here that I have has hit a maximum size, so the space these cards are living in in the title is living in isn't getting any bigger, but the text is still getting bigger through this like squishy zone over here. And the reason that's happening is because I'm using a clamp to set a maximum size, but it's based on the viewport size. And because it's looking at the viewport inline, which is the logical property for viewport width, because it's looking at the viewport, it's saying, "Well, the viewport continues to get bigger. I haven't hit my maximum value yet, so it sort of it just keeps on getting bigger and it's kind of ugly." The solution here is one I've talked about before, which is to use container query inline instead cuz container units can see their container sizes. People don't like this. We'll get to why they don't like this and then we'll get to the fix. But even before we talk about that, this hasn't actually fixed anything yet because if I take a look here, right now it's it's doing the exact same thing where we still have this squishy zone over here when my container hits its maximum size. And the reason that's happening is because I when you switch to container query units, unless you have a defined container, they just look at the viewport anyway. So, the very first thing I'd have to do is to grab in this case my wrapper and say that my wrapper is a container. And this is why I don't like the container name for wrappers anymore. I use wrapper cuz we have containers that are part of the container query spec and all of that. And then if you have a dot container that's then I don't know. It all gets weird. Name things however you want. I call them wrappers and So, wrapper is now a container with the name of wrapper. Uh but regardless of all of that and however we're naming things, now anything that's inside of my wrapper will be looking at the size of the wrapper for its container query inline size, which means we've now fixed that first problem. And we can see that when we hit that and my wrapper gets to its maximum size right there, the font sizes all stop growing, which to me makes a lot more sense than them getting bigger and bigger and bigger even though their space they're in doesn't continue to grow. So, I like this and this works pretty well. And if this is all you're doing, you might not run into any more problems. But, now that we have containers, you might be using them in multiple places. For example, I have those cards that I had here and now I've sort of changed the layout. Before they were stacked and now they're going next to each other. And if I shrink this down, it's going to break the layout cuz I do want them to stack at one point where we have overflow. Oh my goodness, they get all the way down here and then they stack. Uh and so ideally, what I would be doing is actually using an at container to look at the size available and have the cards stack at you know when when they reach too small of a size. The problem is right now my only defined container is the wrapper, which is the entire layout. I want them to look at their individual card sizes instead. So, now what I can do is say that my card is also a container. I fixed my layout issues. We can see now that's actually working and they'll stack and and grow and it works the way I want it to. But, the problem is now look at the inconsistent font sizes that come up. And this is the problem most people have with container query units uh for font sizes is it quickly leads to this type of problem. And it is kind of weird that we have the same declaration on all three of them and the font sizes are different in all three places. A lot of people don't like this and I understand why, especially like design system people. This This I think gives them anxiety looking at this type of inconsistency we have that is going on here right now. But, there is a potential fix for this type of thing now, as well, which is using @property. But, before I get into how this works, I just want to say a very big thank you to Ana Tudor. I'm going to link to an article she put out a little while ago that I didn't know about until recently, uh down in the description, that is what gave me the idea for this solution. And that's because with @property, we can register custom properties, but it saves their values in a different way than unregistered custom properties do. So, if you're not used to @property, the first thing we need to do is give it a name, the same way you would name any custom property that you're doing. So, my step two, exactly the same as I had before. But, with this, we do need three things. We need to have in syntax, initial value, and whether or not it inherits. The syntax, just look up what you want. In this case, I'd want it to be a length. Also, the syntax highlighting here is weird. Syntax highlighting with @property, still triangle brackets in CSS, it it it tends to look weird in a lot of places that do syntax highlighting, but this is completely valid. It works in all browsers. Has very good support right now. So, my syntax is my length, and the reason I'm doing a length is because my initial value is going to be 1 rem. I would just have something here that's a valid font size. But, if it's not just a number, like number would be 10, right? Unitless number. But, if I want it to be rem or pixels or anything like that, that's actually a length. And whether or not it inherits, in this case, I don't think it matters, though I do think inherits true No, I'm going to go back on that. I think you really do want this to inherit, cuz you If something is set on that, you want it to also be able to be set on its children. There are times where inherits false is actually pretty good. I'll link to a video in the description about one of those use cases uh that I came across, where you actually want inherits to be false, and it makes life a lot easier. But yeah, once we've set this up, we've now registered this custom property, and that means that, well, I can have my step two declared like this, I can then do something like this. And this is re-declaring the the step two as the same thing that I have here. And this might seem a little bit weird, but the reason this is working is because it's a registered custom property. If we go back quickly, it knows that it's a length. So, it knows it's going to be getting an actual like computed number value here. So, because it knows that, knows it's a computed length, it's actually going to compute this length and save that number. And then we're doing the same thing here. We're going to compute this length and we're going to save that number. I am doing this on the children of my wrapper. And this is important as well, because what it's doing is because I need it to look at the size of the wrapper itself. So, as the wrapper is changing, it's going to continue to compute that number. But unlike a regular custom property that we just redeclare like this value over and over again, it's getting the calculated value of this and saving that as my step two. And again, that value can change as the viewport or as the container size is changing, but it's always going to be that final result. So, by taking that extra step of registering the custom property and then setting this up where we're sort of redefining step two right here, that means now all of our font sizes are consistent. I have my container queries still set up. So, as this shrinks down, we can see that my layout is snapping and changing over here. Uh but all three of those font sizes are computing to the same value, which is based on the container size of the wrapper. And it's not looking at the container size of the container that we're in right here. And it's a little bit weird, but we've now sort of defined which container we're going to be looking at for the container query units. And this is what's so cool. That's what Anna was talking about just with a different use case in her blog post that she wrote. Uh so yeah, super useful to do this. And again, that means that step two is now defined and set to this wrapper. Uh but it's kind of weird like redeclaring things like this. And sometimes you might also want to go back to the initial one, right? You might be like, "Oh, I don't want to be using this one for whatever reason. Like, I need to reset this along the way." So, the way that we can do that is actually to change this to like a step to reset, or you might have to declare it twice. You'd have your step two in your root and your step two reset. And this is where it's a little bit weird, but this would be an on-registered custom property. And by being an on-registered custom property, it means this isn't getting a computed value. It's just saving this entire string as a value right there. And that means we could do something like this, where I mean, it makes it a little bit easier to declare it instead of doing the entire declaration every single time. And so, like, really quickly, this is working exactly as it was working before. We haven't actually made a change at this point. But, what this means is not only can we have it set here, if you did need it to really be a container query unit for that specific container, where you can do that, where my wrapper can set step two, and then I can also then go on my card, where I have a container, I can redeclare what step two is, and then it's going to be set for the card. And remember I said inherits true being on is good. And the reason for that is I'm only declaring this on the direct children of my wrapper, but then that value would inherit into anywhere that's using it. Uh the same way here, then my card, we've reset it, but then it's going to inherit into all of its children as well. And so, with this reset on the cards now, we can see we have the inconsistent sizing that has come back there. Not something I'd want, and if you always want this to happen, I wouldn't go through all this trouble of registering it in the first place. And so, like, this probably isn't the best use case for how you would actually use the reset, but I wanted to show that it was something that was actually possible. Uh I think there's a lot of different ways and interesting ways that we could do something like this, and I hope you like this trick. It's a little bit of a weird one. Takes a bit of time for your mind to wrap around it, but I think it could be really useful. So, I do hope that you enjoyed this video. Uh if you want the one where I looked at why you'd want inherits false, the video is right here for your viewing pleasure and linked down in the description. And with that I'm going to say a very big thank you to my enabler of awesome Johnny as well as all my other patrons and channel members for their continued support. And of course, until next time, don't forget to make your corner of the internet just a little bit more awesome.