Scope and Inheritance of CSS Variables
CSS variables, also known as custom properties, have a defined scope and follow the standard rules of inheritance. This allows for powerful and flexible styling, enabling developers to create more maintainable and dynamic stylesheets. Understanding how to control the scope and leverage inheritance is a fundamental skill for modern CSS development.
Example 1: Global Scope with :root
/* Defining a global variable within the :root pseudo-class */
:root {
--main-bg-color: #f0f0f0;
}
body {
background-color: var(--main-bg-color); /* Using the global variable */
}
div {
border: 1px solid var(--main-bg-color); /* Inherited by descendant elements */
}
Explanation
Variables defined within the :root
pseudo-class have a global scope, meaning they are accessible throughout the entire document. This is the standard practice for defining a site-wide color palette or font sizes that need to be used consistently.
Example 2: Local Scope
/* Defining a local variable within a specific class */
.container {
--container-padding: 20px;
padding: var(--container-padding);
}
.box {
/* This would not work as --container-padding is not in this scope */
/* margin: var(--container-padding); */
margin: 10px;
}
Explanation
A variable declared inside a selector, like .container
, has a local scope. It can only be accessed by the element with that class and its descendants, preventing unintended styles from leaking out to other elements.
Example 3: Overriding Global Variables
:root {
--text-color: #333;
}
body {
color: var(--text-color); /* Will be #333 */
}
.dark-theme {
--text-color: #eee; /* Overriding the global variable for this class */
color: var(--text-color); /* Will be #eee */
}
Explanation
Local variables will override global variables when applied to the same element. This is useful for creating themes or specific component styles that deviate from the global defaults.
Example 4: Inheritance in Action
.parent {
--parent-font-size: 1.2rem;
font-size: var(--parent-font-size);
}
.child {
/* The --parent-font-size is inherited from .parent */
/* The font-size of .child will be 1.2rem unless overridden */
}
Explanation
CSS variables are inherited by default. Any child element can use a variable defined in its parent, which simplifies styling nested components and ensures consistency within a specific section of your layout.
Example 5: Using Fallback Values
.element {
/* The second value is a fallback if the first is not defined */
background-color: var(--undefined-variable, #ff0000);
}
Explanation
The var()
function can accept a second parameter which acts as a fallback value. If the custom property in the first parameter is not defined, the browser will use the fallback value instead, which helps prevent broken styles.
Example 6: Reassigning Variables
:root {
--base-spacing: 10px;
}
.component {
--base-spacing: 15px; /* Reassigning the variable for this component */
padding: var(--base-spacing); /* Will be 15px */
}
Explanation
You can reassign the value of a custom property within a different scope. This powerful feature allows for creating variations of a component without writing entirely new CSS rules, promoting reusability.
Example 7: Combining Variables
:root {
--base-font-size: 16px;
--font-scale: 1.5;
}
h1 {
/* Variables cannot be directly combined with units like this */
/* font-size: var(--base-font-size) * var(--font-scale); */
/* Use calc() to combine them */
font-size: calc(var(--base-font-size) * var(--font-scale));
}
Explanation
While you cannot directly concatenate or perform mathematical operations with variables in a property value, you can use the calc()
function. This enables dynamic calculations based on your defined custom properties for creating responsive and scalable typography or layouts.