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

Improve text-opacity #3706

Open
4 tasks done
jods4 opened this issue Apr 10, 2024 · 0 comments
Open
4 tasks done

Improve text-opacity #3706

jods4 opened this issue Apr 10, 2024 · 0 comments

Comments

@jods4
Copy link

jods4 commented Apr 10, 2024

Clear and concise description of the problem

text-opacity-{x} is a Windi rule that introduces an extra variable to control text opacity.

This variable could enable us to control text opacity separately from color, which would be useful, but implementation is lacking. We can only use this variable as an alternate syntax for Tailwind text-{color}/{opacity}:

<div class="text-red text-opacity-50">Windi, uses variable</div>
<div class="text-red/50">Tailwind, single class, doesn't require variable</div>

Separation of color and opacity is quite interesting if we could change them separately. For example reduce opacity to de-emphasize some text while preserving the current color.

<div class="text-red">
  Useful idea: dim text.
  This is <span class="text-opacity/50">NOT 50%.</span>
</div>

<div class="text-opacity/50">
  Less useful, but also an idea.
  This is <span class="text-red">NOT 50% either.</span>
</div>

Intuitively you could expect these to work, but neither does. Let's see why.
First the generated CSS:

.text-red {
  --un-text-opacity: 1;
  color: rgb(248 113 113 / var(--un-text-opacity));
}

.text-opacity-50 {
  --un-text-opacity: 0.5;
}

The outer text-opacity does not apply to inner text-red, because text-red resets --un-text-opacity to 1.
I don't think this is a very useful use-case, so for compatibility purposes I'd say we could keep it unchanged.

The other scenario is useful and the reason why it doesn't work is subtle:
CSS properties inherit their computed value, not their source expression!
So the span.text-opacity-50 inherits the computed color: rgb(248 113 113 / 1). It does not have a dependency on any variable and changing --un-text-opacity at this level has no effect.

Setting both rules on the same element only works because text-opacity-50 is declared after text-red in CSS stylesheet, so it's declaration of --un-text-opacity "wins". Using both class on the same element seems a little wasteful when we can use a single class, constant text-red/50.

Suggested solution

I tweaked the rules as follow:

/* Variant 1: full support for independent opacity control top-down and bottom-up */

.text-red {
  /* removed: --un-text-opacity: 1 */
  --un-color:  rgb(248 113 113); /* added */
  color: rgb(248 113 133 / var(--un-text-opacity));
}

.text-red/50 {
  --un-color:  rgb(248 113 113); /* added as well, to be able to use /opacity syntax and still tweak color inside */
  color:  rgb(248 113 113 / 0.5);
}

.text-opacity-50 {
  --un-text-opacity: 0.5;
  color: rgb(from var(--un-color) r g b / 0.5); /* added, force re-computing the color */
}


/* Variant 2: text-red resets opacity to 1 for back-compat, so controlling opacity higher up in DOM is not possible */

.text-red {
  /* removed: --un-text-opacity: 1 */
  --un-color:  rgb(248 113 113); /* added */
  color: rgb(248 113 133); /* removed / var(--un-text-opacity) */
}

.text-red/50 {
  --un-color:  rgb(248 113 113); /* added */
  color:  rgb(248 113 113 / 0.5);
}

.text-opacity-50 {
  color: rgb(from var(--un-color) r g b / 0.5); /* added */
}

Removing --un-text-opacity from text-red enables top-down cascade of opacity.
As I said it's not the most useful use case so might be kept in if we want to minimize breakage.
Notice that if we keep this backward compatible behavior, --un-text-opacity is not necessary at all and can be dropped. When both text-red text-opacity-50 are declared on the same element, the new color rule of the later takes over (as it's declared after text-red, same reasoning as previously).

Introducing a new variable --un-color to text-color rules lets us re-compute the color property in child elements that use text-opacity, enabling opacity to affect colors picked higher up.

Alternative

If you want to be able to dim elements by reducing their opacity, while keeping any current color, I don't see any other way to achieve this.

You might think that this style could be a cheap solution: rgb(from currentColor r g b / 0.5).
It's actually valid CSS that works when assigned to any property... except color.
The problem is that using currentColor inside color property creates a circular reference that doesn't work :(

Additional context

Other rules work identically, in particular bg-red and bg-opacity-50.
I'd say they would benefit from the same change.

It also opens up new uses cases, for example I'd love being able to darken a background when mouse is pressed (e.g. on a button, or a clickable items).
If there was a variable --un-bg-color then I could create a rule active:bg-darken-10.

Validations

  • Read the Contributing Guidelines.
  • Read the README.md of using the package.
  • Already used the Interactive Docs.
  • Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
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

No branches or pull requests

1 participant