How to use :root, instead of a class

I created this random background code.

Is an addEventListener needed or necessary to have in the code?

It works with an addEventListener. https://jsfiddle.net/q8bdwLxk/

(function randomBackground() {
  window.addEventListener("DOMContentLoaded", function(event) {
    const ran = Math.floor(Math.random() * 3 + 1)
    document.querySelector('body').classList.add('play' + ran)
  })
}());

And without one. https://jsfiddle.net/pfLdx26v/

(function randomBackground() {
  const ran = Math.floor(Math.random() * 3 + 1)
  document.querySelector('body').classList.add('play' + ran)
}());

You know how, when you write your JS on a separate file and then load it as a script source, you can place it above your body content, where you would usually place the stylesheets link and other libraries, or you might put it beneath the body. If you do the second, your JS code will load before the DOM is loaded, so you want to wrap your functionality within the DOMContentLoaded event listener. If you link your JS file above the body, your functionality will apply once the document is loaded, so there is no need for the event listener. By default, you can manipulate elements of the document obejct, only after they are present.

If I understand this correctly:

In github it is done this way:

    <script type="text/javascript" src="script.js"></script>
  </body>
</html>

Which would mean, I would then be using this one?

(function randomBackground() {
  const ran = Math.floor(Math.random() * 3 + 1)
  document.querySelector('body').classList.add('play' + ran)
}());

And so then, addEventListener would not be needed here.

actually this provides better on the matter:

Was I wrong?

If you link your JS file above the body, your functionality will apply once the document is loaded, so there is no need for the event listener.

This would be above body:

    <script type="text/javascript" src="script.js"></script>
  </body>
</html>

Which means this one can be used:

(function randomBackground() {
  const ran = Math.floor(Math.random() * 3 + 1)
  document.querySelector('body').classList.add('play' + ran)
}());

or, am I wrong?

I’m confused now.

If it is set up this way, which one would I be using?

    <script type="text/javascript" src="script.js"></script>
  </body>
</html>

The one with addEventListener or without?

i was amiss in my initial post.
If you put your JS source at the end of your body element, you dont need to apply DOMContentLoaded. (no event listener)

1 Like

Thank you for the clarification.

I created a random background code here.

3 different ways.

How do I know which is the better of the 3 codes I made?

The first 2 codes use an array, code 3 uses the least amount of code.

To see that it works, just click run in the jsfiddle.

Code 1
https://jsfiddle.net/a6hm3s5d/1/

(function randomBackground() {
  const colors = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
  const random = colors[Math.floor(Math.random() * colors.length)];
  document.querySelector('body').classList.add('play' + random);
}());

Code 2
https://jsfiddle.net/r2c5Lf4v/1/

(function randomBackground() {
  const colors = ['play1', 'play2', 'play3', 'play4', 
  'play5', 'play6', 'play7', 'play8', 'play9'];
  const random = Math.floor(Math.random() * colors.length);
  document.querySelector('body').classList.add(colors[random]);
}());

Code 3
https://jsfiddle.net/zhtkyjep/

(function randomBackground() {
    const random = Math.floor(Math.random() * 8 + 1);
    document.querySelector('body').classList.add('play' + random);
}());

css

.play1 {
  --color-a: blue;
  --color-b: black;
  --color-c: red;
  --color-d: black;
}

.play2 {
  --color-a: purple;
  --color-b: black;
  --color-c: purple;
  --color-d: black;
}

.play3 {
  --color-a: green;
  --color-b: black;
  --color-c: green;
  --color-d: black;
}

.play4 {
  --color-a: orange;
  --color-b: black;
  --color-c: orange;
  --color-d: black;
}

.play5 {
  --color-a: yellow;
  --color-b: black;
  --color-c: yellow;
  --color-d: black;
}

.play6 {
  --color-a: blue;
  --color-b: black;
  --color-c: orange;
  --color-d: black;
}

.play7 {
  --color-a: red;
  --color-b: black;
  --color-c: green;
  --color-d: black;
}

.play8 {
  --color-a: white;
  --color-b: black;
  --color-c: white;
  --color-d: black;
}

.play9 {
  --color-a: red;
  --color-b: black;
  --color-c: red;
  --color-d: black;
}

Hi @javascriptcoding5678

There are certain things I usually look into when picking a solution out of several solutions that work. One of the most important one is whether it will be readable if I or someone else looks at the code in the future. And I also look at things like re-usability, efficiency, testability and maintenance.

