Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does changing CSS variables in JS break the app?

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

//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.

>Solution :

CSS variables are copied as they are from where they are defined to the place where they are use var(--build-version).

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>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading