In the second chapter of “Working with Relative Units”, Keith J.Grant’s good BOOK CSS in Depth has been translated. The explanation and examples of relative units in the book are quite comprehensive. After reading it, I found that I do not understand the relative units of CSS, and I hope to share with you, so I have this translation series. (for errata or translation suggestions, welcome Github PR ^_^)

Don’t say you Know CSS relative Units

  1. How to use EM more happily
  2. How to use REM more happily
  3. Application of viewport related units
  4. None unit number and row height
  5. CSS Custom Properties [this article]

Corresponding chapter contents of this paper:

  • 2.6 Custom Properties (also called “CSS variables”)
    • 2.6.1 Dynamically Changing the Value of a user-defined Attribute
    • 2.6.2 Changing the value of a custom attribute through JavaScript
    • 2.6.3 Exploring custom attributes
  • conclusion

At the beginning of this year, I also wrote a “CSS Variables learning notes”, which has more syntax explanation and example demo CSS Variables, interested friends can have a look: Enjoy 🎉🎉🎉 Check out Keith J.Grant’s CSS in Depth.


2.6 Custom Properties (also called “CSS variables”)

In 2015, A long-awaited CSS specification called “Custom Properties for Cascading Variables” has finally been released as a “Candidate Recommendation.” This specification introduces the concept of “variables” in CSS and supports a new way of dynamically defining styles based on context. You can declare a variable, assign a value to it, and then reference it anywhere in the stylesheet. This way, you can reduce the amount of duplicate code in your stylesheets, as well as some useful scenarios you’ll see later.

At the time of writing, custom properties were already supported by most major browsers, except Internet Explorer. For the latest browser support, check out Can I Use at caniuse.com/#feat=css-v… .

notes

If you happen to be using a CSS preprocessor that supports custom variables, such as Sass (Syntactically Awesome Stylesheets) or Less, you might subconsciously reject CSS variables. Don’t do that. Because native CSS variables are more powerful and flexible than any preprocessor can achieve. To emphasize the difference between them (native CSS variables and preprocessor custom variables), I’ll call it a “custom property” instead of a “CSS variable.”

Declare a custom property, just like any other property. Snippet 2.23 is an example of a custom property declaration. Create a new page and style sheet, then add the following CSS code.

[Snippet 2.23 Declaring a custom property]

:root {
  --main-font: Helvetica, Arial, sans-serif;
}
Copy the code

In the code snippet, we define a variable named –main-font and set its value to the plain sans-serif font. To distinguish it from other attributes, the name prefix must be two dashes (–), followed by the name you want.

Variables must be declared in a declaration block. In this case, I used the :root selector, so this variable can be used throughout the page style — I’ll explain this shortly.

The declaration of a variable, by itself, doesn’t do anything until we reference it in our code. Let’s use it in a paragraph to make it look like Figure 2.13.

[Figure 2.13 sans-serif font with variable declaration for a simple paragraph]

We can use a function called var() to reference the value of a custom attribute. Now, you can use this function to reference the variable we just declared, main-font. Add the code snippet shown below to your stylesheet and put variables to use.

[Snippet 2.24 Using a custom attribute]

:root { --main-font: Helvetica, Arial, sans-serif; } p { 1 font-family: var(--main-font); 1}Copy the code
  • 1. Define paragraph fonts as Helvetica, Arial, sans-serif

A custom attribute lets you declare its value in one place, as a “single source of truth,” and reference it anywhere in the stylesheet. This is especially useful for recurring values, such as color. The next code snippet adds a custom property called brand-color. You can use this variable multiple times in your stylesheet, but if you need to change its value (globally), you only need to edit its value in one line of code.

[Snippet 2.25 Using custom attributes for color]

:root {
  --main-font: Helvetica, Arial, sans-serif;
  --brand-color: # 369; 1
}

p {
  font-family: var(--main-font);
  color: var(--brand-color);
}
Copy the code
  • 1 Declare a blue onebrand-colorvariable

The var() function supports a second argument that represents a default value. If a variable is declared and the first parameter is not declared, the second parameter value is referenced.

[Snippet 2.26 provides rollback defaults]

