9

The body should display a handwriting font but will only do so if the comment line is uncommented.

It seems I cannot use custom properties in @font-face? Tested on FF and Chrome.

What's going on here?

:root {
  --backgroundColor: cornflowerblue;
  --textColor: white;
  --fontName: 'Indie Flower';
}

@font-face {
  font-family: var(--fontName); 
  /* font-family: 'Indie Flower'; */
  src: url(https://fonts.gstatic.com/s/indieflower/v11/m8JVjfNVeKWVnh3QMuKkFcZVaUuH.woff2) format('woff2');
}

body {
  background-color: var(--backgroundColor);
  color: var(--textColor);
  font-family: var(--fontName);
}
<p>Custom CSS properties don't work inside @font-face rule?</p>

2 Answers 2

17

Your original suspicion that CSS properties don't work inside @font-face is accurate. The accepted answer is incorrect and only appears to work because of a mistake (see below).

I checked in Firefox, Chrome, and Safari, and none of them accept a @font-face in which a descriptor includes a var() function. Firefox developer edition was particularly helpful, since it let me see that the @font-face rule isn't being parsed at all with font-family: var(--fontName);

I also tried using a custom property for the src descriptor, which also failed.

As far as I can tell, the CSS @font-face specification says nothing about whether custom properties should work or not. No browser has chosen to make them work. This makes considerable sense, as a single font family's source file and properties are not likely to be variable.

If you have to dynamically construct @font-face rules client-side, the best method is using the FontFace API in a script. If absolutely necessary you could even read from your CSS properties with getComputedStyle(document.body).getPropertyValue("--fontName").


The accepted answer only seems to work because it redefines the font family name in @font-face, setting it to a string with the literal value of 'var(--fontName)'. It also sets the body font-family: 'var(--fontName)'. The two strings match, so the font loads.

CSS functions like var() are NEVER evaluated inside of a string. Everything between the opening and closing quotes is evaluated literally, as this diagram from the CSS syntax spec shows. So @disinfor's code isn't referencing the --fontName: "Indie Flower"; set on :root at all.

As a demonstration, see what happens when we unquote the font-family on body, so it actually evaluates the var(). The "Indie Flower" font doesn't exist in the document, so it doesn't load, but a font named "var(--fontName)" does exist, and will load:

:root {
  --backgroundColor: cornflowerblue;
  --textColor: white;
  --fontName: "Indie Flower";
}

@font-face {
  font-family: 'var(--fontName)';
  src: url(https://fonts.gstatic.com/s/indieflower/v11/m8JVjfNVeKWVnh3QMuKkFcZVaUuH.woff2) format('woff2');
}

body {
  background-color: var(--backgroundColor);
  color: var(--textColor);
  font-family: var(--fontName);
}
.use-the-string {
  font-family: 'var(--fontName)';
}
<p>This tries to use "Indie Flower", but it doesn't exist.</p>
<p class="use-the-string">This uses the font named "var(--fontName)"</p>

Sign up to request clarification or add additional context in comments.

3 Comments

Glad you found the real cause. I didn't hunt it down as far as you did! Upvote.
@disinfor Cheers and thanks :) It's a weird little edge-case to be sure! It would be nice if the spec took a clear position on it one way or another. There are other blocks like @keyframes that technically have identical semantics, and custom props work fine there, so it's natural to assume they ought to work in @font-face as well.
@Andron My use case was that I wanted to use the same CSS for different websites and only have to exchange the font-family name (and src) in :root. I eventually achieved this by defining seperate font-face rules for each font and using a font-family var on the affected HTML elements.
-3

The problem is how the font-name is actually output for the browser to read. Remove the quote marks for the root var, and add them around the call to the variable.

:root {
  --backgroundColor: cornflowerblue;
  --textColor: white;
  --fontName: Indie Flower;
}

@font-face {
  font-family: 'var(--fontName)';
  src: url(https://fonts.gstatic.com/s/indieflower/v11/m8JVjfNVeKWVnh3QMuKkFcZVaUuH.woff2) format('woff2');
}

body {
  background-color: var(--backgroundColor);
  color: var(--textColor);
  font-family: 'var(--fontName)';
}
<p>Custom CSS properties don't work inside @font-face rule?</p>

Edit Here's the version with a fallback.

:root {
  --backgroundColor: cornflowerblue;
  --textColor: white;
  --fontName: "Indie Flower";
  --fallBack: sans-serif;
  --fullFont: 'var(--fontName)', var(--fallBack);
}

@font-face {
  font-family: 'var(--fontName)';
  src: url(https://fonts.gstatic.com/s/indieflower/v11/m8JVjfNVeKWVnh3QMuKkFcZVaUuH.woff2) format('woff2');
}

body {
  background-color: var(--backgroundColor);
  color: var(--textColor);
  font-family: 'var(--fontName)', var(--fallBack);
}

p {
   font-family: var(--fullFont);
}
<p>Custom CSS properties don't work inside @font-face rule?</p>

11 Comments

For the fallback font, in your use case, you would not add that to the --fontName var, as that would mess up your @font-face. You would simply add another variable as the fallback, or just put sans-serif after the var font-family: 'var(--fontName)', sans-serif;
Maybe because the @ rule is processed differently than a selector. In your original example, if you wrap the font-family: 'var(--fontName)'; in your @font-face, it would work. Again, that could be because of how the variable is passed with the quotes as part of the string vs. a wrapping element. I'm not sure. That's something perhaps the spec developers could answer.
What? How does it event work? You just pass a string instead of a variable value...
The answer you gave here doesn't really utilize CSS custom properties. You just set a string as a font-family.
@disinfor I think the issue here is that instead of using the value of the custom property, you're using the custom property name. So given a custom property: --font: MyCoolFont setting font-family: 'var(--font)' is setting the font-family to literally be "var(--font)" instead of "MyCoolFont".
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.