In my opinion, any of the solutions would work with some slight modification of the code and naming variables appropriately. Look at the colors array. Are they colors or class names? Or are they parts of class names. The colors array holds different pieces of information for code 1 and code 2. Someone who has not looked at the codebase before will only understand the data the colors array is holding after reading the last line of code.

When you look at code 3, it has some hard-coded values like 8 when generating a random integer. Why 8? Is there anything special about 8?

I hope that helps you choose the best solution for your use-case.

naming variables appropriately

In codes 1 & 2, colors can be changed to const classNames for better readability.

some slight modification of the code

What would be the modification of the code you would make?

Code 1
https://jsfiddle.net/9znq65vL/

(function randomBackground() {
    const classNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
    const random = classNames[Math.floor(Math.random() * classNames.length)];
    document.querySelector("body").classList.add("play" + random);
}());

Code 2
https://jsfiddle.net/9znq65vL/1/

(function randomBackground() {
  const classNames = ["play1", "play2", "play3", "play4",
    "play5", "play6", "play7", "play8", "play9"
  ];
  const random = Math.floor(Math.random() * classNames.length);
  document.querySelector("body").classList.add(classNames[random]);
}());

In Code 3, were you saying that this part * 8 + 1 can be written a different way?

Maybe without using numbers?

If yes, how would this be written without using numbers?

https://jsfiddle.net/zhtkyjep/

    const random = Math.floor(Math.random() * 8 + 1);
    document.querySelector('body').classList.add('play' + random);

What would have been the modification of the code you would have made?

I had this working awhile ago, I had figured it out.

But I forgot to save it.

I do know it was hard for me to figure out, but I don’t remember what I did.

I figured this part out. https://jsfiddle.net/39ph4bvs/9/

I am doing something wrong here, but I can’t seem to wrap my head around what I am doing incorrectly.

I can’t wrap my head around how to fix the CSS.

My head hurts from trying to figure out how to do this.

It’s only the CSS that is messed up.

All I am doing is adding custom css selectors which is giving me a hard time.

Ignore the videos, it’s only the custom css selectors I am trying to get working. The css selectors have nothing to do with the videos. I don’t need help with videos, I need help with implementing the custom css selectors.

I think this part I have fine.

