How to use commas in a CSS variable fallback?
Asked Answered
S

3

9

How can one use commas in the fallback value of a CSS variable?

E.g. this is fine: var(--color, #f00), but this is weird var(--font-body, Verdana, sans-serif).

The idea is to be able to set a font-family using a variable with a fallback value of say Verdana, sans-serif.


Edit: This actually works pretty well for browsers that support CSS properties, but the issue seems to come from Google Polymer's polyfills.

For future reference, I ended up using variables for both the font and the font family fallback like so (seems to be the cleanest way of doing it for now):

font-family: var(--font-body, Verdana), var(--font-body-family, sans-serif)
Shahjahanpur answered 25/5, 2016 at 16:13 Comment(5)
What is the usage of such a value? I can't understand what you are trying to do.Ruben
My initial guess would be to wrap the values in quotes: "Verdana, sans-serif"Wennerholn
@Ruben I think the OP is trying to do this: font-family: Verdana, sans-serif; but with variables.Monday
@BSMP: But that can be done with --font: verdana, sans-serif; and font-family: var(--font) right? The comma syntax mentioned in question is reserved for fallback values if I remember right. (Edit: Maybe you are correct and OP is trying to set Verdana, sans-serif as the fallback but it is unclear.)Ruben
@Harry: that's why you vote to close.Crystallography
R
14

The below is an extract from the W3C spec: (emphasis is mine)

Note: The syntax of the fallback, like that of custom properties, allows commas. For example, var(--foo, red, blue) defines a fallback of red, blue; that is, anything between the first comma and the end of the function is considered a fallback value.

As you can see from the above statement, if your intention is to set Verdana, sans-serif as fallback value when --font-body is not defined then the syntax given in question is expected to work. It does not require any quotes as per spec.

I don't have a browser that supports CSS variables and hence I couldn't test the following code but it should work based on the spec:

.component .item1 {
  --font-body: Arial;
  font-family: var(--font-body, Verdana, sans-serif); 
  /* should result in font-family: Arial */
}
.component .item2 {
  font-family: var(--font-body, Verdana, sans-serif);
  /* should result in font-family: Verdana, sans-serif */
}
<div class=component>
  <p class=item1>Arial
  <p class=item2>Verdana, sans-serif
</div>
Ruben answered 25/5, 2016 at 16:25 Comment(0)
C
3

As Harry mentions, what you have should already work in browsers that implement custom properties.

But if you're using custom properties with font-family, there is a major caveat: var() does not allow you to modify or add to an existing font-stack, due to the fact that custom properties cascade in exactly the same way as all other properties. That is to say, the expression

var(--font-body, Verdana, sans-serif)

results in one of two possible values:

  1. If a --font-body custom property declaration exists, var(--font-body)
  2. Otherwise, Verdana, sans-serif

The "Verdana, sans-serif" is not part of the font-stack that's defined in --font-body, and should the family defined in --font-body be missing or otherwise unavailable to the browser, it will not fall back to Verdana or sans-serif; it will instead fall back to an arbitrary default font of the browser's choosing.

Worst of all, if the value of --font-body causes the entire font-family declaration to be invalid, that font-family declaration will have no effect.

If you're looking to build font-stacks dynamically in a stylesheet, you cannot use custom properties. You will need a CSS preprocessor.

Crystallography answered 25/5, 2016 at 16:45 Comment(6)
I'm not really sure I understand your last two paragraphs. To clarify, I'm using this in the context of Google's Polymer. Perhaps it is the original culprit, but var(--font-body, Verdana, sans-serif) doesn't seem to work, nor does var(--font-body, "Verdana, sans-serif"). The value is interpreted as if it was inherit. Oddly enough, this does work: var(--font-body, Verdana). I'm confused.Shahjahanpur
You are correct. I just tested that too. If I set --font-body as Ariel, there is no fallback font because variable is defined and there is no font with that name.Ruben
@TonyBogdanov: Maybe there is something wrong elsewhere. I am on Chrome v 52 (dev-m) and the snippet in my answer works as expected.Ruben
@Tony Bogdanov: Hmm not sure about Polymer, but make sure the browser you're testing in 1) ships with custom props and 2) has them enabled for use. Not sure if Chrome already ships with custom props out of the box, but Firefox certainly does. As for the last two paragraphs, what I'm saying is that you can't use custom props to declare font-family with a value of "--font-body, Verdana, sans-serif", it can only be either one of the two as shown in the example. So if --font-body is X, but X is not available (e.g. it's not installed and there's no @font-face), it will not fall back to Verdana.Crystallography
@Ruben Your example does work in Chrome for me. I believe the issue will be in Polymer's polyfills. It seems that this actually does the trick pretty well: font-family: var(--font-body, Verdana), var(--font-body-family, sans-serif), so I'll go with that for now.Shahjahanpur
It could well be @TonyBogdanov. Can't help much there because I know nothing about Polymer.Ruben
W
0

This can be achieved by simply separating the separate values by commas:

p{
  /* By commenting this out, we are making the variable non-existent */
  /* --font-family: "Times New Roman, serif"; */
}

p.sans-serif{
  font-family: var(--font-family, "Arial", "Helvetica");
}
<p class="sans-serif">
  This will be in a sans-serif font because the fallback value is "Arial" and "Helvetica"
</p>

As you can see, the p.sans-serif would normally show in a serif font. If you uncomment the p style, it will show in a serif font.

However, if the variable doesn't exist (which, it doesn't since we commented it out), the fallback works.

Wennerholn answered 25/5, 2016 at 16:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.