CSS 変数に基づくテーマ切り替えに最適なソリューション (推奨)

CSS 変数に基づくテーマ切り替えに最適なソリューション (推奨)

この要件を受け取ったとき、Baidu は、CSS リンクの置き換え、className の変更、less.modifyVars、css in js など、業界でテーマを切り替えるための多くのソリューションを見つけましたが、どのソリューションも面倒で高価に思えました。コードの侵入が少なく、使いやすく、保守しやすいソリューションはありますか?もちろんあります。より正確に言うと、CSS 自体がそれをサポートしています。

CSS3 変数

グローバル カラー変数を定義します。この変数の値を変更すると、ページ内でこの変数を参照するすべての要素が変更されます。とてもシンプルですね。

// ベース.less
:根 {
  --プライマリ: 緑;
  --警告: 黄色;
  --情報: 白;
  --危険: 赤;
}

// var.less
@プライマリ: var(--プライマリ)
@危険: var(--危険)
@info: var(--info)

// ページなし
.ヘッダー{
  背景色: @primary;
  色: @info;
}
。コンテンツ {
  境界線: 1px 実線 @danger;
}
//変更.js
関数 changeTheme(themeObj) {
  const vars = Object.keys(themeObj).map(key => `--${key}:${themeObj[key]}`).join(';')
  document.documentElement.setAttribute('style', vars)
}

この記事の終わり

くそ、 IEをサポートしていない! ! 2020 年でも IE と互換性がありますか?はい、IE と互換性がある必要があります。

CSS 変数 ポニーフィル

はい、IE と互換性のあるポリフィルがあります: css-vars-ponyfill。 IEの扱い方

+-------------------------+
| ページ内のスタイル タグのコンテンツを取得します |
| 外部リンク CSS コンテンツをリクエスト |
+-------------------------+
|
|

+-------------------------+ はい +-------------------------+
| コンテンツに var() が含まれていますか | ----> | src としてマークされています |
+-------------------------+ +--------------------------+
| |
| いいえ |
ううう
+-------------------------+ +--------------------------+
| スキップとしてマーク | | var(*) を変数値に置き換えます |
| | | ヘッドに新しいスタイル タグを追加します |
+-------------------------+ +--------------------------+

効果はおそらくこんな感じです

シンプルで粗雑ですがエレガントです。CSS 変数をサポートするブラウザでは処理されないため、パフォーマンスの問題を心配する必要はありません (これは IE の問題であり、私の問題ではありません)

)。 コードを変更してみましょう

//ストア/テーマ.js
'css-vars-ponyfill' から cssVars をインポートします

エクスポートデフォルト{
  州: {
    「プライマリ」:「緑」、
    「危険」:「白」
  },
  突然変異:
    UPDATE_THEME(状態、ペイロード) {
      定数変数 = {}
      オブジェクト.assign(状態、ペイロード)
      Object.keys(state).forEach((キー) => {
        変数[`--${key}`] = 状態[key]
      })
      cssVars({
        変数
      })
    }
  },
  アクション: {
    テーマを変更する({コミット}, テーマ = {}) {
      コミット('UPDATE_THEME', テーマ)
    }
  }
}

// ルータ.js
// ルートジャンプ後のページでは、必要に応じて新しい CSS リソースが読み込まれるため、再変換します。const convertedPages = new Set()
router.afterEach((to) => {
  if (convertedPages.has(to.path)) 戻り値
  変換されたページをパスに追加します
  context.store.dispatch('theme/changeTheme')
})

SSR プロジェクト フラッシュ スクリーンの問題の最適化

SSRプロジェクトでは、上記の解決策を使用してIEでこれが表示される場合があります。

css-vars-ponyfill

変換を実現するために DOM 要素に依存しており、ノードでは使用できません。そのため、変換されていない CSS コードを直接出力するサーバーと、JS ファイルをロードして CSS を変換するクライアントとの間にスタイルのギャップが生じます。

+- - - - - - - - - - - - - - - - - - - - - - - - +
「スタイルウィンドウ期間:」
' '
+----------+ ' +----------------+ +-------------+ ' +-------------+
| リクエストを開始 | --> ' | SSR 直接出力ページ | --> | js 依存関係をロード | ' --> | css 変数を置き換え |
+----------+ ' +----------------+ +-------------+ ' +-------------+
' '
+- - - - - - - - - - - - - - - - - - - - - - - - +

この問題の解決方法も非常に簡単です。CSS css var使用されている各場所に互換性のある記述方法を追加するだけです。

@_primary: 赤
@プライマリ: var(--プライマリ)

:根{
  --プライマリ: @_プライマリ
}

。テーマ {
  色: @primary;
}

//.themeに変更{
  色: @_primary;
  色: @primary;
}

CSS 変数をサポートしていないブラウザでは、デフォルトの色のredがレンダリングされ、js が読み込まれた後に ponyfill がスタイル オーバーライドを置き換えます。

Webpackプラグイン開発

各箇所に互換性のある記述を手動で追加するのは面倒で、メンテナンスも困難です。このとき、webpack のライフサイクルとプラグイン開発に関する知識を理解する必要があります。webpack プラグインを手動で記述し、 normalModuleLoader (バージョン 5 は非推奨です。NormalModule.getCompilationHooks(compilation).loader を使用してください) のフックですべての CSS モジュールにローダーを追加して、互換性のあるコードを処理できます。

