-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Improve compatibility with Safari 15 #17435
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
Conversation
cb15f4e
to
521c5ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't functionally tested yet, but wanted to leave these notes already.
|
||
// Work around an issue where the media query range syntax transpilation | ||
// generates code that is invalid with `@media` queries level 3. | ||
out = out.replaceAll('@media not (', '@media not all and (') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😅
.text-red-500\\/\\(--my-half\\) { | ||
color: #fb2c3680; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sad that this means that you can't change the --my-half
value at runtime, but if it's not supported what can you do haha.
@@ -697,7 +708,7 @@ export async function compileAst( | |||
} | |||
|
|||
if (!utilitiesNode) { | |||
compiled ??= optimizeAst(ast, designSystem) | |||
compiled ??= optimizeAst(ast, designSystem, opts.polyfills) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should store the polyfills
on the designSystem
itself 🤔
…computation is just too flaky across OSes
…included in IntelliSense output
2ded17c
to
9244037
Compare
Sorry for the late comment, but it is my understanding that with this PR merged the general Safari support for basic Tailwind v4 goes from 16.4 to 16.2 ( |
I am facing issue with gradient if I defined a color in rgb format e.g // index.css
@theme inline {
--color-custom: rgba(111, 160, 0);
} Now If, I am using the class for gradient with opacity e.g <div class="bg-linear-to-tr from-0% to-40% from-custom/20" /> It's not working in iOS 16. Do, I need to change color to hex? |
@philipp-spiess , any help regarding this? |
@sehmbimanvir Do you have a repro please? I suppose this should work: https://play.tailwindcss.com/aqmzubxchz The play generates a |
Gradient, blur isn't working for a production build. I tried to extract using tailwind cli tool. Here are the results. /* This is at line number 3000 */
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-translate-z: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-scale-z: 1;
--tw-rotate-x: initial;
--tw-rotate-y: initial;
--tw-rotate-z: initial;
--tw-skew-x: initial;
--tw-skew-y: initial;
// more variables /* This is at line number 1600 */
.from-background-primary {
--tw-gradient-from: var(--bg-primary);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} All variables are getting generated after the actual class. So, these initial values are replacing the property being used in class. @philipp-spiess, Any help or fix for this? |
@sehmbimanvir Please attach a full reproduction here, the variables are put in an |
/** App.css */
@import 'tailwindcss';
@theme {
--color-custom-100: #e67e22;
} <div class='h-screen w-screen flex justify-center items-center'>
<div class="flex items-center justify-center h-60 w-60 rounded-xl bg-linear-to-r from-custom-100 to-red-100">Hello</div>
</div> Please find the below CSS generated by tailwind cli. /*! tailwindcss v4.1.7 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--color-red-100: oklch(93.6% 0.032 17.717);
--spacing: 0.25rem;
--radius-xl: 0.75rem;
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
--color-custom-100: #e67e22;
}
}
@layer base {
*, ::after, ::before, ::backdrop, ::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html, :host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol, ul, menu {
list-style: none;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: block;
vertical-align: middle;
}
img, video {
max-width: 100%;
height: auto;
}
button, input, select, optgroup, textarea, ::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
:-moz-ui-invalid {
box-shadow: none;
}
button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden="until-found"])) {
display: none !important;
}
}
@layer utilities {
.flex {
display: flex;
}
.h-60 {
height: calc(var(--spacing) * 60);
}
.h-screen {
height: 100vh;
}
.w-60 {
width: calc(var(--spacing) * 60);
}
.w-screen {
width: 100vw;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.rounded-xl {
border-radius: var(--radius-xl);
}
.bg-linear-to-r {
--tw-gradient-position: to right;
@supports (background-image: linear-gradient(in lab, red, red)) {
--tw-gradient-position: to right in oklab;
}
background-image: linear-gradient(var(--tw-gradient-stops));
}
.from-custom-100 {
--tw-gradient-from: var(--color-custom-100);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
}
.to-red-100 {
--tw-gradient-to: var(--color-red-100);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
}
}
@property --tw-gradient-position {
syntax: "*";
inherits: false;
}
@property --tw-gradient-from {
syntax: "<color>";
inherits: false;
initial-value: #0000;
}
@property --tw-gradient-via {
syntax: "<color>";
inherits: false;
initial-value: #0000;
}
@property --tw-gradient-to {
syntax: "<color>";
inherits: false;
initial-value: #0000;
}
@property --tw-gradient-stops {
syntax: "*";
inherits: false;
}
@property --tw-gradient-via-stops {
syntax: "*";
inherits: false;
}
@property --tw-gradient-from-position {
syntax: "<length-percentage>";
inherits: false;
initial-value: 0%;
}
@property --tw-gradient-via-position {
syntax: "<length-percentage>";
inherits: false;
initial-value: 50%;
}
@property --tw-gradient-to-position {
syntax: "<length-percentage>";
inherits: false;
initial-value: 100%;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-gradient-position: initial;
--tw-gradient-from: #0000;
--tw-gradient-via: #0000;
--tw-gradient-to: #0000;
--tw-gradient-stops: initial;
--tw-gradient-via-stops: initial;
--tw-gradient-from-position: 0%;
--tw-gradient-via-position: 50%;
--tw-gradient-to-position: 100%;
}
}
} You can see, one @layer properties is at top (which is empty) and other one is at bottom. |
Yeah this is intentional. Your CSS file and HTML seems to work fine for me in iOS 16.4 Safari, see: ![]() |
This PR improves the compatibility with Tailwind CSS v4 with unsupported browsers with the goal to greatly improve compatibility with Safari 15.
To make this work, this PR makes the following changes to all code
oklab(…)
default theme values to use a percentage in the first place (so instead of--color-red-500: oklch(0.637 0.237 25.331);
we now define it as--color-red-500: oklch(63.7% 0.237 25.331);
since this syntax has much broader support on Safari).@property
with a@supports
query targeting older versions of Safari and Firefox *color-mix(…)
function that use inlined color values from your theme so that they can be computed a compile time bylightningcss
. These fallbacks will convert to srgb to increase compatibility.color-mix(…)
in case relative color is applied oncurrentcolor
(due to limited browser support)bg-linear-to-r/oklab
)@media
queries range syntax.A simplified example
Given this example CSS input:
Here's the updated output CSS including the newly added polyfills and updated
oklab
values:* A note on
@property
polyfills and CSS modulesOn Next.js, CSS module files are required to be pure, meaning that all selectors must either be scoped to a class or an ID. Fortunatnyl for us, this does not apply to
@property
rules which we've been using before to initialize CSS variables.However, since we're now bringing back the
@property
polyfills, that would cause unexpected rules to be exported from the CSS file as this:Would turn to the following file:
Notice that this adds a
*
selector which is not considered pure.Unfortunately there is no way for us to silence this warning or work around it, as the dependency causing this errors (
postcss-modules-local-by-default
) is bundled into Next.js. To work around crashes, these polyfills will not apply to CSS modules processed by the PostCSS extension for now.Testing on tailwindcss.com
To see the changes in effect, take a look at this screencast that compares tailwindcss.com on iOS 15.5 with a version that has the patches of this PR applied:
Screen.Recording.2025-03-28.at.17.52.25.mov
Open questions
@property
polyfill not require an@layer base
and instead place the generated CSS on the top of the file?@media
range query workaroundTest plan