Part of the current changes, we also want to make the `--line-height-*`
namespace closer to the utility name so we're renaming it to
`--leading-*`:
```diff
@theme {
- --line-height-none: 1;
- --line-height-tight: 1.25;
- --line-height-snug: 1.375;
- --line-height-normal: 1.5;
- --line-height-relaxed: 1.625;
- --line-height-loose: 2;
/* ... */
+ --leading-none: 1;
+ --leading-tight: 1.25;
+ --leading-snug: 1.375;
+ --leading-normal: 1.5;
+ --leading-relaxed: 1.625;
+ --leading-loose: 2;
/* ... */
}
```
Notice that we did not change the nested values used in the `--text`
type scale, e.g.:
```css
@theme {
/* Type scale */
--text-xs: 0.75rem;
--text-xs--line-height: 1rem;
}
```
These do not refer to the `leading` utility and instead refer to nested
properties so we're keeping those as-is.
## Test Plan
Added cases to the CSS `theme()` variable/JS plugin tests (interop
layer) and the integration tests (codemod layer).
Part of the current changes, we also want to make the
`--letter-spacing-*` namespace closer to the utility name so we're
renaming it to `--tracking-*`:
```diff
@theme {
- --letter-spacing-tighter: -0.05em;
- --letter-spacing-tight: -0.025em;
- --letter-spacing-normal: 0em;
- --letter-spacing-wide: 0.025em;
- --letter-spacing-wider: 0.05em;
- --letter-spacing-widest: 0.1em;
/* ... */
+ --tracking-tighter: -0.05em;
+ --tracking-tight: -0.025em;
+ --tracking-normal: 0em;
+ --tracking-wide: 0.025em;
+ --tracking-wider: 0.05em;
+ --tracking-widest: 0.1em;
/* ... */
}
```
## Test Plan
Added cases to the CSS `theme()` variable/JS plugin tests (interop
layer) and the integration tests (codemod layer).
When using an opacity modifier such as `bg-black/[var(--opacity)]`, then
this was translated to:
```css
.bg-black\/\[var\(--opacity\)\] {
background-color: color-mix( in oklch, var(--color-black, #000) calc(var(--opacity) * 100%), transp
}
```
The issue is that this part: `calc(var(--opacity) * 100%)` is invalid
_if_ the `var(--opacity)` already contains a percentage value. See:
https://play.tailwindcss.com/xz0t
This is because this eventually resolves to `calc(20% * 100%)` and `20%
100%` is invalid in CSS.
In Catalyst we use variables like that _with_ the `%` included, which
means that v4 doesn't work as expected when using this.
A variable with a `%` included is probably the better value to support
compared to the the unit less one. This also allows you to define your
variables using `@property` as a proper `<percentage>` type.
Unfortunately the `var(--opacity)` is a value that can change at
runtime, so we don't know the type at compile time.
In the future we might be able to use `first-valid(…)` (see:
https://drafts.csswg.org/css-values-5/#f and generate both versions at
the same time.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This PR fixes an issue where utilities like `px` would read the
`--spacing` variable and use its value as the utility value, similar to
how `shadow` reads `--shadow` by default. That doesn't make sense for
these utilities since `--spacing` is reserved as a special multiplier
variable.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR updates all of the `--font-size-*` variables to `--text-*`
instead to closer match the utility names.
```diff
@theme {
- --font-size-xs: 0.75rem;
- --font-size-xs--line-height: 1rem;
- --font-size-sm: 0.875rem;
- --font-size-sm--line-height: 1.25rem;
- --font-size-base: 1rem;
- --font-size-base--line-height: 1.5rem;
- --font-size-lg: 1.125rem;
- --font-size-lg--line-height: 1.75rem;
- --font-size-xl: 1.25rem;
- --font-size-xl--line-height: 1.75rem;
/* ... */
+ --text-xs: 0.75rem;
+ --text-xs--line-height: 1rem;
+ --text-sm: 0.875rem;
+ --text-sm--line-height: 1.25rem;
+ --text-base: 1rem;
+ --text-base--line-height: 1.5rem;
+ --text-lg: 1.125rem;
+ --text-lg--line-height: 1.75rem;
+ --text-xl: 1.25rem;
+ --text-xl--line-height: 1.75rem;
/* ... */
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR fixes an issue where unsetting `--font-*` would unset
`--font-weight-*` and `--font-size-*`.
```css
@theme {
--font-weight-bold: bold;
--font-size-sm: 14px;
--font-sans: sans-serif;
--font-serif: serif;
}
@theme {
--font-*: initial;
--font-body: Inter;
}
```
Up until now this was sort of intended/desired behavior but with recent
changes there are now more overlapping theme keys (`--inset-*` and
`--inset-shadow-*` as well for example), and we don't want to make it
impossible to unset _just_ the default `font-family` values.
This PR also simplifies how we were handling making sure that the
`inset-*` utility ignored `--inset-shadow-*` variables since it's all
really the same problem.
This does mean we need to maintain a list of known theme keys so we know
when there is a conflict between two keys, which is kind of unfortunate
because up until now this was a totally dynamic thing. End users can
still add whatever custom stuff they want under `@theme` but we don't
really know about those namespaces since we're maintaining a static list
so we can't resolve conflicts there. I'm confident there are ways we
could solve this if it actually becomes a problem, so content to push
forward without solving it right now and just deal with it if/when it
actually arises, because it just might not.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR renames all of the `--width-*` variables to `--container-*` to
better communicate the purpose of these tokens as layout container
sizes. These are the values that were historically stored under
`maxWidth` in the v3 and earlier eras, and were also re-used by the
container queries plugin.
The name `--container-*` feels like a better match alongside the
`--breakpoint-*` namespace and since these both serve that same sort of
purpose it makes sense to me that the name should be optimized for
feeling "right" in that context.
I like that this also sort of advertises Tailwind's support for
container queries directly in the CSS variables themselves, and helps
people understand what these are really intended to be used for.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR renames the `--transition-timing-function-*` theme variables to
`--ease-*` to more closely match the utility names and be a bit more
terse in general.
```diff
@theme {
- --transition-timing-function-in: cubic-bezier(0.4, 0, 1, 1);
- --transition-timing-function-out: cubic-bezier(0, 0, 0.2, 1);
- --transition-timing-function-in-out: cubic-bezier(0.4, 0, 0.2, 1);
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR renames the `--font-family-*` theme variables to `--font-*` to
more closely match the utility names and be a bit more terse in general.
```diff
@theme {
- --font-family-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
- --font-family-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
- --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
+ --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+ --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
}
```
This is part of a bigger set of changes where we're renaming other theme
variables as well with the same goals, since many existing theme
variables like `--shadow-*` and `--radius-*` are already not using the
explicit CSS property name.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR improves the generated CSS by running it through Lightning CSS
twice.Right now Lightning CSS merges adjacent at-rules and at the end
flattens the nesting. This means that after the nesting is flattened,
the at-rules that are adjacent and could be merged together will not be
merged.
This PR improves our output by running Lightning CSS twice on the
generated CSS which will make sure to merge adjacent at-rules after the
nesting is flattened.
Note: in the diff output you'll notice that some properties are
duplicated. These need some fixes in Lightning CSS itself but they don't
break anything for us right now.
Related PR in Lightning CSS for the double `-webkit-backdrop-filter` can
be found here: https://github.com/parcel-bundler/lightningcss/pull/850
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR removes all of the static `font-weight` utilities that were
previously hard-coded into the framework in favor of deriving those
utilities from the `--font-weight-*` theme values instead.
Biggest motivation for this is giving people a way to explicitly disable
font-weight utilities they don't want to use in their project, which
previously wasn't possible.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR changes how we render `var(...)` calls for theme values,
removing the fallback values we were previously including.
```diff
.text-white {
- color: var(--color-white, #fff);
+ color: var(--color-white);
}
```
We previously included the fallbacks only so you could see the value in
dev tools but this feels like a bad reason to bloat the CSS. I'd rather
just convince the Chrome team to surface this stuff better in dev tools
in the first place.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR replaces the default spacing scale (`--spacing-*`) with a
generative system based on a default spacing _unit_.
Instead of the default theme containing values like `--spacing-4`,
`--spacing-6`, `--spacing-8`, etc., instead we just define a single
`--spacing` value:
```css
@theme {
--spacing: 0.25rem;
}
```
Utilities like `px-4` are derived from this unit by multiplying it by
the value in the utility (4 in this case):
```css
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
```
The biggest consequence of this change is that every value is available
now, rather than just the explicitly configured values.
This means utilities like `px-42` will work now, whereas prior to this
PR only `px-40` and `px-44` were valid utilities. I personally found it
very difficult to know which values actually existed at the higher end
of the scale without IntelliSense, and in practice even when working
with a skilled designer like [Steve](https://x.com/steveschoger) who
helped design Tailwind's default spacing scale, I'd very often need to
break out of it to implement a design, and trying to round to a value
that was in the scale made the design worse, not better.
This PR allows you to use any whole number, as well as decimal numbers
that are multiples of `0.25` to ensure classes like `px-1.5` continue to
work. While this means you can now technically do things like
`pt-97.25`, I think the presence of the fractional value will be enough
of a signal to developers that they are doing something a little
unusual, and they can use their judgment as to whether they are making
the right decision or not.
I'll update this PR with a lot more detail when I have a chance, as
there are a few other things to explain like:
- Unifying all of the values for
width/min-width/max-width/height/min-height/max-height utilities
- Deriving numeric line-height values from the spacing multiplier
instead of a separate line-height scale
- Using `--spacing: initial` to disable the multiplier
- How you can still use an explicit spacing scale and ignore this change
- How we plan to use IntelliSense to surface a more curated set of
spacing values even if smaller increments work when you type them
explicitly
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR reworks the default `--shadow-*` and `--inset-shadow-*` scales
to remove the bare `shadow` and `inset-shadow` utilities, and ensure
every shadow has an explicit size as part of the utility name.
Here's a complete list of changes:
| v3 | v4 Alpha | Proposed |
| ----------------- | ----------------- | ------------------ |
| _N/A_ | `shadow-xs` | `shadow-2xs` |
| `shadow-sm` | `shadow-sm` | `shadow-xs` |
| `shadow` | `shadow` | `shadow-sm` |
| `shadow-md` | `shadow-md` | `shadow-md` |
| `shadow-lg` | `shadow-lg` | `shadow-lg` |
| `shadow-xl` | `shadow-xl` | `shadow-xl` |
| _N/A_ | `inset-shadow-xs` | `inset-shadow-2xs` |
| _N/A_ | `inset-shadow-sm` | `inset-shadow-xs` |
| `shadow-inner` | `inset-shadow` | `inset-shadow-sm` |
The motivation for this change is just to make the scale more
predictable — it's never been intuitive to me that `shadow` sits in
between `shadow-sm` and `shadow-md`.
This PR doesn't remove the ability to create classes like `shadow` and
`inset-shadow` by adding bare `--shadow` and `--inset-shadow` theme
variables, but does remove them from the default theme.
## Impact
We'll include a codemod for this in our upgrade tool to automate this
change for people upgrading from v3 to v4, but this is still sort of an
annoying breaking change admittedly and will make lots of educational
resources, example components, and LLM tools out of date for v4 😕 At the
same time I don't want to feel like we can never correct regrettable
legacy decisions just to preserve backward compatibility.
We made a similar change like this when we went from the v0.x color
palette to the v1.x color palette changing names like `bg-red` to
`bg-red-500` and that proved to definitely be the right decision long
term, so want to rip the band-aid off here too if we can.
Planning to make the same change for `rounded`, `drop-shadow`, and
`blur` as well — maybe in separate PRs but maybe just all in this one as
well since I don't think we want to do one and not all.
_Update_: I've also made the same changes to the `--radius-*`,
`--drop-shadow-*`, and `--blur-*` scales now, effectively removed the
`rounded`, `drop-shadow`, and `blur` classes by default, and changing
the meaning `rounded-sm`, `drop-shadow-sm`, and `blur-sm`.
We'll put together a codemod to handle this stuff in a separate PR.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR fixes a issue where utilities like `inset-x-*`, `left-*`,
`top-*`, etc. mistakenly pull values from the `--inset-ring-*` and
`--inset-shadow-*` theme namespaces.
For example, the class `left-shadow-sm` currently generates this CSS:
```css
.left-shadow-sm {
left: var(
--inset-shadow-sm,
inset 0 1px 1px rgb(0 0 0 / 0.05)
);
}
```
This happens because the `--inset-ring-*` and `--inset-shadow-*`
namespaces collide with the `--inset-*` namespace.
We were already handling this manually for just the `inset-*` utilities
but didn't realize we needed to handle it for every related utility, so
this PR fixes that.
This also fixes an issue where IntelliSense would suggest classes like
`inset-x-shadow-sm` when they shouldn't actually exist.
To do this we've created this new concept of `ignoredThemeKeys` in the
relevant APIs to make sure these are filtered out at the source.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR updates all of our x/y named utilities (like `px-*`, `my-*`,
`inset-y-*`, `scroll-px-*`, etc.) to use logical properties like
`padding-inline` instead of separate `padding-left` and `padding-right`
properties.
We held off on this originally for a while because `inline` doesn't
really mean _horizontal_ like the "x" in `px-*` implies, but I think in
practice this change is fine — I'm comfortable with "x" meaning "in the
inline direction" and "y" meaning "in the block direction" in Tailwind.
This is technically a breaking change if anyone was depending on the
fact that `px-*` for instance was always explicitly setting
`padding-left` and `padding-right` even when building something in a
vertical writing mode, but I kinda doubt there's a single real project
on the internet that will actually be affected, so not too worried about
it.
If someone _really_ wants to set `padding-left` and `padding-right` they
can always use `pl-4 pr-4` instead of `px-4`.
Nice thing about this change is it produces quite a bit less CSS.
To test this change, I re-generated all of the snapshots and made sure
none of the generated utilities changed position or anything in the
output (initially they did before I updated `property-order.ts` to add
some missing properties).
I also created a little demo locally in the Vite playground to test
things manually and make sure I didn't make any obvious typos or
anything that could slip through the snapshots:
<img width="1223" alt="image"
src="https://github.com/user-attachments/assets/0e9854ba-2b5b-4c8c-87b6-6eb7b7da84f2">
<details>
<summary>Show code for playground demo</summary>
```jsx
import React from 'react'
export function App() {
return (
<div className="p-12 gap-10 grid grid-cols-2 items-start">
<div className="grid grid-cols-1 gap-10 justify-start">
<div className="space-y-6">
<p className="font-semibold mb-6">Border Width</p>
<div className="border-x w-48 h-12 flex items-center justify-center">border-x</div>
<div className="border-y w-48 h-12 flex items-center justify-center">border-y</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Border Color</p>
<div className="border-2 border-x-red-500 w-48 h-12 flex items-center justify-center">
border-x-red-500
</div>
<div className="border-2 border-y-red-500 w-48 h-12 flex items-center justify-center">
border-y-red-500
</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Padding</p>
<div>
<div className="px-8 bg-yellow-300 inline-flex items-center justify-center">px-8</div>
</div>
<div>
<div className="py-8 bg-yellow-300 inline-flex items-center justify-center">py-8</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 gap-10 justify-start">
<div className="space-y-6">
<p className="font-semibold mb-6">Margin</p>
<div>
<div className="bg-red-400 inline-flex">
<div className="mx-8 bg-yellow-300 inline-flex items-center justify-center">mx-8</div>
</div>
</div>
<div>
<div className="bg-red-400 inline-flex">
<div className="my-8 bg-yellow-300 inline-flex items-center justify-center">my-8</div>
</div>
</div>
</div>
<div className="space-y-6">
<p className="font-semibold mb-6">Inset</p>
<div className="relative bg-red-400 w-48 h-48">
<div className="inset-x-8 absolute bg-yellow-300 inline-flex items-center justify-center">
inset-x-8
</div>
</div>
<div className="relative bg-red-400 w-48 h-48">
<div className="inset-y-8 absolute bg-yellow-300 inline-flex items-center justify-center">
inset-y-8
</div>
</div>
</div>
</div>
</div>
)
}
```
</details>
I didn't manually test the scroll padding or scroll margin utilities
because they are more annoying to set up, but I probably should.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR updates all of our OKCLH colors to use `0` instead of `none` due
to weird behavior in Chrome where using `color-mix` with colors using
`none` produces unexpected results:
<img width="1110" alt="image"
src="https://github.com/user-attachments/assets/2272e494-500b-4f75-b5c1-d41c714f0339">
Both `none` and `0` behave as expected in Safari and Firefox so
suspecting this is a bug in Chrome rather than spec'd behavior.
Fixes#14740
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR updates all of our gradient utilities to interpolate using OKLCH
by default instead of sRGB. This results in a smoother transition
between colors that preserves saturation throughout the gradient, rather
than hitting the dreaded dull gray zone in between your color stops.
Here are a few examples comparing sRGB (top) to OKLCH (bottom):
<img width="736" alt="image"
src="https://github.com/user-attachments/assets/57a158b6-a3a2-4eda-813e-1b596c7d4b3a">
We only apply a default interpolation mode when _not_ using arbitrary
values with the gradient utility.
Simplified but clear:
```css
.bg-linear-to-r {
background-image: linear-gradient(to right in oklch, var(--gradient-color-stops));
}
.bg-linear-[to_right] {
background-image: linear-gradient(to right, var(--gradient-color-stops));
}
.bg-linear-[to_right_in_hsl] {
background-image: linear-gradient(to right in hsl, var(--gradient-color-stops));
}
```
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds support for linear gradient angles as bare values, like
this:
```
bg-linear-45 => linear-gradient(45deg, …)
```
We already support this for [conic
gradients](https://github.com/tailwindlabs/tailwindcss/pull/14467), so
this makes these utilities more consistent.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Prior to this PR we were providing fallback values for certain CSS
variables in our gradient utilities that just weren't necessary and
didn't do anything.
For example `bg-linear-to-r` was generating this:
```css
.bg-linear-to-r {
--tw-gradient-position: to right;
background-image: linear-gradient(
var(--tw-gradient-stops, to right)
);
}
```
…but `background-image: linear-gradient(to right)` is not valid CSS and
is thrown out by the browser.
This PR removes these fallback values entirely since there is nothing
sensible to fall back to anyways — you need to combine these utilities
with the `from-*`/`to-*` utilities or provide the complete gradient as
an arbitrary value for things to make sense.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR fixes an issue where bare values in the `font-stretch` utility
such as `font-stretch-50.5%` compiled. But for bare values, we want
these values to be positive integers only so that we don't have too many
special characters.
If you want to use `50.5%`, you can still use `font-stretch-[50.5%]` as
a utility.
Replaces #11271 — the merge conflicts are killing me and it's way easier
to just do it again (added you as a co-author though @lukewarlow so
you're still credited!)
This PR adds the following new utilities for the `color-scheme`
property:
| Class | CSS |
| ------------------- | -------------------------- |
| `scheme-normal` | `color-scheme: normal` |
| `scheme-dark` | `color-scheme: dark` |
| `scheme-light` | `color-scheme: light` |
| `scheme-light-dark` | `color-scheme: light dark` |
| `scheme-only-dark` | `color-scheme: dark only` |
| `scheme-only-light` | `color-scheme: light only` |
Went with `scheme-*` for the utilities because there are currently no
other CSS properties with the word `scheme` in them and
`scheme-light-dark` is going to be a common value which is three words
already even with the shortened property name.
I considered setting `color-scheme: light dark` by default as part of
Preflight for this PR but decided against it, at least for this PR. I
think that could still be a useful default but we should think about it
a bit more because if you're building a light-mode-only site it'll force
you to do some extra work.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
I noticed some more unexpected values being passed through as _bare
values_: Decimal places with zero.
These should not generate CSS but currently does:
- `from-25.%`
- `from-25.0%`
- `from-25.00%`
- etc.
This PR updates the `hover` variant to only apply when `@media (hover:
hover)` matches.
```diff
.hover\:bg-black {
&:hover {
+ @media (hover: hover) {
background: black;
+ }
}
}
```
This is technically a breaking change because you may have built your
site in a way where some interactions depend on hover (like opening a
dropdown menu), and were relying on the fact that tapping on mobile
triggers hover.
To bring back the old hover behavior, users can override the `hover`
variant in their CSS file back to the simpler implementation:
```css
@import "tailwindcss";
@variant hover (&:hover);
```
I've opted to go with just `@media (hover: hover)` for this because it
seems like the best trade-off between the available options. Using
`(any-hover: hover)` would mean users would get sticky hover states when
tapping on an iPad if they have a mouse or trackpad connected, which
feels wrong to me because in those cases touch is still likely the
primary method of interaction.
Sites built with this feature in mind will be treating hover styles as
progressive enhancement, so it seems better to me that using an iPad
with a mouse would not have hover styles, vs. having sticky hover styles
in the same situation.
Of course users can always override this with whatever they want, so
making this the default isn't locking anyone in to a particular choice.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR is a continuation of #13537.
Currently we reverted the merged changes so that we can get a new alpha
version out without this change.
---
This PR removes automatic `var(…)` injection for arbitrary properties,
values and modifiers.
There are a few properties that use "dashed-ident" values, this means
that you can use `--my-thing` as-is without the `var(…)` around it.
E.g.:
```css
.foo {
/* Notice that these don't have `var(…)` */
view-timeline-name: --timeline-name;
anchor-name: --sidebar;
}
```
This causes issues because we are now injecting a `var(…)` where it's
not needed.
One potential solution is to create a list of properties where dashed
idents can be used. However, they can _also_ use CSS custom properties
that point to another dashed ident.
E.g.:
```css
.foo {
--target: --sidebar;
anchor-name: var(--target);
}
```
A workaround that some people used is adding a `_` in front of the
variable: `mt-[_--my-thing]` this way we don't automatically inject the
`var(…)` around it. This is a workaround and gross.
While the idea of automatic var injection is neat, this causes more
trouble than it's worth. Adding `var(…)` explicitly is better.
A side effect of this is that we can simplify the internals for the
`candidate` data structure because we don't need to track `dashedIdent`
separately anymore.
<!--
👋 Hey, thanks for your interest in contributing to Tailwind!
**Please ask first before starting work on any significant new
features.**
It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.
https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md
-->
This PR changes the behavior of the `transition-{property}` utilities to
respect any explicit timing function or duration set by the user using
the `ease-*` and `duration-*` utilities.
Say you have this HTML:
```html
<div class="transition-colors duration-500 ease-out lg:transition-all">
```
Currently, the `transition-duration` and `transition-timing-functions`
will be reset to their default values at the `lg` breakpoint even though
you've provided explicit values for them.
After this PR is merged, those values will be preserved at the `lg`
breakpoint.
This PR also adds `duration-initial` and `ease-initial` utilities to
"unset" explicit duration/timing-function values so that the defaults
from classes like `transition-all` will kick in, without having to
specify their explicit values.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds our custom gradient color properties (`--tw-gradient-from`,
`--tw-gradient-via`, and `--tw-gradient-to`) to the list of color
properties we transition in the `transition` and `transition-colors`
utilities.
As part of this I noticed that we had duplicate `@property` declarations
for these custom properties, so I've removed the duplicates.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Fixes#14479.
Back in March we made a change to the `transition-*` utilities that
inlined the values of the `--default-transition-*` variables to fix a
bug where things would break if those variables didn't exist in your
CSS. At the time though we weren't outputting CSS variables as part of
the values of any utilities, for example `bg-red-500` didn't actually
reference the `--color-red-500` variable.
We later changed that but missed this situation, so these variables were
still inlined even though nothing else was.
This PR fixes that and makes things more consistent, so these variables
will be used as expected unless using the `@theme inline` option, like
with everything else.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR adds support for the
[`field-sizing`](https://developer.mozilla.org/en-US/docs/Web/CSS/field-sizing)
property which can be used to fit a text inputs, file inputs, textareas,
and selects to the size of the text rather than some implicit default
width.
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This PR adds new `bg-radial-*` and `bg-conic-*` utilities for radial and
conic gradients. It also adds support for "arbitrary gradients", where
gradient utilities like `bg-linear-*`, `bg-radial-*`, and `bg-conic-*`
can now accept a complete gradient definition as their arbitrary value.
## Radial gradients
Radial gradients are created with the `bg-radial` utility, or the
`bg-radial-[…]` utility, combined with the existing `from-*`, `via-*`,
and `to-*` utilities.
The simple `bg-radial` utility just creates a radial gradient with no
position information, which defaults to `center`:
```
radial-gradient({from}, {via}, {to});
```
If you use the arbitrary value format, whatever you provide as the
arbitrary value is inserted into the first position:
```
radial-gradient({arbitrary value}, {from}, {via}, {to});
```
So a utility like `bg-radial-[at_top_left]` would produce this:
```
radial-gradient(at top left, {from}, {via}, {to});
```
This makes it possible to use some of the `radial-gradient(…)` features
that this PR doesn't add first class support for, like using values like
`circle at center` or providing a specific interpolation color space
like `in hsl longer hue`. We may add explicit APIs for these in the
future, but I'm proposing this PR first since those changes would be
purely additive and none of the decisions here would create any conflict
with those APIs.
## Conic gradients
Conic gradients are created with the `bg-conic`,
`bg-conic-{bareNumber}`, and `bg-conic-[…]` utilities, combined with the
existing `from-*`, `via-*`, and `to-*` utilities.
The `bg-conic` utility creates a conic gradient with no angle, which
defaults to `0deg`:
```
conic-gradient({from}, {via}, {to});
```
The `bg-conic-{bareNumber}` utilities create conic gradients using the
bare number as the angle:
```
conic-gradient(from {bareNumber}deg, {from}, {via}, {to});
```
The `bg-conic-[…]` arbitrary value utilities insert whatever you provide
as the arbitrary value into the first position verbatim:
```
conic-gradient({arbitraryValue}, {from}, {via}, {to});
```
So a utility like `bg-conic-[from_45deg_in_hsl]` would produce this:
```
conic-gradient(from 45deg in hsl, {from}, {via}, {to});
```
Note that the `from` keyword needs to be provided by the user when using
arbitrary values, but not when using bare values.
This makes it possible to use some of the `conic-gradient(…)` features
that this PR doesn't add first class support for, like using values like
`at 0 0` or providing a specific interpolation color space like `in hsl
longer hue`. We may add explicit APIs for these in the future, but I'm
proposing this PR first since those changes would be purely additive and
none of the decisions here would create any conflict with those APIs.
## Arbitrary gradients
Prior to this PR, utilities like `bg-linear-[…]` could only accept
positional information as their arbitrary value, like
`bg-linear-[to_top_right]`. All of the color stops could only be
provided using the `from-*`, `via-*`, and `to-*` utilities.
If you wanted to provide the complete gradient in one class, you needed
to use `bg-[…]` and write out the gradient function yourself:
```html
<div class="bg-[linear-gradient(to_right,var(--color-red-500),var(--color-yellow-400))]">
```
This PR refactors some things internally to make it possible to provide
the entire gradient as the arbitrary value to each background gradient
utility, like this:
```html
<div class="bg-linear-[to_right,var(--color-red-500),var(--color-yellow-400)]">
```
This is nice if you're doing something very custom and you want to be
able to look at the whole value together, while still avoiding some of
the boilerplate you'd have if you had to write out the entire gradient
function yourself.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR changes how shadow color and shadow size utilities interact when
used with variants.
Take this HTML:
```html
<div class="shadow-lg shadow-red-500 hover:shadow-xl">
<!-- … -->
</div>
```
Currently this shadow would be red by default, but revert to the default
semi-transparent black color on hover.
This PR changes this behavior such that the shadow remains red on hover,
and only the shadow size changes.
We deliberately didn't do this originally because making things behave
this way makes it very difficult to get the default shadow color back
once you've changed it. The default color for `shadow-xl` for instance
is `rgb(0 0 0 / 0.1)`, and the only way to get that color back after
changing it is to know that value and explicitly bring it back:
```html
<div class="shadow-lg shadow-red-500 hover:shadow-xl hover:shadow-black/10">
<!-- … -->
</div>
```
To make things more difficult, the default shadow color is not the same
across shadow sizes. For `shadow-sm` it's `black/5`, and for
`shadow-2xl` it's `black/25`.
In practice though you basically never need to bring back the default
shadow color, so I'm reconsidering this trade-off in v4, and think I
prefer this new behavior where the color is preserved but you have to
bring back the default color if you actually need it.
A simple workaround if you don't know the color is to reset the
`--tw-shadow-color` variable like this:
```html
<div class="shadow-lg shadow-red-500 hover:shadow-xl hover:[--tw-shadow-color:initial]">
<!-- … -->
</div>
```
This relies on semi-private internals though, so perhaps we can
introduce a utility for this, like `shadow-default` or `shadow-initial`
that just unsets the shadow color.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Right now, it is possible to type `grid-cols--8` which maps to:
```css
/* Specificity: (0, 1, 0) */
.grid-cols--8 {
grid-template-columns: repeat(-8, minmax(0, 1fr));
}
```
This doesn't make sense so we used this opportunity to audit all
variants and utilities and properly disallow negative bare values.
Utilities where negative values are supported still work by using the
negative utility syntax, e.g.: `-inset-4`.
This PR improves how the `text-{size}` utilities interact with the
`leading-*`, `tracking-*`, and `font-{weight}` utilities, ensuring that
if the user explicitly uses any of those utilities that those values are
not squashed by any defaults baked into the `text-{size}` utilities.
Prior to this PR, if you wrote something like this:
```html
<div class="text-lg leading-none md:text-2xl">
```
…the `leading-none` class would be overridden by the default line-height
value baked into the `text-2xl` utility at the `md` breakpoint. This has
been a point of confusion and frustration for people [in the
past](https://github.com/tailwindlabs/tailwindcss/issues/6504) who are
annoyed they have to keep repeating their custom `leading-*` value like
this:
```html
<div class="text-lg leading-none md:text-2xl md:leading-none lg:text-4xl lg:leading-none">
```
This PR lets you write this HTML instead but get the same behavior as
above:
```html
<div class="text-lg leading-none md:text-2xl lg:text-4xl">
```
It's important to note that this change _only_ applies to line-height
values set explicitly with a `leading-*` utility, and does not apply to
the line-height modifier.
In this example, the line-height set by `text-sm/6` does _not_ override
the default line-height included in the `md:text-lg` utility:
```html
<div class="text-sm/6 md:text-lg">
```
That means these two code snippets behave differently:
```html
<div class="text-sm/6 md:text-lg">…</div>
<div class="text-sm leading-6 md:text-lg">…</div>
```
In the top one, the line-height `md:text-lg` overrides the line-height
set by `text-sm/6`, but in the bottom one, the explicit `leading-6`
utility takes precedence.
This PR applies the same improvements to `tracking-*` and
`font-{weight}` as well, since all font size utilities can also
optionally specify default `letter-spacing` and `font-weight` values.
We achieve this using new semi-private CSS variables like we do for
things like transforms, shadows, etc., which are set by the `leading-*`,
`tracking-*`, and `font-{weight}` utilities respectively. The
`text-{size}` utilities always use these values first if they are
defined, and the default values become fallbacks for those variables if
they aren't present.
We use `@property` to make sure these variables are reset to `initial`
on a per element basis so that they are never inherited, like with every
other variable we define.
This PR does slightly increase the amount of CSS generated, because now
utilities like `leading-5` look like this:
```diff
.leading-5 {
+ --tw-leading: 1.25rem;
line-height: 1.25rem;
}
```
…and utilites like `text-sm` include a `var(…)` lookup that they didn't
include before:
```diff
.text-sm {
font-size: 0.875rem;
- line-height: var(--font-size-sm--line-height, 1.25rem);
+ line-height: var(--tw-leading, var(--font-size-sm--line-height, 1.25rem));
}
```
If this extra CSS doesn't feel worth it for the small improvement in
behavior, we may consider just closing this PR and keeping things as
they are.
This PR is also a breaking change for anyone who was depending on the
old behavior, and expected the line-height baked into the `md:text-lg`
class to take precedence over the explicit `leading-6` class:
```html
<div class="text-sm leading-6 md:text-lg">…</div>
```
Personally I am comfortable with this because of the fact that you can
still get the old behavior by preferring a line-height modifier:
```html
<div class="text-sm/6 md:text-lg">…</div>
```
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Resolves#14440.
This PR fixes an issue where registering a custom `inset-shadow-*`
utility value in your theme like this:
```css
@theme {
--inset-shadow-potato: inset 0px 2px 6px #7a4724;
}
```
…mistakenly generates both an `inset-shadow-*` and `inset-*` utility
with that value:
```css
.inset-shadow-potato {
inset: inset 0px 2px 6px #7a4724;
}
.inset-shadow-potato {
box-shadow: inset 0px 2px 6px #7a4724;
}
```
This replaces #14445 which turns out to not be the ideal solution.
Now we just explicitly ignore variables like `--inset-shadow-*` and
`--inset-ring-*` in the `inset` handler. Kind of a gross patch but I can
live with it because the whole existence of the `--inset-*` key is kind
of a backwards compatibility thing anyways.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Right now if you have a custom opacity theme value configured like this…
```css
@theme {
--opacity-disabled: 50%;
}
```
…then you can use that named opacity value as a color opacity modifier
like this:
```html
<div class="bg-red-500/disabled">
```
We think this behavior is confusing. The color opacity modifier is not
setting opacity but the alpha value of a color. Opacity is for setting
the opacity of an element, so the custom names you'd come up with are
named after those situations, which makes them not seem appropriate for
color modifiers.
Currently if a plugin adds a utility called `duration` it will take
precedence over the built-in utilities — or any utilities with the same
name in previously included plugins. However, in v3, we emitted matches
from _all_ plugins where possible.
Take this plugin for example which adds utilities for
`animation-duration` via the `duration-*` class:
```ts
import plugin from 'tailwindcss/plugin'
export default plugin(
function ({ matchUtilities, theme }) {
matchUtilities(
{ duration: (value) => ({ animationDuration: value }) },
{ values: theme("animationDuration") },
)
},
{
theme: {
extend: {
animationDuration: ({ theme }) => ({
...theme("transitionDuration"),
}),
}
},
}
)
```
Before this PR this plugin's `duration` utility would override the
built-in `duration` utility so you'd get this for a class like
`duration-3500`:
```css
.duration-3000 {
animation-duration: 3500ms;
}
```
Now, after this PR, we'll emit rules for `transition-duration`
(Tailwind's built-in `duration-*` utility) and `animation-duration`
(from the above plugin) and you'll get this instead:
```css
.duration-3000 {
transition-duration: 3500ms;
}
.duration-3000 {
animation-duration: 3500ms;
}
```
These are output as separate rules to ensure that they can all be sorted
appropriately against other utilities.
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR enables compatibility for the `@tailwindcss/typography` and
`@tailwindcss/forms` plugins. This required the addition of new Plugin
APIs and new package exports.
## New Plugin APIs and compatibility improvements
We added support for `addComponents`, `matchComponents`, and `prefix`.
The component APIs are an alias for the utilities APIs because the
sorting in V4 is different and emitting components in a custom `@layer`
is not necessary. Since `prefix` is not supported in V4, the `prefix()`
API is currently an identity function.
```js
addComponents({
'.btn': {
padding: '.5rem 1rem',
borderRadius: '.25rem',
fontWeight: '600',
},
'.btn-blue': {
backgroundColor: '#3490dc',
color: '#fff',
'&:hover': {
backgroundColor: '#2779bd',
},
},
'.btn-red': {
backgroundColor: '#e3342f',
color: '#fff',
'&:hover': {
backgroundColor: '#cc1f1a',
},
},
})
```
The behavioral changes effect the `addUtilities` and `matchUtilities`
functions, we now:
- Allow arrays of CSS property objects to be emitted:
```js
addUtilities({
'.text-trim': [
{'text-box-trim': 'both'},
{'text-box-edge': 'cap alphabetic'},
],
})
```
- Allow arrays of utilities
```js
addUtilities([
{
'.text-trim':{
'text-box-trim': 'both',
'text-box-edge': 'cap alphabetic',
},
}
])
```
- Allow more complicated selector names
```js
addUtilities({
'.form-input, .form-select, .form-radio': {
/* styles here */
},
'.form-input::placeholder': {
/* styles here */
},
'.form-checkbox:indeterminate:checked': {
/* styles here */
}
})
```
## New `tailwindcss/color` and `tailwindcss/defaultTheme` export
To be compatible to v3, we're adding two new exports to the tailwindcss
package. These match the default theme values as defined in v3:
```ts
import colors from 'tailwindcss/colors'
console.log(colors.red[600])
```
```ts
import theme from 'tailwindcss/defaultTheme'
console.log(theme.spacing[4])
```
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This PR adds support for the [`theme()`
function](https://tailwindcss.com/docs/plugins#dynamic-utilities) from
the v3 plugin API, used for configuring which values functional
utilities support:
```js
plugin(function({ matchUtilities, theme }) {
matchUtilities(
{
tab: (value) => ({
tabSize: value
}),
},
{ values: theme('tabSize') }
)
})
```
Things this handles:
- "Upgrading" theme keys to their v4 names, so if you do
`theme('colors')` that will correctly retrieve all the colors from the
`--color-*` namespace with the new CSS variable based configuration
- Polyfilling dependent keys, so `theme('backgroundColor')` will still
pull everything in `--color-*` even though there is no values in the
`backgroundColor` namespace in v4 by default
- Polyfilling theme values that are now handled by "bare values"
internally, so even though there is no `flexShrink` theme values in v4,
`theme('flexShrink')` will still configure your plugin to properly
support any value that the built-in `shrink-*` utilities support
Things that aren't handled:
- Theme values that have been replaced by static utilities can't be
retrieved yet, so for example `theme('cursor')` returns nothing right
now because there are no values for the `cursor-*` utilities in the
theme anymore, they are all just baked in to the framework.
This will be handled in a future PR.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR adds support for the `tailwindcss/plugin` import which has
historically been used to define custom plugins:
```js
import plugin from "tailwindcss/plugin";
export default plugin(function ({ addBase }) {
addBase({
// ...
});
});
```
This also adds support for `plugin.withOptions` which was used to define
plugins that took optional initilization options when they were
registered in your `tailwind.config.js` file:
```js
import plugin from "tailwindcss/plugin";
export default plugin.withOptions((options = {}) => {
return function ({ addBase }) {
addBase({
// ...
});
};
});
```
We've stubbed out support for the `config` argument but we're not
actually doing anything with it at the time of this PR. The scope of
this PR is just to allow people to create plugins that currently work
using the raw function syntax but using the `plugin` and
`plugin.withOptions` APIs. Support for `config` will land separately.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This PR introduces support for the v3-like `addUtilities` and
`matchUtilities` APIs in v4. We anticipate designing a new API that
feels more native to the way v4 works before shipping v4.0 stable, but
we're continuing to support these APIs for backwards compatibility.
We've tried to make the behavior as identical as possible, but because
of fundamental differences between the v3 and v4 engines there are a few
things that work differently:
## Only simple single-class selectors are supported
In v3 you could pass a complex CSS selector to `addUtilities` and we
would generate a utility for every class in the selector. In v4 we only
allow you to use a simple, single-class selector.
You should use nesting if you need a more complex selector, or need to
include at-rules like `@media` or `@supports`.
```js
// v3
function ({ addUtilities }) {
addUtilities({
'.scrollbar-none::-webkit-scrollbar': {
display: 'none',
},
})
}
// v4
function ({ addUtilities }) {
addUtilities({
'.scrollbar-none': {
'&::-webkit-scrollbar': {
display: 'none',
},
},
})
}
```
If you were adding custom utilities that included two classes and were
depending on both of those classes behaving like utilities (they could
each be used with variants), those custom utilities will need to be
rewritten as two separate utilities that each use nesting:
```js
// v3
function ({ addUtilities }) {
addUtilities({
'.section > .row': {
color: 'red',
},
})
}
// v4
function ({ addUtilities }) {
addUtilities({
'.section': {
'& > .row': {
color: 'red',
},
},
'.row': {
'section > &': {
color: 'red',
},
},
})
}
```
We may introduce support for this in the future if this limitation turns
out to be a huge pain in the ass, but crossing our fingers that people
were mostly doing simple stuff here.
## Opacity modifiers support bare values
To be consistent with how built-in utilities work in v4, custom
utilities that specify `type: "color"` now get "bare value" support for
opacity modifiers. This means that a utility like `foo-black/33` will
work out of the box without having to either add `--opacity-33` to your
theme nor would you need to add it to the `modifiers` option.
## The `preferOnConflict` type option is gone
In v3 we introduced an internal API called `preferOnConflict` for types.
This was used as a way to disambiguate between two utilities with the
same "root" but which produced different properties which used the same
CSS data types. This was only applicable to arbitrary values and was
only used for disambiguating between `background-position` and
`background-size`.
In v4, both of these properties are handled by a single plugin meaning
this feature is no longer necessary. No one should've really been using
this option anyway as it was never documented so we're dropping the
feature.
## The options `respectPrefix` and `respectImportant` are not yet
supported
Neither the `prefix` nor `important` features exist in any form in v4 at
this time. Therefore, they are not currently supported by this PR. We
will look into supporting them if/when those features return.
## The `theme(…)` function is not currently supported
Custom utilities defined using `matchUtilities` often use the `theme(…)`
function to define their default values, but we haven't implemented
support for `theme(…)` yet in v4.
This means that as of this PR, default values for custom utilities must
be hardcoded:
```js
function ({ matchUtilities }) {
matchUtilities({
'tab': (value) => {
return {
'tab-size': value,
}
},
}, {
values: {
2: '2',
4: '4',
8: '8',
},
})
}
```
Getting `theme(…)` working is a big project so we're going to tackle it
in a separate PR.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This PR bumps dependencies
We also make some dependencies `catalog:` dependencies, which allows us
to keep
the version in sync. E.g.: `lightningcss` and `@types/node`.
Bumped `turbo` to the latest version + enabled the new UI
Fixed a bug in the tests now that `lightningcss` outputs the correct
value.
This PR fixes an issue where `@apply` was not handled if it was used
inside of `@utility`.
You should now be able to do something like this:
```css
@utility btn {
@apply flex flex-col bg-white p-4 rounded-lg shadow-md;
}
```
If you then use `btn` as a class, the following CSS will be generated:
```css
.btn {
border-radius: var(--radius-lg, .5rem);
background-color: var(--color-white, #fff);
padding: var(--spacing-4, 1rem);
--tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
flex-direction: column;
display: flex;
}
```
This PR also makes sure that you can use custom `@utility` inside other
`@utility` via `@apply`. E.g.:
```css
@utility foo {
color: red;
}
@utility bar {
color: red;
@apply hover:foo;
}
```
If we detect a circular dependency, then we will throw an error since
circular dependencies are not allowed. E.g.:
```css
@utility foo {
@apply hover:bar;
}
@utility bar {
@apply focus:baz;
}
@utility baz {
@apply dark:foo;
}
```
Regardless of which utility you use, eventually it will apply itself.
Fixes: #14143
Alternative to #14110
This PR changes the way how we load plugins to be compatible with ES6
async `import`s. This allows us to load plugins even inside the browser
but it comes at a downside: We now have to change the `compile` API to
return a `Promise`...
So most of this PR is rewriting all of the call sites of `compile` to
expect a promise instead of the object.
---------
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This PR allows you to add custom utilities to your project via the new
`@utility` rule.
For example, given the following:
```css
@utility text-trim {
text-box-trim: both;
text-box-edge: cap alphabetic;
}
```
A new `text-trim` utility is available and can be used directly or with
variants:
```html
<div class="text-trim">...</div>
<div class="hover:text-trim">...</div>
<div class="lg:dark:text-trim">...</div>
```
If a utility is defined more than one time the latest definition will be
used:
```css
@utility text-trim {
text-box-trim: both;
text-box-edge: cap alphabetic;
}
@utility text-trim {
text-box-trim: both;
text-box-edge: cap ideographic;
}
```
Then using `text-trim` will produce the following CSS:
```css
.text-trim {
text-box-trim: both;
text-box-edge: cap ideographic;
}
```
You may also override specific existing utilities with this — for
example to add a `text-rendering` property to the `text-sm` utility:
```css
@utility text-sm {
font-size: var(--font-size-sm, 0.875rem);
line-height: var(--font-size-sm--line-height, 1.25rem);
text-rendering: optimizeLegibility;
}
```
Though it's preferred, should you not need to add properties, to
override the theme instead.
Lastly, utilities with special characters do not need to be escaped like
you would for a class name in a selector:
```css
@utility push-1/2 {
right: 50%;
}
```
We do however explicitly error on certain patterns that we want to
reserve for future use, for example `push-*` and `push-[15px]`.
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
* ensure that static utilities do not take a `modifier`
* do not allow multiple segments for now
Right now, `bg-red-1/2/3` should not parse
* add tests for variants that don't accept a modifier
* ensure static variants do not accept a modifier
* do not accept a modifier for some variants
* add tests for utilities that don't accept a modifier
* do not accept a modifier for some utilities
* update changelog
* re-add sorting related test
* ensure opacity modifier variables work as expected
We use `color-mix()` in v4 which means that we can use this for the
opacity modifier. One thing we do already is convert values such as
`0.5` to `50%` because that's what the `color-mix()` function expects.
However, if you use a variable like this:
```html
<div class="[--opacity:0.5] bg-red-500/[var(--opacity)]"></div>
```
This currently generates:
```css
.bg-red-500\/\[var\(--opacity\)\] {
background-color: color-mix(
in srgb,
var(--color-red-500, #ef4444) var(--opacity),
transparent
);
}
.\[--opacity\:0\.5\] {
--opacity: 0.5;
}
```
Which won't work because the opacity variable resolves to `0.5` instead
of the expected`50%`.
This commit fixes that by always ensuring that we use `* 100%`.
- If you already had a percentage, we would have `calc(50% * 100%)`
which is `50%`.
- If we have `0.5` then we would have `calc(0.5 * 100%)` which is also
`50%`.
* wrap everything but percentages in `calc(… * 100%)`
* use `else if`
* update changelog
* Use `initial` for `@property` fallbacks instead of ` `
* Update changelog
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
* Support combining arbitrary shadows without a color with shadow color utilities
* Update changelog
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>