スタイリングは、ウェブサイトの見た目を定義し、まとまりのある審美的なブランドの作成を可能にします。ウェブページのスタイリングにはCascading Style Sheets(CSS) を使用する手もありますが、JavaScriptベースのソリューションはより柔軟で、標準的なCSSよりもコントロールしやすくなっています。

よく使われる方法のひとつに、JavaScriptスタイルシート(JSS)があります。JSSには、動的なスタイルやテーマを作成するための変数、JavaScript式、関数の使用など、いくつもの強みがあります。

今回の記事では、JSSの仕組みや利点、JavaScriptアプリケーションでの使用方法についてご説明します。また、動的なスタイル設定、テーマ設定、パフォーマンスの最適化についても触れます。JSSはさまざまな状況で使用できますが、この記事ではReactのJSSに焦点を当てることにします。

JSSとは

JSSを使うと、CSSスタイルをJavaScriptオブジェクトとして記述し、そのオブジェクトを要素やコンポーネントのクラス名として使うことができます。JSSはフレームワークに依存しないので、バニラJavaScriptでもReactAngularのようなフレームワークでも使えます。

JSSには、従来のCSSスタイルよりも優れた点がいくつかあります。

  • 動的なスタイリング─JSSを使えば、ユーザーのインタラクション、propsやコンテキストのような値に基づいてスタイルを操作できます。JavaScriptの関数は、アプリケーションの状態、外部データ、またはブラウザAPIに応じて、ブラウザで動的にスタイルを生成するのに有用です。
  • テーマ設定機能の向上─JSSを使用して、特定のテーマに特化したスタイルを作成できます。たとえば、明るい(ライト)テーマと暗い(ダーク)テーマのスタイルを作成し、ユーザーの好みに応じてこれらのテーマ固有のスタイルをアプリケーション全体に適用できます。Reactの場合、React-JSSパッケージはコンテキストベースのテーマ伝搬をサポートしています。テーマプロバイダを使用してコンポーネントツリーの下層にテーマ情報を渡す前に、一箇所でテーマを定義し管理できます。
  • 保守性の向上 ─JavaScriptオブジェクトでスタイルを定義することで、関連するスタイルを1つの場所にまとめ、必要なときにアプリケーションにインポートできます。このアプローチにより、コードの重複が減り、コードの構成が改善されるため、長期間にわたってスタイルを維持しやすくなります。
  • 慣れ親しんだCSS─JSSは、乱雑で管理しにくいインラインスタイル形式ではなく、扱いやすいCSSを生成します。JSSはデフォルトでユニークなクラス名を使用するため、CSSのグローバルな性質によって引き起こされる名前の衝突を避けることができます。

JSSでスタイルを記述する方法

この説明では、Reactプロジェクトを使用します。さらにHooks APIを用いてJSSとReactを統合するreact-jssパッケージを使用しています。react-jssにはデフォルトのプラグインが付属しており、最小限のセットアップでJSSを使用できます。

ReactでのJSSの基本構文と使い方

ReactでJSSを使うには、まずnpmやYarnなどのパッケージマネージャを使ってreact-jssパッケージをインストールします。

JSSでスタイルを記述する構文では、JavaScriptオブジェクト内の特定の要素に対してCSSルールを定義します。例えば、以下のコードはReactアプリのボタンのスタイルを定義しています。


const styles = {
      button: {
            padding: "10px 20px",
            background: "#f7df1e",
            textAlign: "center",
            border:"none"
      }
};

)CSSプロパティはキャメルケースで記述します。

このスタイルをHTML要素に適用する方法は以下の通りです。

    1. スタイルをreact-jssからcreateUseStyles()メソッドに渡しクラスを生成します。
import { createUseStyles } from "react-jss";
const styles = {
       button: {
             padding: "10px 20px",
             background: "#f7df1e",
             textAlign: "center",
             border:"none"
       }
};
const useStyles = createUseStyles(styles);
  1. 生成されたクラス名を使ってボタン要素にCSSを適用します。
const App = () = > {
      const classes = useStyles();
      return (
            < button className={classes.button} > </button >
      );
};

このコードでは、Reactコンポーネントを作成し、stylesオブジェクト内のスタイルを適用しています。

擬似クラス、メディアクエリ、キーフレームの扱い方

JSSは、擬似クラス、メディアクエリ、キーフレームを含む、既存のすべてのCSS機能をサポートしています。これらの機能のスタイルを定義するには、通常のCSSスタイルルールと同じ構文を使用してください。

擬似クラス

たとえば、ユーザーがボタンの上にマウスを移動したときに背景色を変更できるように、ボタンにホバーの擬似クラスを追加したいとします。次のコードはこの擬似クラスを実装し、ホバー時にボタンの背景が薄緑色になるようにします。

const styles = {
      button: {
            padding: "10px 20px",
            background: "#f7df1e",
            textAlign: "center",
            border:"none",
            '&:hover': {
                  backgroundColor: 'lightgreen',
            }
     }
};

キーフレーム

