1

Let's say I want to implement a text switch with CSS as outlined in https://css-tricks.com/swapping-out-text-five-different-ways/#aa-css-only-way:

:root {
    --release-version: "R0.0.0";
    --build-version: "v0.0.0";
}

/* https://css-tricks.com/swapping-out-text-five-different-ways/#aa-css-only-way */
#app-version {
    position: relative;
}
#app-version-checkbox {
    display: none;
}
#app-version-checkbox:checked + #app-version::after {
    content: var(--build-version);
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: white;
}
<input id="app-version-checkbox" type="checkbox">
<label for="app-version-checkbox" id="app-version">R0.0.0</label>

which as you can see, is working.

But what I really want is to be able to update the versions:

//TODO: get versions from a config file or something
let releaseVersion = "R1.1.0"
let buildVersion = "v1.32.0"

window.onload = () => {
    const root = document.querySelector(":root");
    root.style.setProperty("--release-version", releaseVersion)
    root.style.setProperty("--build-version", buildVersion)
    
    //cannot change label text with CSS
    document.querySelector("#app-version").innerHTML = releaseVersion
}
:root {
    --release-version: "R0.0.0";
    --build-version: "v0.0.0";
}

/* https://css-tricks.com/swapping-out-text-five-different-ways/#aa-css-only-way */
#app-version {
    position: relative;
}
#app-version-checkbox {
    display: none;
}
#app-version-checkbox:checked + #app-version::after {
    content: var(--build-version);
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: white;
}
<input id="app-version-checkbox" type="checkbox">
<label for="app-version-checkbox" id="app-version"></label>

and that doesn't work.

So at first, I thought I'm just stupid and I'm not supposed to use innerHTML and that broke something, but even if I don't do that:

//TODO: get versions from a config file or something
let releaseVersion = "R1.1.0"
let buildVersion = "v1.32.0"

window.onload = () => {
    const root = document.querySelector(":root");
    root.style.setProperty("--release-version", releaseVersion)
    root.style.setProperty("--build-version", buildVersion)
}
:root {
    --release-version: "R0.0.0";
    --build-version: "v0.0.0";
}

/* https://css-tricks.com/swapping-out-text-five-different-ways/#aa-css-only-way */
#app-version {
    position: relative;
}
#app-version-checkbox {
    display: none;
}
#app-version-checkbox:checked + #app-version::after {
    content: var(--build-version);
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: white;
}
<input id="app-version-checkbox" type="checkbox">
<label for="app-version-checkbox" id="app-version">R0.0.0</label>

That still doesn't work.

It's the act of setting the variables that breaks the app, and if I inspect the snippet, I also notice that the override is weird, too:

overrides aren't set correctly

I feel like I'm missing something obvious, but I just don't see it.

What is going on, here?

(And yes, I do realise that since I'm now using JS anyway, I could just use a button, but I want to understand why this is happening.)

EDIT: doing it with CSS variables would also allow me to do things like

.release-version::after {
    content: var(--release-version);
}

which would be nice.

7
  • 1
    Why are you trying to update text with CSS variables? Commented Jan 26, 2022 at 11:32
  • @Dominic because ideally, I just want to update the property and then have it propagated everywhere it's used - which html doesn't allow and doing everything in JS would be a hassle if I can just toss a class onto an element and let CSS sort it out, instead. (see edit) Commented Jan 26, 2022 at 11:36
  • 1
    JS can easily change the text content of, say, any element with a given class. How is this a hassle, especially compared to the time you've already spent trying to solve this CSS problem? Commented Jan 26, 2022 at 11:39
  • I assume it's not just a case of changing let releaseVersion = "R1.1.0" let buildVersion = "v1.32.0" to let releaseVersion = """R1.1.0""" let buildVersion = """v1.32.0""" Commented Jan 26, 2022 at 11:39
  • 1
    You have lost the quotes that the CSS content property requires - as can be seen from the values before you update them. Put some quotes into your string and all should be well. Commented Jan 26, 2022 at 11:43

1 Answer 1

2

CSS variables are copied as they are from where they are defined to the place where they are used. It is mostly just a dynamic copy and paste which is why stuff like that works:

:root {
   --color: 255,0,;
   --comma: ,;
}

div {
   color: rgba(var(--color) 5 var(--comma) 0.5);
}

When you do:

root.style.setProperty("--release-version", releaseVersion)
root.style.setProperty("--build-version", buildVersion)

It would result into this:

:root {
   --release-version: R1.1.0;
   --build-version: v1.32.0;
}

I mean you would expect that root.style.setProperty("--color", "red") results into --release-version: red; and not into --release-version: "red";. But the text has to be quoted, so you somehow need to add the quotes around the text.

You could utilize JSON.stringify to convert the string a textual representation with those quotes that are required, which would also allow to " in the contents of the value:

//TODO: get versions from a config file or something
let releaseVersion = 'R1.1.0"'
let buildVersion = 'v1.32.0"'

window.onload = () => {
    const root = document.querySelector(":root");
    root.style.setProperty("--release-version", JSON.stringify(releaseVersion))
    root.style.setProperty("--build-version", JSON.stringify(buildVersion))
    
    //cannot change label text with CSS
    document.querySelector("#app-version").innerHTML = releaseVersion
}
:root {
    --release-version: "R0.0.0";
    --build-version: "v0.0.0";
}

/* https://css-tricks.com/swapping-out-text-five-different-ways/#aa-css-only-way */
#app-version {
    position: relative;
}
#app-version-checkbox {
    display: none;
}
#app-version-checkbox:checked + #app-version::after {
    content: var(--build-version);
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: white;
}
<input id="app-version-checkbox" type="checkbox">
<label for="app-version-checkbox" id="app-version"></label>

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

1 Comment

@User1291 Many problems are obvious once you know the reason for it not working.

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.