レスポンシブデザインで Tailwind CSS と CSS custom properties を併用する体験が良過ぎる
Tailwind CSS での開発体験が個人的に最高すぎて、最近はどんなWebサイトの実装でも利用しています。
CSS custom properties を併用することもあり、そのときに嬉しいことを紹介します。
Next.js を使っている前提でコード・ファイル名を例示しますが、他でも扱えると思います。
CSS custom properties 併用したい場面
- スマートフォンでは、コンテンツを端から 16px の位置に置く
- パソコンでは、コンテンツ幅を 960px にし中央寄せにする
こんなデザイン仕様、レスポンシブデザインだとよく出きます。
tailwind.config.js
でテーマを拡張して実装すると以下のようになります。
import type { Config } from 'tailwindcss';
export default {
theme: {
extend: {
spacing: {
'content-width-sp': 'calc(100% - 32px)',
'content-side-width-sp': '16px',
'content-width-pc': '960px',
'content-side-width-pc': 'calc((100% - 960px) / 2)',
},
},
},
} satisfies Config;
export const Section: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return <section className="px-content-side-width-sp md:px-content-side-width-pc ...">{children}</section>
};
export const Dialog: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return <dialog className="w-content-width-sp md:w-content-width-pc ...">{children}</dialog>
};
メディアクエリを伴ったテーマの拡張はできません。
利用ごとに「スマホでは、PCでは、」と書く必要があり、面倒くさいです。
そこで CSS custom properties の出番です。
CSS custom properties で書き直し
import type { Config } from 'tailwindcss';
export default {
theme: {
extend: {
spacing: {
'content-width': 'var(--content-width)',
'content-side-width': 'var(--content-side-width)',
},
},
},
} satisfies Config;
@tailwind ...;
:root {
--content-width: calc(100% - var(--content-side-width) * 2);
--content-side-width: 16px;
@media screen(md) {
--content-width: 960px;
--content-side-width: calc((100% - var(--content-width)) / 2);
}
}
export const Section: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return <section className="px-content-side-width ...">{children}</section>
};
export const Dialog: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return <dialog className="w-content-width ...">{children}</dialog>
};
メディアクエリによって、デバイス幅ごとに CSS custom properties が変わります。
これで、class 名を二重で書く必要はなくなりました。
ただ、見慣れないコード @media screen(md)
が気になるかと思います。
これこそ、良い体験を作っている Tailwind CSS の機能です。
Tailwind CSS の嬉しい機能
CSS ファイルで使える関数 screen()
が用意されています。
これで、レスポンシブデザインのブレークポイントを CSS 側で二重に宣言する必要もなく、テーマで定義しているスクリーン名をそのままメディアクエリに変換してくれます。
テーマのスクリーンを拡張、上書きしている場合でも、クラス名と同じスクリーン名を利用できるわけです。
またもう一つの関数に theme()
が存在します。
例示した 16px
も、テーマで定義した単位で扱うこともできます。
デフォルトのテーマで mt-4
が margin-top: 16px
となる感じですね。
:root {
--content-width: calc(100% - var(--content-side-width) * 2);
--content-side-width: theme(spacing.4);
}
これらの関数は、PostCSS で変換されるようになっています。
Tailwind CSS 専用の PostCSS プラグインという認識でよさそうです。
はまった点と解決
最初 @tailwind ...
などを記述している、グローバルな css を global.scss
という scss ファイルで管理していました。
ただこれだと、scss から css にビルドする段階で、@media screen()
の変換ができず、エラーが出てしまいます。global.css
にして解決しました。
css 単体でネストしたスタイルの記述もできるようになりましたし、拡張子変えるだけで基本オッケーのはずです。
追記 (2023.5.1)
せっかくなので、tailwind.config.ts
にしたコードに変更しました。
Discussion