同様に、@keyframesルールを使用して、キーフレームアニメーションをコンポーネントに適用できます。例えば、以下は回転するコンポーネントのスタイルオブジェクトです。

const styles = {
       '@keyframes spin': {
             '0%': {
                   transform: 'rotate(0deg)',
             },
             '100%': {
                   transform: 'rotate(360deg)',
             },
       },
       spinner: {
              width: "100px",
              height: "100px",
              backgroundColor: "lightgreen",
              animation: '$spin 1s linear infinite',
       },
}

styles関数内で、@keyframesルールを使用して、spinというキーフレームアニメーションを定義します。次に、$構文を使用してアニメーションを適用するspinnerというクラスを作成し、キーフレームアニメーションを参照します。

メディアクエリ

メディアクエリもJSSの通常のCSS構文を使います。たとえば、特定の画面サイズでボタンのフォントサイズを変更するには、次のスタイルを使用します。

const styles = {
      button: {
            fontSize: "12px",
            '@media (max-width: 768px)': {
                  fontSize: '34px',
            },
      }
};

ここまで見てきたように、JSSでスタイルを書くことは、通常のCSSを書くこととそれほど変わりません。しかし、JSSの利点は、JavaScriptの性能を活用してスタイルを動的にできることです。

JSSによる動的なスタイル設定

動的スタイルとは、特定の条件に応じて変化するスタイルを意味します。Reactでは、state、props、コンポーネントのコンテキストなどの値に応じてスタイルが変化します。

JSSで動的にスタイルを変化させる方法

JSSでは、JavaScriptの式を使って要素に条件付きでスタイルを適用し、動的なスタイルルールを作成することができます。

bgColorというpropsを受け取るボタンがあるとします。その値はボタンの背景色です。propsに基づいてボタンの背景色を変更するスタイルルールを作成するには、useStylesメソッドにpropsを渡します。

import { createUseStyles } from "react-jss"

const styles = {
      button: {
            padding: "10px 20px",
            background: props = >props.bgColor,
            textAlign: "center",
            border:"none"
      }
};
const Button = ({...props}) => {
  
      const useStyles = createUseStyles(styles);
      const classes = useStyles({...props});
      return (
            <button className={classes.button}>Button </button>
      );
};

そして、stylesオブジェクトでpropsを参照します。上の例では、props.bgColorを参照しています。

コンポーネントをレンダリングするときに、必要な背景色を渡すことができます。以下のコンポーネントは、lightgreenyellowの背景色を持つ2つのButtonコンポーネントをレンダリングします。

export default function App() {
  return (
    <div >
      <Button bgColor="lightgreen" />
      <div style={{ marginTop: "10px" }}></div>
      <Button bgColor="yellow" />
    </div>
  );
}
Two buttons dynamically styled with JSS
JSSで動的に2つのボタンにスタイルを適用する

Buttonコンポーネントをレンダリングするたびに、好きなように背景をスタイルできます。

また、コンポーネントの状態(state)に応じてスタイルを変更することもできます。ナビゲーションメニューにいくつかのリンク項目があるとします。現在のページのリンクをハイライトするには、isActiveという状態値を定義して、メニューのリンク項目が有効かどうかを追跡します。

そして、JavaScriptの三項演算子を使ってisActiveの値をチェックし、状態(state)がtrueの場合はリンクの色を青に、falseの場合は赤に設定します。

const styles = {
      a: {
             color: ({ isActive }) => isActive ? 'blue' : 'red',
             padding: '10px',
      },
};

これで、有効なリンクは青に、そうでないリンクは赤になります。

同様に、コンテキストに基づいて動的にスタイルを適用することもできます。利用者のオンラインステータスを保存するコンテキストの値に基づいて、UserContextのような要素をスタイルすることが可能です。

const { online } = useContext(UserContext);
const styles = {
      status: {
            background: online ? 'lightgreen' : '',
            width: '20px',
            height: '20px',
            borderRadius: "50%",
            display: online ? 'flex' : 'hidden'
      },
};

この例では、ユーザーがオンラインの場合、要素の背景は緑色になります。ユーザーがオンラインの場合はdisplayプロパティをflexに設定し、オフラインの場合はhiddenに設定します。

動的スタイルの使用例

動的スタイルはJSSの便利な機能であり、多くの使用例があります。

  • テーマ─ライトテーマやダークテーマなど、テーマオブジェクトに基づいてスタイルを定義し、propsやコンテキスト値としてコンポーネントに渡すことができます。
  • 条件付きレンダリング─JSSでは、特定の値に基づいてスタイルを定義できます。たとえば、ボタンが無効になっているとき、テキストフィールドがエラー状態になっているとき、サイドナビゲーションメニューが開いているとき、ユーザーがオンラインになっているときなど、特定の条件下でのみ適用されるスタイルを用意できます。
  • レスポンシブデザイン─JSS の動的スタイルを使用して、ビューポートの幅に基づいて要素のスタイルを変更できます。たとえば、メディアクエリを使用して特定のブレイクポイントのスタイルを定義し、画面サイズに基づいて条件付きで適用可能です。