This part is GOOD

    .bg1 {
      --color-a: linear-gradient(120deg, #155799, #159957);
    }
    
    .bg2 {
      --color-b: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
    }
    
    .bg3 {
      --color-c: linear-gradient(45deg, #102eff, #d2379b);
    }
    
    .bg4 {
      --color-d: linear-gradient(90deg, #360033 30%, #0b8793 100%);
    }
    
    .bg5 {
      --color-e: linear-gradient(115deg, #0a0e88, #00b1ce);
    
    }
    
    .bg6 {
      --color-f: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
    }
    
    .bg7 {
      --color-g: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
    }
    
    .bg8 {
      --color-h: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
    }
    
    .bg9 {
      --color-i: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
    }

I got stuck here:

I have no idea why my head is confused on how this is done.

WRONG

    body {
      background-image:
        linear-gradient(var(--color-a)),
        linear-gradient(var(--color-b)),
        linear-gradient(var(--color-c)),
        linear-gradient(var(--color-d)),
        linear-gradient(var(--color-e)),
        linear-gradient(var(--color-f)),
        linear-gradient(var(--color-g)),
        linear-gradient(var(--color-h)),
        linear-gradient(var(--color-i));
      background-repeat: no-repeat;
    }

That part there is entirely wrong.
I don’t know how to fix it.
There is a way for it to be written, I don’t know how to do it.

Here was my second attempt: videoPlayer test page - JSFiddle - Code Playground

I have a working version here and I am still confused.
https://jsfiddle.net/g9h4xLsv/

I have no idea why my head can’t figure this out.

WRONG

    body {
      background-image:
        (var(--color-a)),
        (var(--color-b)),
        (var(--color-c)),
        (var(--color-d)),
        (var(--color-e)),
        (var(--color-f)),
        (var(--color-g)),
        (var(--color-h)),
        (var(--color-i));
      background-repeat: no-repeat;
    }

That part there is entirly wrong.
I don’t know how to fix it.
There is a way for it to be written, I don’t know how to do it.

Here was my 3rd attempt: https://jsfiddle.net/8b0msnkL/3/

WRONG

    body {
      background-image:
        linear-gradient(var(--color-a), var(--color-a)),
        linear-gradient(var(--color-b), var(--color-b)),
        linear-gradient(var(--color-c), var(--color-c)),
        linear-gradient(var(--color-d), var(--color-d)),
        linear-gradient(var(--color-e), var(--color-e)),
        linear-gradient(var(--color-f), var(--color-f)),
        linear-gradient(var(--color-g), var(--color-g)),
        linear-gradient(var(--color-h), var(--color-h)),
        linear-gradient(var(--color-i), var(--color-i));
      background-repeat: no-repeat;
    }

That part there is entirely wrong.
I don’t know how to fix it.
There is a way for it to be written, I don’t know how to do it.

I tried reducing the code down to 1 line here:

https://jsfiddle.net/8b0msnkL/6/

That does not seem to be helping.

WRONG

    .bg1 {
      --color-a: linear-gradient(120deg, #155799, #159957);
    }
    
    body {
      background-image:
        linear-gradient(var(--color-a), var(--color-a));
      background-repeat: no-repeat;
    }

That part there is entirely wrong.
I don’t know how to fix it.
There is a way for it to be written, I don’t know how to do it.

Placing the custom property declaration inside the .bg1 scopes it to only elements with the class bg1 or their children. Since your <body> neither has the class bg1 nor is it a child of an element with the class bg1, it does not have access to the --color-a custom property.

Since --color-a is not defined in scope, the body background-image basically looks like this when evaluated:

background-image: linear-gradient( , );

So, you could move the custom property declarations to the body tag selector to fix the scoping issue.

body {
  --color-a: linear-gradient(120deg, #155799, #159957);

  background-image: linear-gradient(var(--color-a), var(--color-a));

But then you’ve got another issue, because here’s what that looks like evaluated:

background-image: linear-gradient(linear-gradient(120deg, #155799, #159957), linear-gradient(120deg, #155799, #159957));

Fixed: https://jsfiddle.net/axm93y7w/

Like this?

.bg1 {
  --color: linear-gradient(120deg, #155799, #159957);
}
body {
  background-image: var(--color);
  background-repeat: no-repeat;
}

Most often you would use the :root selector for setting the initial values. It doesn’t make much sense to have to move class selectors up before the type selectors (in this case body) just to set the values.

Sometimes you will set the value in a selector that comes before another selector where the value is used, but not in this case. Having class selectors before the type selectors is just a confusing CSS structure.

If I were to use :root instead of a class here, how would I do that?

https://jsfiddle.net/r9bygt3d/

(function randomBackground() {
  const classNames = [
    "bg1",
    "bg2",
    "bg3",
    "bg4",
    "bg5",
    "bg6",
    "bg7",
    "bg8",
    "bg9",
    "bg10"
  ];

  const random = Math.floor(Math.random() * classNames.length);
  document.querySelector("body").classList.add(classNames[random]);
}());
.bg1 {
  --color: linear-gradient(76.9deg, #e8bbf2, #8787fd 51.66%, #84caff 109.18%);
}

.bg2 {
  --color: linear-gradient(45deg, #102eff, #d2379b);
}

.bg3 {
  --color: radial-gradient(60% 60% at 50% 50%, rgb(40, 0, 115), rgb(0, 0, 0));
}

.bg4 {
  --color: radial-gradient(rgba(80, 0, 0, 0.1) 0%, rgba(80, 0, 0, 0.2) 30%, rgba(21, 11, 1, 0.9) 100%), linear-gradient(to right, #02111d, #037bb5, #02111d);
}

.bg5 {
  --color: radial-gradient(rgba(80, 0, 0, 0.1) 0%, rgba(80, 0, 0, 0.2) 30%, rgba(21, 11, 1, 0.9) 100%), linear-gradient(to right, #02111d, #037bb5, #02111d);

}

.bg6 {
  --color: radial-gradient(circle at 5% 13%, #0b7bd2, #3d41b4 40%, #591fa4 101%);
}

.bg7 {
  --color: linear-gradient(95deg, #67115e, #2d0546 31%, #160322);
}

.bg8 {
  --color: linear-gradient(darkviolet, navy);
}

.bg9 {
  --color: linear-gradient(120deg, rgba(255, 125, 255, 0.7), rgba(125, 85, 255, 0.7) 70%);
}

.bg10 {
  --color: linear-gradient(90deg, #10069F, #9932CC);
}

Something like this?

:root {
  --color-a: linear-gradient(76.9deg, #e8bbf2, #8787fd 51.66%, #84caff 109.18%);
  --color-b: linear-gradient(45deg, #102eff, #d2379b);
  --color-c: linear-gradient(95deg, #67115e, #2d0546 31%, #160322);
}

But then how would the javascript be written?

The position of the classes is irrelevant in that case. Whatever class you add to the body will set the --color.

Using custom properties isn’t really doing much for you. You might as well just have the classes set the background-image property directly.

You also do not need classes to set custom properties. You get and set them from JS using getPropertyValue and setProperty.

1 Like

Keeping the CSS out of the javascript, how would this be written differently, fixed, or modified?

Do you see anything that can be adjusted in it?

https://jsfiddle.net/f7qopgwL/

:root {
  --color-a: linear-gradient(120deg, #155799, #159957);
  --color-b: linear-gradient(0deg, #522db8 0%, #1c7ce0 100%);
  --color-c: linear-gradient(45deg, #102eff, #d2379b);
}
(function randomBackground() {
  const varNames = [
    "color-a",
    "color-b",
    "color-c"
  ];

  const random = Math.floor(Math.random() * varNames.length);
  document.body.style.backgroundImage = 'var(--' + varNames[random] + ')';
}());

or, is there a way to do that with your code? https://jsfiddle.net/0hcgkurm/

:root {
  --bg-color: linear-gradient();
}

body {
  background: var(--bg-color, white);
  background-repeat: no-repeat;
  min-height: 100vh;
  overflow: hidden;
}
(function randomBackground() {

  const linearGradients = [
    "linear-gradient(to right, #c6ffdd, #fbd786, #f7797d)",
    "linear-gradient(to right, #6a3093, #a044ff)",
    "linear-gradient(to right, #a8ff78, #78ffd6)",
    "linear-gradient(to right, #6d6027, #d3cbb8)",
    "linear-gradient(to right, #4da0b0, #d39d38)",
    "linear-gradient(to right, #74ebd5, #acb6e5)",
    "linear-gradient(to right, #12c2e9, #c471ed, #f64f59)",
    "linear-gradient(to right, #4b79a1, #283e51)",
    "linear-gradient(to right, #0099f7, #f11712)"
  ];

  const randomColor =
    linearGradients[Math.floor(Math.random() * linearGradients.length)];
  document.querySelector("body").style.setProperty("--bg-color", randomColor);
}());

Do whatever works for you, it’s your code. But the example you have is still setting CSS in the JS.

The point of the code I posted is that you only have one custom property that you change the value of instead of having different custom properties with different values. Because if you do that, as I said, you really might as well just be setting the CSS background-color property directly. At least that’s the way I see it.

I was told:

Where possible keep the CSS out of the JS.

Don’t do this unless there is no choice.

  const linearGradients = [
    "linear-gradient(to right, #c6ffdd, #fbd786, #f7797d)",
    "linear-gradient(to right, #6a3093, #a044ff)",
    "linear-gradient(to right, #a8ff78, #78ffd6)",
    "linear-gradient(to right, #6d6027, #d3cbb8)",
    "linear-gradient(to right, #4da0b0, #d39d38)",
    "linear-gradient(to right, #74ebd5, #acb6e5)",
    "linear-gradient(to right, #12c2e9, #c471ed, #f64f59)",
    "linear-gradient(to right, #4b79a1, #283e51)",
    "linear-gradient(to right, #0099f7, #f11712)"
  ];

I was just told that this one, in their opinion would be the cleanest and the most easiest to maintain.

https://jsfiddle.net/r9bygt3d/

Javascript

(function randomBackground() {
  const classNames = [
    "bg1",
    "bg2",
    "bg3",
    "bg4",
    "bg5",
    "bg6",
    "bg7",
    "bg8",
    "bg9",
    "bg10"
  ];

  const random = Math.floor(Math.random() * classNames.length);
  document.querySelector("body").classList.add(classNames[random]);
}());

CSS

.bg1 {
  --color: linear-gradient(76.9deg, #e8bbf2, #8787fd 51.66%, #84caff 109.18%);
}

.bg2 {
  --color: linear-gradient(45deg, #102eff, #d2379b);
}

.bg3 {
  --color: radial-gradient(60% 60% at 50% 50%, rgb(40, 0, 115), rgb(0, 0, 0));
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background-image: var(--color);
  background-repeat: no-repeat;
}