I'm using
#progressBar{
background-color: #247BA0;
width: 150px;
padding: 10px;
border-radius: 5px;
animation: progressBar 3s ease;
animation-fill-mode:both;
text-align: center;
box-sizing: content-box;
}
and
@keyframes progressBar {
0% { width: 0; }
100% { width: 280px; }
}
I want to change the width number of @keyframe
using a JS variable. How could I do this (whithout jQuery) ?
I guess we are in the territory of CSS+JS = CJSSS thats lot of Ss to handle tbh. JS deals with Document object model and CSS deals with CSS object model. Browser object model deals with both of these.
That's being said JS have no interaction with CSSOM. What we see on screen is BOM taking the two and painting it on screen. It is when its painted aka DOM is represented Js is able to access and manipulate objects.
With above in mind when we change style values with JS e.g. element.style.height=100% it is happening after the fact widely known as computed value.
By computed it refers to what got painted on screen so element.height would return hight in pixels not the CSS rule from which it was painted that being percentage.
Thus when we are intending to change @keyframe we are intending to manipulate CSS rule before the fact not after the fact. thats problem no 1.
BOM only provides set number of CSS style properties to be manipulated through style function e.g. height color etc It does not include @keyframe in that set.
so we have to do some leg work to handle it after the fact.
root = document.documentElement;
setTimeout(function(){ root.style.setProperty('--change', 30 + "px"); }, 5000);
:root {
--change: 280px;
}
#progressBar{
background-color: #247BA0;
width: 150px;
padding: 10px;
border-radius: 5px;
animation: progressBar 3s ease;
animation-fill-mode:both;
text-align: center;
box-sizing: content-box;
}
@keyframes progressBar {
0% { width: 0; }
100% { width: var(--change); }
}
<div id="progressBar"></div>
So here is my solution allow me to introduce CSS Variables
I have created a CSS variable in CSSOM globle scope
:root {
--change: 280px;
}
then have accessed the same with in CSS. Benefit is when ever the value of variable is changed in root it will be automatically be represented where ever the variable is called.
@keyframes progressBar {
0% { width: 0; }
100% { width: var(--change); }
}
No we need to access this in after the fact. I have used document.documentElement to grab the whole document as an element including all the css that is in it. then I have used style.setProperty to modify the modifies an existing CSS property in a CSS declaration block. Keyword declaration block not the computed painted block.
root.style.setProperty('--change', 30 + "px");
Above is changing the property of the document which is set in global scope of CSSOM and it has no sub properties etc. We still cannot access rules e.g. root.style.setProperty('@keyframes progressBar', 30 + "px") simply wont work.
final example to use it as before the fact.
root = document.documentElement;
root.style.setProperty('--change', 30 + "px");
:root {
--change: 280px;
}
#progressBar{
background-color: #247BA0;
width: 150px;
padding: 10px;
border-radius: 5px;
animation: progressBar 3s ease;
animation-fill-mode:both;
text-align: center;
box-sizing: content-box;
}
@keyframes progressBar {
0% { width: 0; }
100% { width: var(--change); }
}
<div id="progressBar"></div>
KEY TAKE AWAY. manipulating CSS block after the fact wont rerun the animation again as seen in the first example unless you run another set of function that reverses every thing then redoes it. Depends on your context.
manipulating CSS block before the fact will consider JS manipulation as considered value as shown in the second example.
By context I mean what ever you intend to do really as sown in example below using set time out we are changing css variable after 3 seconds obviously animation is ran twice to but on second run bar goes even longer. so CJSSS alo needs you context.
root = document.documentElement;
setTimeout(function(){ root.style.setProperty('--change', 500 + "px"); }, 3000);
:root {
--change: 280px;
}
#progressBar{
background-color: #247BA0;
width: 150px;
padding: 10px;
border-radius: 5px;
animation: progressBar 3s ease;
animation-fill-mode:both;
text-align: center;
box-sizing: content-box;
animation-iteration-count: 2;
}
@keyframes progressBar {
0% { width: 0; }
50% { width: var(--change); }
100% { width: 0; }
}
<div id="progressBar"></div>
Hope answer gives you enough head ways to move forward.