vanilla-extract探訪
@vanilla-extract/sprinkles について
@vanilla-extract/sprinkles
というライブラリを使うと、tailwindみたいなユーティリティCSSを組み合わせたスタイリングを実現できる。
properties
properties
フィールドのみを用いたコード例はこんな感じである。
import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'
const colorProperties = defineProperties({
properties: {
color: ['red', 'green', 'blue'],
backgroundColor: ['cyan', 'magenta', 'yellow'],
}
})
export const sprinkles = createSprinkles(colorProperties)
するとこのようなCSSを生成する。(セレクタは説明のためにわかりやすくした)。
1つのプロパティに渡された値ごとにスタイルを生成する。
.sprinkle-color-red1 {
color: red;
}
.sprinkle-color-green1 {
color: green;
}
.sprinkle-color-blue1 {
color: blue;
}
.sprinkle-backgroundColor-cyan1 {
background-color: cyan;
}
.sprinkle-backgroundColor-magenta1 {
background-color: magenta;
}
.sprinkle-backgroundColor-yellow1 {
background-color: yellow;
}
sprinkles
関数を利用すると、指定したスタイルに必要なクラス名をまとめた文字列を生成してくれる。
import { sprinkles } from '~/sprinkles.css.ts'
export const redText = sprinkles({
// `colorProperties` の `color` プロパティに `red` が入っているので指定できる
color: 'red',
// `colorProperties` の `backgroundColor ` プロパティに `yellow ` が入っているので指定できる
backgroundColor: 'yellow',
})
上記の redText
には ".sprinkle-color-red1 .sprinkle-backgroundColor-yellow1
が入る。
@vanilla-extract/css
の style
関数を用いる場合と比較すると、 クラス名が長くなる代わりにCSSが小さくなる。Tailwindと同様に、同じようなスタイルを利用するのであればCSSが増えにくいはずである。
一方で、Tailwindはデフォルトで様々な値が用意されているのに対して、vanilla-extractのsprinklesでは必要な値を自分で指定しなければならない。もちろんTailwindをしっかり使う場合には自分で色情報だったりサイズだったりを指定することになるとは思う。
また、指定していないプロパティや値を渡そうとすると型チェックで弾いてくれる。
export const redBackground = sprinkles({
// @ts-expect-error 未定義のプロパティに値を設定することはできない
borderColor: 'red',
})
export const yellowText = sprinkles({
// @ts-expect-error `sprinkles` に渡した `color` プロパティで未定義の値は指定できない
color: 'yellow',
})
shorthands
例えば padding
は、tailwindだと pl-2
のように1つずつ指定する方法もあれば、p-2
、 px-2
のようにまとめて指定方法がある。これと同等の機能を shorthands
プロパティで実現できる。
const sizes = [4, 8, 12] as const
const sizePropeties = defineProperties({
properties: {
paddingTop: sizes,
paddingRight: sizes,
paddingBottom: sizes,
paddingLeft: sizes,
},
shorthands: {
padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
paddingX: ['paddingRight', 'paddingLeft'],
},
})
このように設定することで、 sprinkles({ padding: 8 })
や sprinkles({ paddingX: 12 })
のようにして複数項目を一括指定できる。
Tailwindと比較すると、Tailwindは p-2
と px-2
では異なるスタイル定義になるのに対し、vanilla-extractではアトミックなCSSを組み合わせて実現する点で異なっている。
conditions, defaultCondition
conditionsを使えばメディアクエリや疑似クラスごとに異なる値を指定できるようになる。
キーはわかりやすい名前をつけておくとよさそう。
const colorProperties = defineProperties({
conditions: {
default: {},
hover: { selector: '&:focus' },
},
defaultCondition: 'default',
properties: {
color: ['red', 'green', 'blue'],
backgroundColor: ['cyan', 'magenta', 'yellow'],
}
})
const
すると以下のようなCSSを生成する。コンディションごとに別々のクラス名を生成するようである。
.sprinkle-color-red1,
.sprinkle-color-red2:hover {
color: red;
}
.sprinkle-color-green1,
.sprinkle-color-green2:hover {
color: green;
}
.sprinkle-color-blue1,
.sprinkle-color-blue2:hover {
color: blue;
}
.sprinkle-backgroundColor-cyan1,
.sprinkle-backgroundColor-cyan2:hover {
background-color: cyan;
}
.sprinkle-backgroundColor-magenta1,
.sprinkle-backgroundColor-magenta2:hover {
background-color: magenta;
}
.sprinkle-backgroundColor-yellow1,
.sprinkle-backgroundColor-yellow2:hover {
background-color: yellow;
}
そして、 sprinkles({ color: { default: 'green', hover: 'blue' } })
と書くと、2つのクラス名を合体させた文字列を得られる。
セレクタ以外にもメディアクエリやコンテナクエリなどを条件に指定できる。
Tailwindにおける hover:
や md:
といったプレフィクスを自前で用意するに相当すると言える。