Guide to updating the value of a CSS seconds dynamically

let timerSeconds = 10;  // This value will be retrieved from a database

function StartCountDownTimer() {
  let timerStart = new Date();
  let css_seconds = `${timerSeconds}s`;
  
  const css_root = document.querySelector(':root');
  
  let cssVarBefore = '--timer-seconds BEFORE being set by JS: ' + getComputedStyle(css_root).getPropertyValue('--timer-seconds');
  
  css_root.style.setProperty('--timer-seconds', css_seconds);
  
  let cssVarAfter = '--timer-seconds AFTER being set by JS: ' + getComputedStyle(css_root).getPropertyValue('--timer-seconds');
  
  document.querySelector('.progress-border').classList.add('progress-border-animation');

  timerStart.setSeconds(timerStart.getSeconds() + timerSeconds);
  timerStart = timerStart.getTime();

  // Update the countdown every second
  let x = setInterval(function() {
    let now = new Date().getTime();
    let distance = timerStart - now;
    let seconds = Math.round(distance / 1000, 1000);
    document.getElementById("seconds-remaining").innerHTML = seconds;

    if (seconds < 1) {
      clearInterval(x);
      document.getElementById("seconds-remaining").innerHTML = "";
      document.querySelector('.progress-border').classList.remove('progress-border-animation');
      alert("This shows that the CSS variable has been changed but it doesn't affect the animation duration.\n\n" + cssVarBefore + '\n' + cssVarAfter);      
     }
  }, 1000);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;

/* The CSS variable is being tried to set dynamically from JavaScript */
  --timer-seconds: 5s;
  --box-size: 150px;
  --border-width: 8px;
}

body {
  margin: 3em;  
}

container {
  display: flex;
  flex-direction: columns;
  gap: 1em;
}

.secs {
  color: #365a2a;
  font-size: 72px;
  font-weight: bold;
  text-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);
}

