Home > Article > Web Front-end > The Surprising Details of CSS Variables - Using var() and Cool Examples
これは CSS 変数に関する投稿の後半です。前半はここにあります。
この記事では、var() の詳細を見ていきます。そして 2 つの素晴らしい例:
var() はカスタム プロパティ値 (CSS 変数) にアクセスします。その構文は次のとおりです:
var( <custom-property-name>, <fallback-value>? )
最初のパラメータは CSS 変数である必要があります: var() はカスタム プロパティ名のみを受け入れるため、var(20px) などの直接値はエラーになります。
var() はプロパティ名を置き換えることはできません: つまり、var(--prop-name): 20px; のようなものは記述できません。 var() はプロパティ値でのみ使用できるように制限されているためです。
.foo { margin: var(20px); /* Error, 20px is not a CSS variable */ --prop-name: margin-top; var(--prop-name): 20px; /* Error, cannot use var() this way */ }
var(--b, fallback_value) Fallbacks: 2 番目のパラメーターは、--b が無効な場合に使用されるフォールバック値として機能します。
空のフォールバックを使用した var(--c,) 構文: フォールバック値が空のままの場合、構文は有効なままであり、--c が無効な場合はデフォルトで空の値になります。 .
複数のカンマ: var(--d, var(--e), var(--f), var(--g)) では、最初のカンマ以降はすべてフォールバックとして扱われるため、--d が無効な場合、var() 式は var(--e)、var(--f)、var(--g) を 1 つのフォールバックとして評価し、結果を決定します。
var(): この関数は、20px と同様に、完全な CSS トークンとして機能します。したがって、var(--size)var(--unit) は 20px を作成せず、無効とみなされます。
CSS 変数でのイニシャルの使用: CSS 変数へのイニシャルの割り当ては、無効であることを意味します。初期値を値として表示するには、それをフォールバックに配置する必要があります。
url() および var() 使用法: url() は完全な CSS トークンとして扱われるため、変数内で完全な url() を定義する必要があります。
:root { /* 1. */ margin: var(--b, 20px); /* Uses 20px if --b is invalid */ /* 2. */ padding: var(--c,) 20px; /* Falls back to 20px if --c is invalid */ /* 3. */ font-family: var(--fonts, "lucida grande", tahoma, Arial); /* Uses fallback font stack if --fonts is invalid */ /* 4. */ --text-size: 12; --text-unit: px; font-size: var(--text-size)var(--text-unit); /* Invalid, as it does not resolve to 12px */ /* 5. */ --initialized: initial; background: var(--initialized, initial); /* Results in background: initial */ /* 6. */ --invalid-url: "https://useme.medium.com"; background: url(var(--invalid-url)); /* Invalid, as url() cannot parse var() */ --valid-url: url(https://useme.medium.com); background: var(--valid-url); /* Correct usage */ }
CSS 変数は、他の CSS プロパティと同様に、スコープと詳細性に関して CSS 固有のルールに従います。これらの要素が CSS 変数にどのような影響を与えるかを理解することで、より正確な制御が可能になります。
グローバル変数とスコープ変数:
:root で定義された変数はグローバルに適用されますが、セレクターで定義された変数のスコープはより制限されています。
:root { --main-color: blue; /* Globally applied */ } .container { --main-color: green; /* Scoped, applies only within .container */ }
特異性による優先度:
より高い特異性は、CSS 変数のより低い特異性をオーバーライドします。
:root { --main-color: blue; } .section { --main-color: green; /* Overrides :root definition */ } .section p { color: var(--main-color); /* Shows green */ } p { color: var(--main-color); /* Shows blue */ }
<div> <p><strong>Calculating Values Based on Specificity Order:</strong> <br> Like CSS properties, variables are resolved based on specificity in ascending order.<br> </p> <pre class="brush:php;toolbar:false"> :root { --red: 255; --green: 255; --blue: 255; --background: rgb(var(--red), var(--green), var(--blue)); } .box { --green: 0; background: var(--background); }
この例では、.box が --green: 0 を再定義する前に --background が rgb(255, 255, 255) に解決されたため、.box の背景色は白のままです。
Reevaluating Variables with Pseudo-Classes:
Variables change based on pseudo-class states when defined at the same level.
:root { --red: 255; --green: 255; --blue: 255; } .box { --background: rgb(var(--red), var(--green), var(--blue)); background: var(--background); } .box:hover { --green: 0; /* Changes background color on hover */ }
Next, let’s explore some advanced use cases for CSS variables:
CSS variables cannot be directly animated because the browser cannot infer the data type. To resolve this, use @property to define the variable's type and initial value, enabling the browser to understand how to animate the variable.
@property --green { syntax: "<number>"; initial-value: 255; inherits: false; } .section { padding: 5em; background: rgb(50, var(--green), 50); transition: --green 0.5s; } .section:hover { --green: 50; }
<div> <p>In this example, @property is used to declare --green as a <number> type with an initial value of 255. When hovering over .section, --green changes to 50, creating a smooth color transition effect. <p>CodePen example</p> <hr> <h2> Usage Example B: Light/Dark Mode Toggle </h2> <p>If you want to implement theme switching for light and dark modes, it’s helpful to extract color values into variables that adjust automatically based on the prefers-color-scheme setting. Here’s how you can manage this using CSS variables.<br> </p> <pre class="brush:php;toolbar:false">:root { --background-color: #FBFBFB; --container-background-color: #EBEBEB; --headline-color: #0077EE; --text-color: #333333; } @media (prefers-color-scheme: dark) { :root { --background-color: #121212; --container-background-color: #555555; --headline-color: #94B2E6; --text-color: #e0e0e0; } }
Adding a Manual Toggle that Aligns with System Preferences
While the system setting controls the theme by default, we may want to give users the option to manually toggle between light and dark themes. To achieve this, we can add a checkbox to toggle the state. Ideally, when the checkbox is selected, it indicates dark mode, and when unselected, it represents light mode.
However, CSS cannot automatically detect system settings and change the checkbox state accordingly, especially in dark mode. To handle this limitation, we can use CSS variables and the :has() selector to control theme switching based on the checkbox state.
I wanted to try achieving this entirely with CSS, but since a user’s system may be set to either light or dark mode, CSS alone can’t automatically check the checkbox in dark mode.
If we can’t move the mountain, we’ll route the path. Here’s the workaround:
When system sets to light mode: When the checkbox is unselected, it corresponds to the “OFF” state (light mode). When selected, it corresponds to the “ON” state (dark mode).
When system sets to dark mode: Since the system preference is reversed, the visual state also inverts. When the checkbox is unselected, it corresponds to “ON” (dark mode). When selected, it corresponds to “OFF” (light mode).
To achieve this effect, we need two main elements:
First: Variables that Change Based on System Setting and Checkbox State
:root { --background-color: #FBFBFB; --container-background-color: #EBEBEB; --headline-color: #0077EE; --text-color: #333333; } :root:has(input[type="checkbox"]:checked) { --background-color: #121212; --container-background-color: #555555; --headline-color: #94B2E6; --text-color: #e0e0e0; } @media (prefers-color-scheme: dark) { :root { --background-color: #121212; --container-background-color: #555555; --headline-color: #94B2E6; --text-color: #e0e0e0; } :root:has(input[type="checkbox"]:checked) { --background-color: #FBFBFB; --container-background-color: #EBEBEB; --headline-color: #0077EE; --text-color: #333333; } }
Second: Toggle Behavior Based on System Settings for checked State and ON/OFF Representation
The light and dark mode CSS properties are reversed depending on the system setting.
/* Toggle Switch Styles */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; } /* Hide the checkbox element to style a custom switch */ .switch input { opacity: 0; width: 0; height: 0; } /* Slider styling for the switch background */ .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--slider-bg, #ccc); transition: 0.4s; border-radius: 34px; } /* Slider knob styling */ .slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; transition: 0.4s; border-radius: 50%; } /* Dark mode styles: make the switch look "checked" by default */ @media (prefers-color-scheme: dark) { .slider { background-color: #94b2e6; } .slider:before { transform: translateX(26px); /* Move knob to the right */ } /* Invert checked state in dark mode to look "unchecked" */ input:checked + .slider { background-color: #ccc; } input:checked + .slider:before { transform: translateX(0); /* Move knob to the left */ } } /* Light mode styles: make the switch look "unchecked" by default */ @media (prefers-color-scheme: light) { .slider { background-color: #ccc; } .slider:before { transform: translateX(0); /* Knob on the left */ } /* Invert checked state in light mode to look "checked" */ input:checked + .slider { background-color: #94b2e6; } input:checked + .slider:before { transform: translateX(26px); /* Move knob to the right */ } }
Simplifying Variable Setup with CSS Variable Tricks
Here we’ll use Space Toggle technique to simplify variable settings. Here’s the code, followed by an explanation of how it works:
:root { --ON: initial; /* Default state variable to use for switching colors */ --OFF: ; /* Alternative state variable for switching colors */ /* Set default color variables based on light mode */ --light: var(--ON); --dark: var(--OFF); /* Define custom properties for colors used in light and dark modes */ --background-color: var(--light, #fbfbfb) var(--dark, #121212); --container-background-color: var(--light, #ebebeb) var(--dark, #555555); --headline-color: var(--light, #0077ee) var(--dark, #94b2e6); --text-color: var(--light, #333333) var(--dark, #e0e0e0); } :root:has(input[type="checkbox"]:checked) { --light: var(--OFF); --dark: var(--ON); }
The key here is in the line --background-color: var(--light, #fbfbfb) var(--dark, #121212);. Here, the background color depends on the values of --light and --dark, effectively simulating an if/else in the property.
How does it work? Initially, --light: var(--ON); and --ON: initial; make --ON an invalid state. Meanwhile, --OFF is set as an empty string. When applied to var(--light, #fbfbfb) var(--dark, #121212), the invalid --light variable will default to #fbfbfb, and the valid --dark variable (empty) allows --background-color to equal #fbfbfb.
All the other color variables follow the same logic, adjusting based on the state of --light and --dark. This way, each color variable only needs to be defined once.
Switching states becomes simple. If dark mode is active, use --light: var(--OFF); and --dark: var(--ON);. In light mode, reverse them. Though not immediately intuitive, this method is currently the most effective with CSS. If there are better solutions, they are worth exploring.
Complete example: CodePen Example
CSS continues to evolve, with CSS variables available in major browsers since 2016. New features like @property and :has() are expanding CSS variables’ flexibility even further. Combined with other new tools, CSS variables are becoming more powerful—for instance, they can now enhance scroll-driven animations to create visually dynamic effects. As a core element for storing state in CSS, much like variables in any programming language, a solid understanding of CSS variables will prove invaluable for more sophisticated styling and design down the road.
The above is the detailed content of The Surprising Details of CSS Variables - Using var() and Cool Examples. For more information, please follow other related articles on the PHP Chinese website!