Search code examples
javascriptcsscss-variables

Manipulate a CSS-Variable by clicking


I want to double the value of an elements' property each time it gets clicked. Thereby I am using CSS-variables. So I am trying to do that:

#circle_1 {
width:50px;
height:50px;
width: var(--size_1, 50px);
height: var(--size_1, 50px);
}

and that:

// Vars
var circle_1 = document.querySelector("#circle_1");
var size_1 = document.getPropertyValue("--size_1");

// Function to grow the circle
function growCircle() {
var size_1_n =size_1*2;
  circle_1.style.setProperty("--size_1", size_1_n.value);
}

// Event listener
var el = document.getElementById("circle_1");
el.addEventListener("click", growCircle, false);

You may see it here https://codepen.io/daiaiai/pen/QQXrGz

Nothing is happening. I assume it's something wrong with (at least) var size_1 = document.getPropertyValue("--size_1"); but I can't really figure it out. Could you guide me a bit (much) please?


Solution

  • There are quite a lot of problems with your codepen, so I will clean up your code, and present a working example instead.

    Here are some key changes:

    1. I have added a :root delcaration for the variable. This allows me to get the value of --size_1 at the element circle_1. Without this, you'd get NaN as the value of the variable, as it is not declared anywhere in the styles.

      You could write some conditions to get the computed width or height values, but I felt it is cleaner to put a default value in :root.

    2. Since you are setting the value like 50px instead of 50, i.e. value with units, you need to get the numerical part out of it before you could double it. I am using parseInt(size_1) for that.

    var circle_1 = document.querySelector("#circle_1");
    var size_1 = document.body.style.getPropertyValue("--size_1");
    
    // Function to grow the circle
    function growCircle() {
      var size_1 = window.getComputedStyle(circle_1).getPropertyValue("--size_1");
      var size_1_n = parseInt(size_1) * 2;
      circle_1.style.setProperty("--size_1", size_1_n + "px");
    }
    
    
    // Event listener
    circle_1.addEventListener("click", growCircle, false);
    :root {
      --size_1: 50px;
    }
    
    body {
      margin: 100px;
    }
    
    #circle_1 {
      width: var(--size_1, 50px);
      height: var(--size_1, 50px);
      border-radius: 50%;
      margin-top: 20px;
      background-color: pink;
      opacity: 0.7;
      display: inline-block;
      transition: 0.3s;
    }
    
    div span {
      position: relative;
      top: 50%;
      left: 50%;
      text-align: center;
    }
    <div id="circle_1" draggable="true"><span>Group 1<span></div>


    A slightly different approach to this would be to declare the value part only in the variable's :root declaration. You could then refer to its value using width: calc(var(--size_1) * 1px).

    I personally prefer this approach as the variable only carries the value component, and you could apply any unit you like at the time of declaring a style. Also, this would allow you to avoid the parseInt of variable's value.

    Here's a snippet with that approach:

    var circle_1 = document.querySelector("#circle_1");
    var size_1 = document.body.style.getPropertyValue("--size_1");
    
    // Function to grow the circle
    function growCircle() {
      var size_1 = window.getComputedStyle(circle_1).getPropertyValue("--size_1");
      var size_1_n = size_1 * 2;
      circle_1.style.setProperty("--size_1", size_1_n);
    }
    
    
    // Event listener
    circle_1.addEventListener("click", growCircle, false);
    :root {
      --size_1: 50;
    }
    
    body {
      margin: 100px;
    }
    
    #circle_1 {
      width: calc(var(--size_1, 50px) * 1px);
      height: calc(var(--size_1, 50px) * 1px);
      border-radius: 50%;
      margin-top: 20px;
      background-color: pink;
      opacity: 0.7;
      display: inline-block;
      transition: 0.3s;
    }
    
    div span {
      position: relative;
      top: 50%;
      left: 50%;
      text-align: center;
    }
    <div id="circle_1" draggable="true"><span>Group 1<span></div>