:root {
  --main-font: Helvetica, Arial, sans-serif;
  --brand-color: # 369;} p { font-family: var(--main-font, sans-serif); 1 color: var(--secondary-color, blue); 2}Copy the code
  • 1 Declare a default value sans-serif
  • The secondary color variable is not declared, so the default blue will be used

This code defines the default values in two different declarations. In the first declaration, –main-font is declared with the value Helvetica, Arial,sans-serif, and this value will be used. In the second declaration, –secondary-color is an undeclared variable, so the default blue is used.

 

Note If var() is defined as an invalid value, this property is defined as its initial value. For example, if the variable is a color in the padding: var(–brand-color), it is an invalid value for the padding. In this case, the padding value is defined to be 0.

 

2.6.1 Dynamically Changing the Value of a user-defined Attribute

As you can see from these examples, custom attributes are just a little more convenient and can help you reduce a lot of code duplication. But what makes custom properties even more interesting is that the declarations of custom properties can be layered and inherited. You can declare the same variable in multiple selectors, and these variables can have different values in different parts of the page.

You can declare a variable to be black, for example, and then redefine it to be white in a particular container. So, all the dependent colors outside the container are black, and all the dependent colors inside the container are white. In this way, we achieve an effect like figure 2.14.

[Figure 2.14. Two panels with different colors for custom properties based on values in different fields]

This panel is similar to the one you saw earlier (Figure 2.7), with the HTML in snippet 2.27. This panel has two instances, one under the body and one in a dark block. Come on, update your code.

[Two panels in different contexts on the page in snippet 2.27]

<body>
  <div class="panel">                               1
    <h2>Single-origin</h2>
    <div class="body">
      We have built partnerships with small farms
      around the world to hand-select beans at the
      peak of season. We then careful roast in
      small batches to maximize their potential.
    </div>
  </div>

  <aside class="dark">                              2
    <div class="panel">                             2
      <h2>Single-origin</h2>
      <div class="body">
        We have built partnerships with small farms
        around the world to hand-select beans at the
        peak of season. We then careful roast in
        small batches to maximize their potential.
      </div>
    </div>
  </aside>
</body>
Copy the code
  • A normal panel on the page
  • 2 The second panel is in the dark container

Let’s rewrite the text and background color in the panel using variables. Add the following code snippet to your stylesheet. I’m going to make the background color white and the text color black. Before you add dark themes, I’ll explain how this code works.

[Snippet 2.28 Defines panel colors with variables]

:root {
  --main-bg: #fff; 1
  --main-color: # 000; 1
}

.panel {
  font-size: 1rem;
  padding: 1em;
  border: 1px solid # 999;Border - the radius: 0.5 em. background-color: var(--main-bg); 2 color: var(--main-color); 2 } .panel > h2 { margin-top: 0; The font - size: 0.8 em. font-weight: bold; text-transform: uppercase; }Copy the code
  • 1 Define the background color and text color as white and black respectively
  • Use variables in panel styles

Again, you declare the variable in the :root selector. Obviously, then we can refer to this variable in any element below the root element (the entire page). When children of the root element use these variables, they get their values.

You have two panels, but they still look the same. Now, define these variables again, but this time in a different selector. The next code snippet is a dark container with a dark gray background color and a little padding and margin. At the same time, it overwrites two variables. Add it to your stylesheet.

[Snippet 2.29 Styling a dark container]

.dark {
  margin-top: 2em;                   1
  padding: 1em;
  background-color: # 999; 2
  --main-bg: # 333; 3
  --main-color: #fff; 3
}
Copy the code
  • 1 Set a margin between the dark container and the previous container
  • 2 Give the dark container a dark grey background color
  • 3 Redefine the values of –main-bg and –main-color in the scope of the current container

Refresh the page and the second panel will have a dark background and white text. This is because when the panel calls these variables, it gets the values in the dark container scope, not the root element field. Note that you don’t need to change the styles in the container or add extra class names.

In this example, you define the custom property twice, first on the root element scope (–main-color is black) and second on the dark container scope (–main-color is white). Custom attributes behave like scoped variables because the values are inherited by descendant elements. In the dark container, –main-color is white, while elsewhere on the page, it is black.

2.6.2 Changing the value of a custom attribute through JavaScript

Custom properties can also be accessed and dynamically modified by JavaScript in the browser. After all, this is not a JavaScript book, and I’ll give you enough basic concepts to incorporate into your own JavaScript projects.

[Snippet 2.30 Accessing a custom variable in JavaScript]

<script type="text/javascript">
  var rootElement = document.documentElement;
  var styles = getComputedStyle(rootElement);                 1
  var mainColor = styles.getPropertyValue('--main-bg');       2
  console.log(String(mainColor).trim());                      3
</script>
Copy the code
  • 1 get the style object of the element
  • Get –main-bg from the style object
  • 3 Make sure mainColor is a string and remove Spaces, print “# FFF”

Since you can change the values of custom attributes at will, you can use JavaScript to dynamically define a new value for –main-bg. If you define it as light blue, it looks like this (Figure 2.15).

[Figure 2.15 JavaScript can change the background color of the panel by changing the value of the variable main-bg]

The following code snippet defines a new value for –main-bg under the root element, and adds this code at the bottom of the

[Snippet 2.31 Defining the value of a custom variable in JavaScript]

var rootElement = document.documentElement;
rootElement.style.setProperty('--main-bg'.'#cdf');            1
Copy the code
  • 1 defines –main-bg under the root element as light blue

If you execute this code, any element that inherits the –main-bg attribute will be changed and the corresponding value will become new. On your page, this will change the background color of the first panel to light blue. The second panel remains the same because it inherits the values defined in the dark container.

With this technology, you can change the theme of your site with JavaScript in the browser. Or you can highlight parts of the page, or you can make changes at will. With just a few lines of JavaScript code, you can make changes that affect a large number of elements on the page.

2.6.3 Exploring custom attributes

Custom properties are a whole new area of CSS that developers are just beginning to explore. It is not yet “prime time” to use it because of limited browser support. Over time, I’m sure you’ll see a lot of best practices and novel gameplay for customizing attributes. That’s what you need to be aware of. Try custom attributes and see what you can do.

One thing to keep in mind is that if you use var() declarations, older browsers won’t recognize them and will ignore them. If possible, provide a fallback scheme for those browsers.

[Code snippet (unnumbered)]

color: black;
color: var(--main-color);
Copy the code

Custom properties the native dynamic feature, which is not always available, can be viewed with browser support at caniuse.com.

conclusion

  • Embrace and use relative units and let the structure of the page define the meaning of the style code
  • I like to use REM for font size and EM selectively for some simple scaling effects on page components
  • You can scale the entire page in response without any media queries
  • When declaring line heights, use numeric values without units
  • Get to know and use one of CSS’s newest features, custom properties.

Don’t say you Know CSS relative Units

  1. How to use EM more happily
  2. How to use REM more happily
  3. Application of viewport related units
  4. None unit number and row height
  5. CSS Custom Properties [this article]

Chapters:

  • 2.1 Magic relative to unit values
    • 2.1.1 The struggle of Pixel-perfect Design
    • 2.1.2 The end of the perfect pixel web
    • Pixel, Point, and PC (PICA)
  • 2.2 em and rem
    • 2.2.1 Using em for Font size
      • When we declare font size and other attributes in an element using em
      • Type shrinkage problem
    • 2.2.2 Rem for font size
      • Availability: Use relative length units for font size
  • 2.3 Stop using pixel thinking to think
    • 2.3.1 Set a reasonable size default
    • 2.3.2 Make this panel “responsive”
    • 2.3.3 Resize a Component
  • 2.4 Viewport-relative Units
    • CSS3
    • 2.4.1 Using VW on font size
    • 2.4.2 Using calc() on font size
  • Unitless number and line height
  • 2.6 Custom Properties (also called “CSS variables”)
    • 2.6.1 Dynamically Changing the Value of a user-defined Attribute
    • 2.6.2 Changing the value of a custom attribute through JavaScript
    • 2.6.3 Exploring custom attributes
  • conclusion

Copyright Information:

Book: CSS in Depth Chapter: Working with Relative Units


The author @Yuying Wu, front-end enthusiast/encourager/New Zealand working holiday/poop collector. Currently, I am working in B2B front-end team of a large e-commerce company.

Thank you for reading this. If you have any questions or suggestions, please leave a comment below.

If you like the front end as much as I do, like to play with independent blogs or cutting-edge technology, or have any career questions, please follow me and communicate with me.

Zhihu ID: @yuying Wu Github: Yuying Wu