2021年12月25日

プログラミング

vanilla-extractで型安全なCSSを書こう!

目次

  1. はじめに
  2. vanilla-extractの書き方
  3. TypeScriptでCSSを書くことのメリット
  4. JSでCSSを扱う際によく直面する課題
  5. まとめ

はじめに

この記事は新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay25の記事です!ついに最終日です!

昨日は「Miroを使ったプロジェクトの振り返り」についての記事でした。

Miroを使ったプロジェクトの振り返り

今日はvanilla-extractという2021年5月にv1.0.0がリリースされた新しいCSSライブラリについてです。
大きな特徴としてTypeScriptをプリプロセッサとして用いており、型安全なCSSを書くことができます。
またbuild時にCSSファイルが生成されるので、読み込み時のパフォーマンスに影響を与えないことも特徴です(zero-runtime)。

vanilla-extractの書き方

ライブラリから提供されているstyleメソッドの中にCSSを書いていきます。
返り値であるcontainerにはHome__1dz81cn0といったハッシュ付きのクラス名が与えられます。この文字列はモジュール内で閉じており、他のモジュール内のクラス名とぶつかることがないです。やっていることはCSS Moduleに近いですね。

POINT!!

styleメソッドを使う際にはcss.tsファイル内に書く必要があります。

// Home.css.ts

import { style } from '@vanilla-extract/css';

export const container = style({
  padding: "0 2rem",
})

そしてexportしたクラス名をclassnameに与えることでスタイルが当たります!

// Home.tsx

import { container } from './Home.css';

export const Home = () => {
  return (
    <div classname={container}></div>
  )
}

注意点

vanilla-extractではstyleメソッド内で生のCSSを扱えるため、表現の幅が広いという長所がありますが、以下のようなセレクタは使えません。

// styles.css.ts

import { style } from '@vanilla-extract/css';

export const parentClass = style({});

export const childClass = style({
  selectors: {
    // これはOK
    [`${parentClass}:focus &`]: {
      background: '#fafafa'
    },
    // これはNG
    '& a[href]': {
      background: '#fafafa'
    }
  },
});

vanilla-extractではメンテナンス性を損なわないように、自分自身以外の要素に対するセレクタを使うとエラーを出します。
自由なCSSをあえて制限することでメンテナンス性を重視する、vanilla-extractの思想が伺えます。

TypeScriptでCSSを書くことのメリット

(エディタにVS Codeを使用することで特に得られるメリットです)

補完が効く

image.png (135.0 kB)
CSSのプロパティ、値それぞれにTypeScriptによる補完があります。
また、一つのクラス名に同じプロパティを付けようとするとTypeScriptがエラーを返してくれるので、重複したプロパティを防ぐことができます。

定義元にジャンプできる

Untitled2.gif (1.1 MB)
VS Codeの「定義元にジャンプ」を使うことで、該当のクラス名にスタイルを定義した場所に飛ぶことができます。
普通にCSS Modulesを使うときには得られないメリットで(d.tsファイルに飛んでしまう)、開発者としては地味に嬉しい機能だなと思います。
また、「参照に移動」からクラス名が使われている場所を探して元の場所に戻ることもできます。

JSでCSSを扱う際によく直面する課題

複数のクラス名を並べて使ったとき

// Home.css.ts

import { style } from '@vanilla-extract/css';

export const red = style({ color: "red" })
export const blue = style({ color: "blue" })
// Home.tsx

import { red, blue } from './Home.css';

export const Home = () => {
  return (
    <h1 classname={`${red} ${blue}`}>Foo Bar</h1>
  )
}

このようにテキストカラーに異なる色を指定したとき、「Foo Bar」の文字の色は赤になるか青になるかわかりません。
${red} ${blue}というように書いたのだから後に書いたblueが適用されるはずだ、と考えたいところですが実際には両者の詳細度によって結果が変わってきてしまいます。

vanilla-extractに限らず他の多くのCSSライブラリでも同様の問題があり、この問題の解決にはまだ時間がかかりそうです。

propsによってクラス名を切り替えたい場合

ReactでCSSを書くときによくある要望として、propsやstateでDOM要素に与えたいクラス名を切り替えたい場合があります。
vanilla-extractではこのような場合、三項演算子を使うと上手く表現できます。

// Home.tsx

import { red, blue } from './Home.css';

type HomeProps = {
  isRed: boolean
}

export const Home = ({ isRed }: HomeProps) => {
  return (
    <h1 classname={isRed ? red : blue}>Foo Bar</h1>
  )
}

まとめ

まだcreate-react-appで少し使いづらかったり、用意されているメソッドも少なめですが、TypeScriptによる恩恵を受けながらCSSを書く体験は、非常にいいものでした。
これからもアップデートされてより洗練されたライブラリになっていく予感はしているので、今後もキャッチアップしていきたいと思います!

TypeScriptのお仕事に関するご相談

Bageleeの運営会社、palanではTypeScriptに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。

無料相談フォームへ

0

0

AUTHOR

kobari

taishi kobari

フロントエンドの開発を主に担当してます。Blitz.js好きです。

アプリでもっと便利に!気になる記事をチェック!

記事のお気に入り登録やランキングが表示される昨日に対応!毎日の情報収集や調べ物にもっと身近なメディアになりました。

簡単に自分で作れるWebAR

「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。

palanARへ
palanar

palanはWebARの開発を
行っています

弊社では企画からサービスの公開終了まで一緒に関わらせていただきます。 企画からシステム開発、3DCG、デザインまで一貫して承ります。

webar_waterpark

palanでは一緒に働く仲間を募集しています

正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。

話を聞いてみたい

運営メンバー

eishis

Eishi Saito 総務

SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。

sasakki デザイナー

アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。

yamakawa

やまかわたかし デザイナー

フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。

Sayaka Osanai デザイナー

Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。

はらた

はらた エンジニア

サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

kobori

こぼり ともろう エンジニア

サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。

sasai

ささい エンジニア

フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。

damien

Damien

WebAR/VRの企画・開発をやっています。森に住んでいます。

ゲスト bagelee

ゲスト bagelee

かっきー

かっきー

まりな

まりな

suzuki

suzuki

miyagi

ogawa

ogawa

雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。

いわもと

いわもと

デザイナーをしています。 好きな食べ物はラーメンです。

kobari

taishi kobari

フロントエンドの開発を主に担当してます。Blitz.js好きです。

shogokubota

kubota shogo

サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!

nishi tomoya

aihara

aihara

グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。

nagao

SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。

kainuma

Kainuma

サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

sugimoto

sugimoto

asama

ando

CONTACT PAGE TOP