Skip to content

Conversation

RobinMalfait
Copy link
Member

This PR improves some of the signature computation logic. Right now, when you want to convert [font-weight:400] to font-normal it's not going to work because the signatures don't like up:

/* [font-weight:400] */
.x {
  font-weight: 400;
}

/* font-normal */
.x {
  --tw-font-weight: 400;
  font-weight: 400;
}

So this PR essentially ignores --tw-{property} if the {property} exists with the exact same value.

The main reason we have this, is to make composition of utilities easier.

As with any of these upgrades, they are the expected behavior in most cases, but there could always be a case where you don't want this, but that's why the upgrade tool requires you to review each change before applying it. Intellisense will recommend the simplified class, but it's up to you to decide if you want to apply it or not.

There is a known edge case for leading-{num}, because the property is line-height and the CSS variable is --tw-leading. Right now we map --tw-leading to line-height but we can also update the leading classes to use --tw-line-height instead but that feels like a bigger breaking change if people rely on these internal CSS variables...

@RobinMalfait RobinMalfait requested a review from a team as a code owner October 20, 2025 10:54
@RobinMalfait RobinMalfait force-pushed the feat/canonicalize-ignore-tw-vars branch from 10a32fc to 41abcb1 Compare October 20, 2025 10:59
@philipp-spiess
Copy link
Member

@RobinMalfait Is this an issue of utilities like the filter stuff that all emit the same declarations but only varying variables?

Also being nitpicky: The PR title is a bit confusing. It could help if you prefix it with "Signature Computation: …"

@RobinMalfait RobinMalfait changed the title Ignore --tw- variables Ignore --tw- variables during internal signature computation Oct 20, 2025
@RobinMalfait
Copy link
Member Author

@RobinMalfait Is this an issue of utilities like the filter stuff that all emit the same declarations but only varying variables?

Also being nitpicky: The PR title is a bit confusing. It could help if you prefix it with "Signature Computation: …"

Updated the title 👍

It is also an issue with filter and stuff, but that's much more scary to even try and normalize imo. This is the current implementation for backdrop-blur-sm (simplified by ignoring all the @property stuff).

.backdrop-blur-sm {
  --tw-backdrop-blur: blur(var(--blur-sm, 8px));
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
  backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
}

I also don't think it's super realistic to to try and migrate [backdrop-filter:blur(8px)] all the way to backdrop-blur-sm because the arbitrary property will only set the blur(8px), but the moment you translate it, then all other filters will take effect which maybe not be what you want?

If we do want something like that, then I think that should be a separate PR 🤔

We also have the issue where -webkit-* properties exists, but that's also a different PR if we want that.

@philipp-spiess
Copy link
Member

@RobinMalfait What I'm thinking is if we remove --tw-* from the signature, all filter utilities will have the same signature?

 .blur {
  /* --tw-blur: blur(8px); */
  filter: var(--tw-blur,) var(--tw-brightness,)
    var(--tw-contrast,) var(--tw-grayscale,)
    var(--tw-hue-rotate,) var(--tw-invert,)
    var(--tw-saturate,) var(--tw-sepia,)
    var(--tw-drop-shadow,);
}

.contrast-100 {
  /* --tw-contrast: contrast(100%); */
  filter: var(--tw-blur,) var(--tw-brightness,)
    var(--tw-contrast,) var(--tw-grayscale,)
    var(--tw-hue-rotate,) var(--tw-invert,)
    var(--tw-saturate,) var(--tw-sepia,)
    var(--tw-drop-shadow,);
}

@RobinMalfait
Copy link
Member Author

RobinMalfait commented Oct 20, 2025

We're only removing --tw-foo: value; if foo: value exists with the exact same value. So in case of blur --tw-blur: blur(8px) exists, but blur: blur(8px); does not exist because it's a filter property, so the --tw-* is kept.

So the final signature looks like this:

/* blur */
.x {
  --tw-blur: blur(8px);
  filter: var(--tw-blur,)_var(--tw-brightness,)_var(--tw-contrast,)_var(--tw-grayscale,)_var(--tw-hue-rotate,)_var(--tw-invert,)_var(--tw-saturate,)_var(--tw-sepia,)_var(--tw-drop-shadow,);
}

/* contrast-100 */
.x {
  --tw-contrast: contrast(100%);
  filter: var(--tw-blur,)_var(--tw-brightness,)_var(--tw-contrast,)_var(--tw-grayscale,)_var(--tw-hue-rotate,)_var(--tw-invert,)_var(--tw-saturate,)_var(--tw-sepia,)_var(--tw-drop-shadow,);
}

Base automatically changed from feat/canonicalize-multiple-to-one to main October 20, 2025 15:15
We already constant fold declarations, including normalization of
`0.00%` to just `0%`. So we don't need this code anymore.
This will help with `[font-weight:400]` to `font-normal`, even though
`font-normal` is actually implemented as:

```css
.font-normal {
  --tw-font-weight: 400;
  font-weight: 400;
}
```
Not super keen on this exception here, but it's something we do. Another
solution here is to use `--tw-line-height` instead so it properly maps
to the other property.
This way we don't have to hardcode the edge cases, but we have to make
sure that the same value exists _somewhere_.

We also make sure that the other property is also not a CSS variable.
Otherwise we would run into:

```css
.foo {
  --tw-a: 1;
  --tw-b: 1;
  --tw-c: 1;
}
```

Because this would delete all the declarations
@RobinMalfait RobinMalfait force-pushed the feat/canonicalize-ignore-tw-vars branch from e8a6120 to dc60f7a Compare October 20, 2025 15:16
@RobinMalfait RobinMalfait enabled auto-merge (squash) October 20, 2025 15:18
@RobinMalfait RobinMalfait merged commit 7537e34 into main Oct 20, 2025
7 checks passed
@RobinMalfait RobinMalfait deleted the feat/canonicalize-ignore-tw-vars branch October 20, 2025 15:21
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.

3 participants