JSSとテーマを組み合わせて使用する方法

テーマを使用して、アプリケーション全体で一貫したユーザーインターフェースを提供することができます。JSSでのテーマ作成は簡単です。色、タイポグラフィ、空白などのグローバルなスタイル値を持つテーマオブジェクトを定義するだけでOKです。例えば以下の通りです。

const theme = {
      colors: {
            primary: '#007bff',
            secondary: '#6c757d',
            light: '#f8f9fa',
            dark: '#343a40',
       },
       typography: {
             fontFamily: 'Helvetica, Arial, sans-serif',
             fontSize: '16px',
             fontWeight: 'normal',
       },
       spacing: {
             small: '16px',
             medium: '24px',
             large: '32px',
       },
};

コンポーネントにテーマを適用するには、コンテキストプロバイダを使用します。JSSライブラリでは、テーマへのアクセスが必要なコンポーネントをラップできるThemeProviderコンポーネントが利用可能です。

次の例では、ButtonThemeProviderコンポーネントでラップし、themeオブジェクトをpropsとして渡しています。

import { ThemeProvider } from "react-jss";
const App = () => (
      <ThemeProvider theme={theme}>
            <Button />
      </ThemeProvider>
)

useTheme()フックを使用してButtonコンポーネントのテーマにアクセスし、useStylesオブジェクトに渡します。以下の例では、themeオブジェクトで定義されたスタイルを使用しプライマリボタンを作成しています。

import { useTheme } from “react-jss”

const useStyles = createUseStyles({
  primaryButton: {
    background: ({ theme }) => theme.colors.primary,
    font: ({ theme }) => theme.typography.fontFamily,
    fontSize: ({ theme }) => theme.typography.fontSize,
    padding: ({ theme }) => theme.spacing.medium
  }
});

const Button = () => {
      const theme = useTheme()
      const classes = useStyles({theme})
      return (
            <div>
              <button className={classes.primaryButton}> Primary Button </button>
            </div>

      )
}

ボタンは下の画像のようになり、長方形の青いボタンに黒いテキストが表示されます。

A primary button style based on the theme.
テーマに基づくメインのボタンのスタイル調整

themeオブジェクトの値を変更すると、自動的に新しいスタイルがトリガーされ、ThemeProviderコンポーネントでラップしたすべてのコンポーネントに適用されます。原色の値をlightgreenに変更すると、下の画像のようにボタンの色も黄緑色に変わります。

A primary button color adapts to the theme.
メインのボタンの色がテーマに応じて変化

テーマを作成する際の指標をいくつかご紹介します。

  • コードを整理して保守しやすくするために、テーマオブジェクトを別のファイルで定義する
  • スタイル値には説明的な名前を使用して、テーマオブジェクトを読みやすく、更新しやすくする
  • CSS変数を使用して、CSS全体でよく使用する値を定義する
  • アプリケーション全体で一貫したデザインを維持するために、すべてのスタイルプロパティにデフォルト値を用意する
  • テーマを徹底的にテストし、すべてのデバイスとブラウザで意図したとおりに動作することを確認

これらのベストプラクティスに従うことで、使いやすく、アプリケーションの成長に合わせて更新しやすいテーマを作成できます。

パフォーマンスと最適化

JSSはパフォーマンスの面で優れたスタイル設定の一手法です。JSSでは、画面上で使用されているスタイルだけがDocument Object Model (DOM) に追加されるため、DOMサイズ縮小が実現し、レンダリングが素早くなります。また、JSSはレンダリングしたスタイルをキャッシュするため、CSSのコンパイルは一度だけとなり、パフォーマンスがさらに向上します。

さらにパフォーマンスを最適化するには react-jssパッケージの代わりにJSSパッケージを使うこともできます。たとえば、react-jssではコンポーネントのアンマウントに際しスタイルシートが削除されます。また、重要なCSS抽出を処理し、レンダリング後のコンポーネントからのみスタイルを抽出します。このようにして、react-jssパッケージによりCSSバンドルのサイズを削減し、読み込み時間を改善できます。

CSSバンドルのサイズをさらに小さくするには、コードを分割し、特定のページまたはコンポーネントが必要とするCSSだけを読み込むことが可能です。loadable-componentsのようなライブラリを使うと、コード分割が簡単になります。

JSSでは、サーバーサイドでCSSを生成することもできます。JSSのStyleSheetレジストリクラスを使用して、CSSを集約して文字列化し、レンダリングしたコンポーネントとCSS文字列をクライアントに送信できます。アプリケーションを起動した後は、静的なCSSは不要になるので、削除してバンドルサイズを小さくすることができます。

まとめ

JSS構文の基本、スタイルオブジェクトを作成してコンポーネントに適用する方法、および動的スタイルを定義する方法をご紹介しました。また、ThemeProviderコンポーネントを使用してテーマを適用し、JSSのパフォーマンスを引き上げる方法もご理解いただけたと思います。これで、JSSを使用して、さまざまな条件に適応する、再利用可能かつ保守しやすい動的スタイルの活用ができるはずです。