Tailwind CSS 4では、transition
ユーティリティおよびtransition-colors
ユーティリティのtransition-property
プロパティにoutline-color
プロパティが含まれるように変更された(参考: Upgrade guide - Getting started - Tailwind CSS)。
変更前(Tailwind CSS 3):
.transition {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition-colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
変更後(Tailwind CSS 4):
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.transition-colors {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
これにともなって、要素をフォーカスしたときのインジケータの色が一瞬currentcolor
になってしまう問題が生じることがある。
Chromeのユーザーエージェントスタイルシートでは、フォーカス時のoutline-color
プロパティの値として-webkit-focus-ring-color
が指定されている。
:focus-visible {
outline: auto 1px -webkit-focus-ring-color
}
通常は即座にこの色に変化するが、transition
の対象になっていると、currentcolor
を開始点として-webkit-focus-ring-color
に遷移するという挙動になる。これによって、一瞬黒く見えてしまう。
このような挙動になるのはChromeのみで、SafariやFirefoxではtransitionが有効にならない。とはいえ、このような挙動は好ましくないため、何かしらの方法で修正する必要がある。
Tailwind CSSのUpgrade Guideでは、そのための回避策として、条件にかかわらずoutline-color
の値が変化しないように指定することが提案されている。
-<button class="transition hover:outline-2 hover:outline-cyan-500"></button>
+<button class="outline-cyan-500 transition hover:outline-2"></button>
しかし、フォーカス可能なすべての要素に対してこのような指定をすることは現実的ではない。このような個別の指定が必要になると、必然的に間違いが起こるだろう。そのため、代わりとなる別のアプローチをいくつか挙げて検討してみる。
1. transition-property
のデフォルト値を上書きする
最初に考えられる方法としては、transition-property
プロパティの値からoutline-color
プロパティを取り除くことだ。そのために、それぞれのユーティリティの実装を調べてみる。
まず、transition
ユーティリティは次のように実装されている。
functionalUtility('transition', {
defaultValue:
'color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events',
themeKeys: ['--transition-property'],
handle: (value) => [
decl('transition-property', value),
decl('transition-timing-function', defaultTimingFunction),
decl('transition-duration', defaultDuration),
],
})
もう一方の、transition-colors
ユーティリティは次のように実装されている。
staticUtility('transition-colors', [
[
'transition-property',
'color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to',
],
['transition-timing-function', defaultTimingFunction],
['transition-duration', defaultDuration],
])
これらを上書きするには、@utility
ディレクティブを使ってCSSを記述する。ここで指定されている値からoutline-color
プロパティを取り除いて指定する。
@utility transition {
transition-property:
color, background-color, border-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
}
@utility transition-colors {
transition-property:
color, background-color, border-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
}
ただし、これらユーティリティのプロパティ値は予期せず変更される可能性があるため、Tailwind CSSのアップデートにともなう変更を監視して追従できるようにしておく必要がある。
2. transition
ユーティリティの対象プロパティを個別に指定する
transition
ユーティリティ自体の実装に手を入れずとも、arbitrary valuesとしてユーティリティの値を調整することはできる。次のようにして対象のプロパティだけを個別に指定すれば、意図しないプロパティのtransitionが有効になってしまうことを回避できる。
<button class="bg-blue-500 transition-[background-color] hover:bg-indigo-500"><!-- ... --></button>
3. フォーカス可能な要素すべてのoutline-color
プロパティにデフォルト値を指定する
先ほどの説明の繰り返しになるが、outline-color
プロパティの値が変化しないように指定すれば意図しないtransitionを回避できる。
-<button class="transition hover:outline-2 hover:outline-cyan-500"></button>
+<button class="outline-cyan-500 transition hover:outline-2"></button>
この例はカスタムのoutline-color
プロパティを適用するものだが、ブラウザデフォルトのフォーカスリングを適用したい場合には次のようにする。
<button class="outline-[-webkit-focus-ring-color] transition"><!-- ... --></button>
これによって、要素がフォーカスされてフォーカスリングが表示される際のtransitionを無効化できる。
Firefoxではフォーカス時のoutline-color
プロパティの値はcurrentcolor
になっているが、このように-webkit-focus-ring-color
を指定した場合はパースエラーとして扱われて無視される。
4. すべての要素のoutline-color
プロパティのデフォルト値を上書きする
outline-color
プロパティを個別に設定するアプローチでは、やはり作業の抜け漏れが生じる可能性がある。それよりも、あらかじめすべての要素のプロパティ値を指定してしまうのが良いだろう。次のようにして実装する。
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
outline-color: -webkit-focus-ring-color;
}
}