著者のプロジェクトでは less を使用しています。webpack のローダーの実行順序はスタックの先入れ後出し順序に似ていることに注意してください。そのため、less 変数ではなくコンパイルされた CSS 変数の書き込みを処理するようにするには、less ローダーの前に変換ローダーを追加する必要があります。

// プラグイン.js
デフォルトクラス HackCss をエクスポートします。
  コンストラクタ (テーマ = {}) {
    this.themeVars = テーマ
  }

  適用(コンパイラ) {
        コンパイラー.フック.thisCompilation.tap('HackCss', (コンパイル) => {
          コンパイル.フック.normalModuleLoader.tap(
            「ハックCSS」、
            (_, モジュールコンテキスト) => {
              /\.vue\?vue&type=style/.test(moduleContext.userRequest) の場合 {
                // ssr プロジェクトの同型性には 2 つのコンパイラがあります。モジュールにローダーがある場合は追加されません if (hasLoader(moduleContext.loaders, 'hackcss-loader.js')) {
                  戻る
                }

                lessLoaderIndex = 0 とします
                // プロジェクトでは less を使用しているため、less-loader の場所を見つけます。moduleContext.loaders.forEach((loader, index) => {
                  (/less-loader/.test(loader.loader)) の場合 {
                    lessLoaderIndex = インデックス
                  }
                })
  
                moduleContext.loaders.splice(lessLoaderIndex, 0, {
                  ローダー: path.resolve(__dirname, 'hackcss-loader.js'),
                  オプション: this.themeVars
                })
              }
            }
          )
        })
      }
    })
}

// ローダー.js
const { getOptions } = require('loader-utils')

module.exports = function(ソース) {
  if (/module\.exports/.test(source)) ソースを返す
  const theme = getOptions(this) || {}
  ソースを返す.replace(
    /\n(.+)?var\(--(.+)?\)(.+)?;/g,
    (コンテンツ、前、名前、後 = '') => {
      const [キー、インデント] = before.split(':')
      定数add = after.split(';')[0]
      `\n${key}:${indent}${theme[name]}${after}${add};${content}` を返します
    }
  )
}

この時点で、テーマを楽しく自由に切り替えることができます。

追記

「コードを書くのが面倒」になる方法を学ぶことで、新しい知識を吸収する方が面白いです。この記事がお役に立てば幸いです。

CSS 変数に基づくテーマ切り替えの完璧なソリューション (推奨) に関するこの記事はこれで終わりです。CSS 変数テーマ切り替えに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  Iframe の使用を減らすべきいくつかの理由の分析

>>:  HTMLでのラジオ値の取得、割り当て、登録の詳細な説明

推薦する

Vueのリストレンダリングの詳細な説明

目次1. v-for: 配列の内容を走査する(よく使われる) 2. v-for: オブジェクトのプロ...

Linux (CentOS7) で RPM を使用して MySQL 8.0.11 をインストールするチュートリアル

目次1. インストールの準備1. Linux関連情報の表示(Linuxコマンドライン操作) 2. M...

シームレスなカルーセル効果を実現するネイティブ js

参考までに、ネイティブjsでカルーセル効果(シームレススクロール)を実現しています。具体的な内容は以...

ROS2のインストールとdocker環境の使い方について

目次Docker を使用する理由は何ですか? DockerのインストールROSイメージを取得するRO...

Firefox で Webdings フォントをサポートする方法

Firefox、Opera、その他のブラウザは Webdings フォントをサポートしていません。回...

Div CSS 命名標準 CSS クラスの命名規則 (SEO 標準に準拠)

検索エンジン最適化 (SEO) では実行すべきタスクが多数ありますが、その中でもコードの最適化は重要...

MySQLで大きなテーブルを正常に削除する方法の詳細な説明

序文テーブルを削除するには、無意識に思い浮かぶコマンドは、DROP TABLE "テーブル...

MySQL 5.7.18 バージョンの無料インストール構成チュートリアル

MySQLはインストール版と無料インストール版に分かれていますインストール版の拡張子はmsi、無料イ...

WeChatアプレットがシンプルな計算機機能を実装

WeChatアプレット:シンプルな計算機、参考までに、具体的な内容は次のとおりです。ミニプログラムに...

Vue3 での provide と injection の使用

1. provideとinjectの説明Provide と Inject により、ネストされたコンポ...

nginx で HSTS を有効にしてブラウザを HTTPS アクセスにリダイレクトする方法の詳細な説明

前回の記事では、https を使用したローカルノードサービスアクセスを実装しました。前回の記事の効果...

Linux の MySQL でリモート接続を承認する方法

注意: 他のマシン (IP) は、承認なしではクライアント経由で MySQL データベースに接続でき...

Vueのフロントエンドとバックエンドのデータのやり取りと表示を理解する方法

目次1. 技術概要2. 技術的な詳細1. インターフェースからバックエンドデータを取得する2. フロ...

高度な JavaScript フロントエンド開発でよく使用されるいくつかの API の例の詳細な説明

目次ミューテーションオブザーバーAPI特徴インターセクションオブザーバーAPI例えば画像の遅延読み込...

MySQL クエリの最適化: クエリが遅い原因と解決策

開発に携わっている友人、特に MySQL に関係のある友人は、非常に遅い MySQL クエリに遭遇す...