.count-down-timer{
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  width: var(--box-size);
  height: var(--box-size);
  border: var(--border-width) solid #c05b20;
  border-radius: calc(var(--border-width)*2);
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
  background: linear-gradient(#599646, #bfe2c3);
  cursor: pointer;
}

.progress-border {
  position: absolute;
  top: calc(var(--border-width)*-1);
  left: calc(var(--border-width)*-1);
  width: var(--box-size);
  height: var(--box-size);
  border-radius: calc(var(--border-width)*2);
}

.progress-border-animation {
  border: var(--border-width) solid #365a2a;
  animation: fill forwards linear;
  animation-duration: var(--timer-seconds); 
  /* animation-duration: 10s; */ /* this line works */
}

@keyframes fill {
   /* keyframes styling goes here */
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Progress Bar</title>
  </head>
  <body>
    <container>
      <div>
        <p><b>Click on the box to start the timer</b></p><br>
        <div onclick="StartCountDownTimer()" class="count-down-timer">
          <p class="secs" id="seconds-remaining"></p>
          <div class="progress-border"></div>
        </div>
      </div>
      <div>
        <p><b>Need help:</b></p>
        <p>The goal is to dynamically change the seconds value for the CSS animation duration. Although the CSS variable is set to 10 seconds, I want to alter it through JavaScript to a dynamic value like 60 seconds. However, my attempts have not been successful so far.
        </p>
      </div>
    </container>
  </body>
</html>

I am exploring ways to modify the seconds value for a CSS animation duration dynamically. Currently, the value is statically assigned as 20s in the CSS class. From JavaScript, I aim to change this value to something dynamic, e.g., 60s. As I need an integer type in JavaScript for other computations, there might be conflicts with using different data types between integers and seconds. Suggestions are welcome to address this challenge...

  1. Tried changing the CSS integer variable --sec: 20 from JS, then utilizing calc(0s + var(--sec)) for the animation duration.
  2. Attempted to modify the CSS seconds variable --sec: 20s from JS by concatenating (60 + 's') and using var(--sec) for the animation duration.
  3. Tested modifying the animationDuration value of document.getElementsByClassName('class')[0].style from JS by concatenating (60 + 's')

Any insights or advice would be greatly appreciated...

Answer №1

Update on the recent code update

After reviewing the latest code, it appears that the CSS variables are not properly defined within :root {}, but rather in * {}. This caused the setProperty() function to not work as intended.

If you move these variable definitions to :root {}, the code should function correctly:

:root {
  --timer-seconds: 5s;
  --box-size: 150px;
  --border-width: 8px;
}

Additional update on custom duration input

Another option is to set the value of animation-duration in CSS using milliseconds (ms).

More information on animation-duration

Below is a simplified example where a value in milliseconds is set to animation-duration by modifying a variable --duration on the animated element.

There are multiple approaches to achieving this, but this method seems straightforward.

Hope this explanation proves useful.

const figure = document.querySelector("figure");
const btns = document.querySelectorAll("button:not(#custom)");
const btnCustom = document.querySelector("button#custom");
const input = document.querySelector("input");

btnCustom.addEventListener("click",()=>{
  const {value} = input
  if (!value || isNaN(value) || value < 100 || value > 2000) {
    input.value = ""
    return}
  const duration = `${Math.floor(value)}ms`
  figure.style.setProperty("--duration", duration)
})

btns.forEach((btn) =>
  btn.addEventListener("click", (e) =>
    figure.style.setProperty("--duration", e.target.dataset.duration)
  )
)
*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

section {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  align-items: center;
  width: 500px;
  padding: 6px;
}

.control {
  display: flex;
  width: 100%;
  justify-content: center;
  align-items: center;
  gap: 3px;
}

button {
  flex: 1;
  padding: 3px;
}

input {
  flex: 1;
  padding: 3px;
}

.animation {
  display: flex;
  align-items: center;
  width: 500px;
  height: 150px;
  background-color: #fdf5e6;
}

figure {
  width: 100px;
  height: 100px;
  background-color: #1e90ff;
  border-radius: 50%;
  animation: move alternate infinite linear;
  animation-duration: var(--duration, 1200ms);
}

@keyframes move {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(400px);
  }
}
<section>
  <div class="control">
    <input
      type="number"
      min="100"
      max="2000"
      step="100"
      placeholder="Enter num between 100 and 2000"
    />
    <button id="custom">Set custom duration in ms</button>
  </div>

  <div class="control">
    <button data-duration="1200ms">Default</button>
    <button data-duration="700ms">Fast</button>
    <button data-duration="300ms">Faster</button>
  </div>
  <div class="animation">
    <figure></figure>
  </div>
</section>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The requested `GLIBC_2.28' version required by node cannot be located, leading to an inability to amplify the version

While there were numerous questions about this topic, I am specifically seeking solutions for amplify. Below are the logs from my amplify build: 2024-01-14T16:14:17.626Z [INFO]: # Cloning repository: <a href="/cdn-cgi/l/email-protection" class="__cf_em ...

Update data in the datatables using values from an array list

Currently, I have two HTML files where I am loading data using JSON and then applying jQuery datatables to them. Now, I need to refresh the data with new parameters. For example: JSON: [ {"name":"jon","sales":"100","set":"SET1"}, {"name":"charlie","sale ...

The HTTPOnly cookie is not accessible within the getServerSideProps function in Next.js

Why isn't the jid cookie available in getServerSideProps using Next JS? Here's the scenario: https://i.stack.imgur.com/FLRGk.png The jid cookie is generated by an Expressjs API at https://api-dev.example.com. I'm attempting to retrieve thi ...

Unable to access the 'fn' property of undefined in Handlebars causing a TypeError

I encountered an issue with my custom handlebars helper. When I fail to define values for the parameters, I receive the following error message. module.exports = function(src, color, classatr, options) { if (typeof src === 'undefined') src ...

Extract the image URL from a JSON API

I'm struggling to retrieve an image URL from a Wordpress JSON API and populate an image tag with it. Below is the code that isn't working for me: $(document).ready(function() { $.getJSON('http://interelgroup.com/api/get_post/?post_id=46 ...

JavaScript matching partial domains

let address = 'http://sub.domain2.net/contact/'; if (['https://sub.domain1.com/', 'http://sub.domain2.net/'].includes(address)) { console.log('match'); } else { console.log('no match'); } Here, it ...

The ASP Classic site is not displaying the expected styles on its elements

Currently, I am revamping an ASP Classic website. The entire site relies on a major CSS file named Main which houses all the styles used. In this file, there are not many styles as the current design is quite basic. Some elements on certain pages have thei ...

What is the best way to allocate a larger size to one part of a flex div?

A div is used to insert information <div class="inputs"> <div class="content">@Html.TextBoxFor(model => invoices.ProductDesc, new { disabled = "disabled", @readonly = "readonly" })</div> <div class="content">@Html.TextBo ...

Creating side by side input panels with Bootstrap version 3.1 on Internet Explorer 8

Although I have some familiarity with Bootstrap, my experience with it is limited. While attempting to create a static form using Bootstrap, I encountered difficulties getting panels to align side by side using the "col-md-6" class within rows. Despite my ...

Opening a modal in React Material UI from an autocomplete component results in losing focus

My current challenge involves utilizing the material-ui library to create an autocomplete feature where each item is clickable and opens a modal window. The basic structure looks like this: const ModalBtn = () => { ... return ( <> ...

Publishing Your App on the Android Market with PhoneGap

Seeking a comprehensive PhoneGap tutorial that covers app publishing, especially struggling with successful app deployment. Currently experienced in HTML, CSS, and JavaScript. Any tips or advice would be greatly appreciated, thank you! I have a good gras ...

How can a jQuery fadeTo Effect be timed?

Presently, I am utilizing jQuery's fadeTo function to gradually fade in a div. Nevertheless, I am encountering a slight timing issue. I have an Animated GIF file that I wish to synchronize with the jQuery fadeTo effect. I have tried using window.onlo ...

Incorporating a class into ever-changing Bootstrap Table rows

Looking to enhance my table rows with a class, excluding the header. Struggling to find a way to do this. Any ideas? This is the table in question: <table id="table" class="hidden table table-bordered table-striped table-hover"> <thead> ...

update the element that acts as the divider in a web address (Angular)

Is it possible to modify the separator character used when obtaining the URL parameters with route.queryParams.subscribe? Currently, Object.keys(params) separates the parameters using "&" as the separator. Is there a way to change this to use a differe ...

Limiting the length of numbers in Material UI

Is there a way to restrict user input to only numbers with a maximum length of 3 in Material UI? <TextField id="score" label="score" className={classes.textField} name="totalScore" margin="normal" defaultValue={score} /> We specifically ...

click to save the document

My goal is to download a csv file when clicked, rather than having it open in the browser I attempted this code <a href="file.csv">download file</a> However, when I click the link, the file opens in the browser instead of downloading. Intere ...

Having trouble with your CSS on your mobile website?

After developing a website and implementing media queries for responsiveness, everything seemed to be in perfect working order. The website displayed flawlessly on emulators like () and Chrome's inspect element, mirroring my desired mobile design. How ...

What are the steps to create a customized app bar with React and Material-UI similar to this design?

Can anyone help me create an app bar that resembles this design: Click here to view I have managed to implement the search box in the top half of the app bar, but I am struggling with adding the bottom half. Here is the code I have written so far: ...

How can I ensure my button aligns to the left with the element above in Bootstrap?

Here is a JSFiddle link for reference: https://jsfiddle.net/sf4wkyx0/ The alignment of my 'Add' button with the textarea seems slightly off: https://i.sstatic.net/r7lAn.png Both elements are within a container with the class col-2, but the al ...

Emphasizing sections using a specific class for paragraph highlighting

Is it possible to dynamically change the style of paragraphs based on certain classes? Let's say we have a text with a list of p elements and we want to modify the styles of paragraphs that come after specific classes, such as 'alert' or &ap ...