Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a default line height #14503

Open
wants to merge 2 commits into
base: next
Choose a base branch
from

Conversation

MartijnCuppens
Copy link
Contributor

This is a slimmer version of #14335, which only includes the default line heights & the <small> fix.

In this PR:

  • Fixed line heights are replaced by a default line height css function.
  • This removes the need of adding fixed line heights to each font size.
  • It's still possible to use fixed line heights the way it worked before.
  • Custom font sizes will now have a better line height by default. For example, text-[2.4rem] will have a calculated line height of 2.625rem, instead of 3.6rem.
  • The default values are calculated in CSS, which means you can use arbitrary values in combination with custom properties (eg text-[length:var(--title-font-size)]).
  • Relative font sizes like text-[1.5em] or text-[larger] will now use a recalculated line height.
  • Only breaking change is the line height of lg (also see Change line height of the lg font size to 1.625rem #14223).
  • The line heights are always rounded to even pixels (2px), so that you never have vertical alignment issues. Even if you use viewport relative units.

Here's have an overview of which line height will be used for each font size range:

Font size range Line height
0rem - .5rem * 1em
.5rem - 1rem 2em - .5rem
1rem - 2rem 1em + .5rem
2rem - 3rem 2em / 3 + 1rem
3rem 1em

* These font sizes are not used in Tailwind by default

Closes #14484, #14223

@adamwathan
Copy link
Member

Hey revisiting this again! The biggest blockers for me still are two things:

  1. I have no idea what happens when I change the numbers in the formula (round(max(min(2em - .5rem, 1em + .5rem, 2em / 3 + 1rem), 1em), 2px) — do you have any idea how we can get these to feel like labelled knobs that actually have an intuitive effect? It feels very opaque right now.
  2. I'm worried about any potential performance impact of making the browser do all this math on every text element.

What are your thoughts?

@MartijnCuppens
Copy link
Contributor Author

MartijnCuppens commented Nov 7, 2024

Good feedback. I was looking at some alternative approaches, and maybe min(2em - .5rem, 1em + .5rem) can be an interesting option. This approach yields even line heights without needing the round() trick.

The only downside is that it does change more line heights for larger font sizes (although you can still set the --text-*--line-height if you notice this causes issues when upgrading from v3 to v4):

  Current line height (rem) min(2em - .5rem, 1em + .5rem) (rem)
text-xs 1 1
text-sm 1.25 1.25
text-base 1.5 1.5
text-lg 1.75 1.625
text-xl 1.75 1.75
text-2xl 2 2
text-3xl 2.25 2.375
text-4xl 2.5 2.75
text-5xl 3 3.5
text-6xl 3.75 4.25
text-7xl 4.5 5
text-8xl 6 6.5
text-9xl 8 8.5

Performance

To be honest, I'm not sure about the performance impact or even the best way to benchmark it. My intuition is that the function simply calculates a number, which likely isn't any more complex than the approach we're using with color-mix() to adjust background opacity.


I also noticed the main titles on the homepage of commit, pocket, salient, spotlight, studio & syntax actually follow the logic of 1em + .5rem (or are close (+-1px) to following it).

What do you think about the simplified line height function?

@MartijnCuppens MartijnCuppens requested a review from a team as a code owner November 7, 2024 20:19
@MartijnCuppens
Copy link
Contributor Author

What if we just use calc(1em + .5rem) for all the line heights and still keep --text-xs--line-height and --text-sm--line-height? This will be:

  • easy to understand than the functions mentioned earlier.
  • easy for designers to pick a line height when choosing a custom font size like 2.5rem, because it's just +.5rem.

And all the upsides mentioned in the PR description.

@MartijnCuppens
Copy link
Contributor Author

MartijnCuppens commented Nov 11, 2024

If we go that way, it might be worth changing the named leading classes. Right now, they often generate odd numbers or decimals:
image

If we change them to calc(1em + .25rem), calc(1em + .375rem), calc(1em + .5rem), calc(1em + .625rem) & calc(1em + 1rem) we can force even numbers and "adaptive line heights based on font size".

It can also make designing (or converting a design into code) a little easier since there is now an easy to remember relation between font sizes & line heights:
Thight: font size + 4px
Snug: Font size + 6px
Normal (& default): font size + 8px
Relaxed: font size + 10px
Loose: font size + 16px

This does introduce some breaking changes (just like the v1->v2 upgrade), which can be reverted by using the old config.

@adamwathan
Copy link
Member

adamwathan commented Nov 11, 2024

@MartijnCuppens Sorry I don't think I was clear enough in my original message — what I'm wondering I guess is if this formula can be written in a way where you could give each number a variable name and it would actually be understandable:

min(2em - .5rem, 1em + .5rem)

What is 2em here? What is 0.5rem? What happens if I change them? Those are the things that I wish we could figure out.

Would be awesome to land on something we feel good about here though because I agree it would be really great to get nice automatic line heights even for arbitrary values.

@MartijnCuppens
Copy link
Contributor Author

What is 2em here? What is 0.5rem? What happens if I change them? Those are the things that I wish we could figure out.

Well, this is the hard part about these functions indeed. Changing these values is like changing the coeficient and constant in 2 linear equations. Just to find out what these things are doing, you can calculate the matching point with y = ax + b:

y = 2x - .5   (2em - .5rem)
y = x + .5   (1em + .5rem)
⬇
2x - .5 =  x + .5
⬇
2x - x = .5 + .5
⬇
x = 1 (font size in rem)

y = 1 + .5 = 1.5 (line height in rem)

This means 1rem is the point where the functions are the same (= 1 + .5 = 2*1 - .5 = 1.5), for smaller font sizes 2em - .5rem is used, for larger font sizes 1em + .5rem is used.

What happens when you for example change 2em? Well, you 'll need to recalculate the intersection to get a better idea of what is happening.


These min() functions are just incredibly hard to understand, and replacing the numbers with variables doesn't really help.

That’s why I suggested using just 1em + 0.5rem instead. This simpler formula works well for font sizes ≥1rem, though we’ll still need to override line heights for smaller font sizes.

I'm also unsure about how far we should go with breaking changes to line heights. Do we want to avoid any breaking changes at all costs, or would it be worth it if it significantly simplifies things (and possibly lets us avoid decimals in the named leadings)?

@MartijnCuppens
Copy link
Contributor Author

It might be hard to grasp what calc(1em + .5rem) actually looks like, so here's a demo: https://play.tailwindcss.com/eJ1qLd9Vkz

Upper part is the current (v3) state, lower part is calc(1em + .5rem).

@MartijnCuppens
Copy link
Contributor Author

I think there are a few ways we could proceed:

1. Use the long function & remove line heights from the config

This approach uses round(max(min(2em - .5rem, 1em + .5rem, 2em / 3 + 1rem), 1em), 2px) as the line height. While it only affects the text-lg line height, the function is very complex, making it hard to understand or modify.

2. Use a less complicated function & remove line heights from the config

Here, we could use a simpler function like min(2em - .5rem, 1em + .5rem) or possibly min(1.5em, 1em + .5rem). While easier to grasp compared to approach 1, this introduces more breaking changes to the line heights. Additionally, using 1.5em can result in some odd line heights for small font sizes.

3. Using calc(1em + .5rem) & remove line heights in config

Use calc(1em + .5rem) (which is quite easy to understand) for all the line heights and still keep --text-xs--line-height and --text-sm--line-height. Also see #14503 (comment)

4. Use calc(1em + .5rem) as a fallback if no line height is defined & keep line heights in config

This is a more conservative approach. We retain the existing configuration but introduce a better fallback for cases where arbitrary values or custom properties are used. See https://play.tailwindcss.com/o707eQzYqO


In all cases mentioned above we could make the line height variable a custom property like --default-line-height or --text-default-line-height. The latter option is slightly more verbose but may be clearer, as it specifically applies to the text utilities rather than the body text line height.

@adamwathan, do you have any preferences on how we should move forward?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Line-height issue for <small>
2 participants