Preserving and adding new transform on hover (CSS/LESS) - javascript

To make it simple, I have a div that I rotate by default with a JS code. But then I want to add a :hover class, so that it translates when hovering over it. The problem is, that either the new transform does not apply, or the old is not preserved.
How can I make it work? Btw, I am using LESS, so if there's a solution with LESS, would be happy to hear it.
P.S. The angle is being generated according to the number of siblings in JS. Maybe I would be able to do a rotation with LESS and then do a :hover there?
document.getElementById("box").style.transform = "rotate(" + 40 + "deg)";
#box {
width: 50px;
height: 50px;
background-color: red;
transition: all 0.5s ease-in;
}
#box:hover {
background-color: blue;
transform: translate(50px) !important;
}
<div id="box">
</div>

you cannot achieve the desired result using CSS/LESS. You have to use JavaScript to generate dynamic styles. A script similar to below can do the task on your hand:
var dynamic_styles = '';
var counter = 1;
$('.box').each(function() {
$(this).attr('data-num', counter);
dynamic_styles += '.box[data-num="' + counter + '"] {transform: rotate(40deg);}';
dynamic_styles += '.box[data-num="' + counter + '"]:hover {transform: rotate(40deg) translate(50px);}';
counter++;
});
$('head').append('<style>' + dynamic_styles + '</style>');
Please check the codepen here:
http://codepen.io/anon/pen/LGzXEM
P.S. You can change the rotation 40deg with your dynamically calculated values.

Related

How to make top border animated where color goes from left to right

I finished my idea and it works as it is, but it's static and as all developer like, we want to make it better. I have a script where user choose his own top border color for posts(self-developed forum feature).
There is forum post and top border is colored in some color. How can I make it animated. You know when there is a circle and color goes around (it can be different colors) and makes that cool effect (never ending). I don't want something complex as that. I would like a very "simple" concept. Top border color is red (example). Animation starts from left all the way to the right and then repeats. It works like a pulse when heart beats. Like some different color going in that single line, reaching end, stops, repeat.
This is my code:
$(document).ready(function() {
var postDivs = $(".post");
$.each(postDivs, function(index, div) {
var color = ($(".post .postprofile-info")[index].firstChild.nextSibling.data[0] == "#") ? $(".post .postprofile-info")[index].firstChild.nextSibling.data : "#d4d4d4";
$(this).css("border-top", "15px solid " + color);
var element1 = $(".post .postprofile-info ")[index].firstChild;
$(".post .postprofile-info")[index].firstChild.nextSibling.data = "";
element1.style.visibility = "hidden";
});
I know it's quite messy and very badly written but it works :D
Focus here on this line:
$(this).css("border-top", "15px solid " + color);
How can I animate that? I hope I managed to explain myself as best as I could. :)
You can't change the border in the way you would like on the actual element, but you can get the effect using pure CSS (without having to add extra elements to the DOM) by using a before pseudo element.
Here's a simple example in pure HTML/CSS:
div {
height: fit-content;
width: fit-content;
position: relative;
}
div::before {
content: '';
width: 100%;
height: 2px;
background: red;
display: inline-block;
position: absolute;
top: 0;
left: 0;
width: 0;
animation: grow 2s infinite;
}
#keyframes grow {
to {
width: 100%;
}
}
<div>some info</div>

Making a container grow on hover using jQuery

I'm trying to make a jQuery function that takes the current height and width of a link then makes it grow by whatever amount of px I set. I don't have much so far and I'm completely lost.
$('.absolute_img_links').hover(function(){
var link_height = $('.absolute_img_links').outerHeight();
var link_width = $('.absolute_img_links').width();
});
I know how to get the current height and width but I don't know how to basically say height of .absolute_img_links = link_height + 10px in jQuery
same functions do the job:
$('.absolute_img_links').hover(function(){
var link_height = $('.absolute_img_links').outerHeight();
$('.absolute_img_links').outerHeight(link_height + 10);
var link_width = $('.absolute_img_links').width();
$('.absolute_img_links').width(link_width + 10);
});
To achieve what you need you can pass a function to the height() and width() functions. In these functions you receive the current value, to which you can just add the 10px as required.
Note that hover() fires twice, once for mouseenter and once for mouseleave. Also, you don't reset the size of the element, so it just gets larger and larger on successive hovering. To fix this, amend your logic so that you attach the event handlers separately instead of one hover() call so you can increase/decrease the size as needed. Try this:
$('.absolute_img_links').on('mouseenter', function(){
$(this)
.height(function(i, height) { return height + 10; })
.width(function(i, width) { return width + 10; });
}).on('mouseleave', function() {
$(this)
.height(function(i, height) { return height - 10; })
.width(function(i, width) { return width - 10; });
});
.absolute_img_links {
position: absolute;
background-color: #C00;
color: #FFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="absolute_img_links">
Hover me!
</div>
Also note that you can implement a pure CSS version of this which has the exact same effect, although simply adds padding to the right and bottom of the element, instead of changing the width/height. Try this:
.absolute_img_links {
position: absolute;
background-color: #C00;
color: #FFF;
}
.absolute_img_links:hover {
padding: 0 10px 10px 0;
}
<div class="absolute_img_links">
Hover me!
</div>
Using the above method you could even keep the text centralised too, by adding a consistent 5px padding around the entire element.
Using height() and width() you can simply add 10 to the values you have found to increase the height/width of the container.
$('.absolute_img_links').hover(function() {
//var link_height = $('.absolute_img_links').outerHeight();
//var link_width = $('.absolute_img_links').width();
//Changed to $(this)
var link_height = $(this).outerHeight();
var link_width = $(this).width();
$(this).height(link_height + 10);
$(this).width(link_width + 10);
});
.absolute_img_links {
width: 300px;
height: 300px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="absolute_img_links"></div>
I know you asked for jQuery but...
This is trivial (and more flexible) in CSS:
.absolute_img_links img { transition: all .2s ease-in-out; }
.absolute_img_links:hover img { transform: scale(1.1); }
<img src="https://placeimg.com/100/100/any" />
<img src="https://placeimg.com/100/100/any" />

How to increase rotate value

The Problem
I want to increase the rotate value to a div by using jquery, i know you can increase the value of height and width by $("#div").css('height','+=200px') but you cant do that with transform property because it got many value like translate, rotate, scale, and skew.
Question
How to increase rotate value transform: rotate(30deg); by 30deg to become 60deg ?
i dont want to do transform: rotate(60deg); with css or$("#mydiv").css('transform','rotate(60deg)') with Jquery.
Code
// Any idea ?
#container{
padding: 100px;
}
#mydiv{
height: 200px;
width: 200px;
background: pink;
transform: rotate(30deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="mydiv"></div>
</div>
Hint
I tried $("#mydiv").css('transform') it return matrix value.
You can do it by adding rotate into your css('transform' call:
var value = 60;
$("#mydiv").css('transform', 'rotate(' + value + 'deg)');
More demos with CSS3 transitions using jQuery here
Solution
the getRotationDegrees() function will calculate the rotate degress and return the value.
function getRotationDegrees(obj) {
var matrix = obj.css("transform");
if(matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
} else { var angle = 0; }
return (angle < 0) ? angle + 360 : angle;
}
var rotate = getRotationDegrees($("#mydiv")) + 30;
$('#mydiv').css('transform', 'rotate('+rotate+'deg)')
#container{
padding: 100px;
}
#mydiv{
height: 200px;
width: 200px;
background: pink;
transform: rotate(30deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="mydiv"></div>
</div>
EDIT: oops ... I just saw that you don't want to use css, but I will leave answer here for reference
isn't this the purpose of transition?
.my_div_class__closed
{ transform : rotate(30deg) ;
transition : transform 200 ;
/* You could substitute 200 (as in milliseconds) to 0
if you want instantaneous change.
*/
}
.my_div_class__opened
{ transform : rotate(60deg) ;
}
NOTE: vendor prefixes not used in example ... if you don't know vendor prefixes, then copy/paste css snippet into service like autoprefixer .. and be sure to use filter value: >0%

-webkit-transform not working in JavaScript rotation animation(no JQuery)

I made a animation function for a simple game I am making, the animation rotates some text 360degrees 4 times, to give it the appearance that the text is spinning. I looked for similar issues to the one I'm experiencing, but the suggestions did not solve my problem. The animation method is part of my view-object:
rotateText : function(deg, message) {
this.gameState.innerHTML = message;
var animationStepsLeft = this.STEPS;
requestAnimationFrame(setStyle);
function setStyle() {
if(animationStepsLeft > 0) {
Perfection.view.gameState.style =
"-ms-transform: rotate(" + deg + "deg);" +
"-webkit-transform: rotate(" + deg + "deg);" +
"-moz-tranfsform: rotate(" + deg + "deg);" +
"transform: rotate(" + deg + "deg);";
deg += 28.8;
console.log("Rotated");
animationStepsLeft--;
requestAnimationFrame(setStyle);
};
};
},
The "gameState" is a paragraph element in HTML, which is a property of the view object. The method is supposed to take a starting point for the degrees (0) and the message you want to spin - is passed as a string. The amount of steps it's executing is 50, and each time the animation is called the text is rotated 28.8 degrees. My issue is that the animation works flawlessly in Firefox but does not seem to work in webkit based browsers (It's not working in Chrome or Safari). I should mention that the method is being called, as I've attached a console.log in the attempt to debug, and it's being logged 50 times, and the text appears on the screen, but does not rotate. I read in a similar post that in webkit browsers the elements need to be displayed as an inline-block, so I had my CSS styles set as:
#game-state {
display: inline-block;
position: absolute;
margin-left: auto;
margin-right: auto;
margin-top: 200px;
z-index: 2;
font-family: "Tahoma", Geneva, sans-serif;
text-shadow: -3px 0 black, 0 3px black, 3px 0 black, 0 -3px black;
font-size: 100px;
color: rgb(213,40,8);
}
But it is still not working!
Can anyone help me pls!
I suggest that you should open console and see what inside element.style. Style is a set of properties. EG: style.height, style.visible... not style="".
You should change your code to <element>.style.transform='rotate(' + deg + 'deg)'. For -ms-transform you can try to use .style['-ms-transform'].
Using raw javascript then you must detect your browser for supported style.

How to dynamically create '#-Keyframe' CSS animations?

I have a requirement to rotate a div and stop at a particular position ( The value will be received from the server).
I tried native JS to rotate and stop but it is eating up my CPU big time.
I can rotate with CSS animation but I need to create a class which will dynamically describe where to stop the animation. Something like
#-webkit-keyframes spinIt {
100% {
-webkit-transform: rotate(A_DYNAMIC_VALUE);
}
}
#-moz-keyframes spinIt {
100% {
-webkit-transform: rotate(A_DYNAMIC_VALUE);
}
}
Here is one reference
http://jsfiddle.net/bVkwH/8/
You can insert stylesheet rules dynamically to override previous styles in the head. This helps avoid adding yet another library for a single task.
var style = document.createElement('style');
style.type = 'text/css';
var keyFrames = '\
#-webkit-keyframes spinIt {\
100% {\
-webkit-transform: rotate(A_DYNAMIC_VALUE);\
}\
}\
#-moz-keyframes spinIt {\
100% {\
-webkit-transform: rotate(A_DYNAMIC_VALUE);\
}\
}';
style.innerHTML = keyFrames.replace(/A_DYNAMIC_VALUE/g, "180deg");
document.getElementsByTagName('head')[0].appendChild(style);
well i don't think it is easy to create dynamic #keyframes they are inflexible because they must be hard-coded.
Transitions are a little easier to work with, as they can gracefully respond to any CSS changes performed by JavaScript.
However, the complexity that CSS transitions can give you is pretty limited — an animation with multiple steps is difficult to achieve.
This is a problem that CSS #keyframe animations are meant to solve, but they don’t offer the level of dynamic responsiveness that transitions do.
but these links might help you
Link1 : a tool that generates a #-webkit-keyframe animation with many tiny steps. This opens the door to an unlimited selection of easing formula.
Link2 it will be a great help for you to take it as a base as it provides a UI to create animations and exports it to CSS code.
I guess this solution will definitely work for you. Its is used for dynamic keyframes
Let me share an updated (2019) answer to this.
Yes, it's possible without Javascript using CSS Variables (supported by all modern browsers).
--lightScaleStart: 0.8;
.light {
animation: grow 2s alternate infinite ease-in-out;
}
.light.yellow {
--lightScaleEnd: 1.1;
}
.light.red {
--lightScaleEnd: 1.2;
}
#keyframes grow {
from {
transform: scale(var(--lightScaleStart));
}
to {
transform: scale(var(--lightScaleEnd));
}
}
See demo on Codepen Dynamic CSS Animations with CSS Variables
Edit: Here's a CSS Tricks article about it too.
Alex Grande's answer works GREAT for a few keyframes. But, say you want to dynamically keep adding in keyframes over and over again, then your webpage get really laggy really quick. To solve this problem, just STOP creating new DOM elements. Rather, create 1 new DOM stylesheet, and just reuse it with the insertRule. If you want even more keyframes (like if you're generating a new keyframe every animationframe), then you need to set up a system which deletes old keyframes after they're no longer used. This is a good start to how something like this can be achieved.
var myReuseableStylesheet = document.createElement('style'),
addKeyFrames = null;
document.head.appendChild( myReuseableStylesheet );
if (CSS && CSS.supports && CSS.supports('animation: name')){
// we can safely assume that the browser supports unprefixed version.
addKeyFrames = function(name, frames){
var pos = myReuseableStylesheet.length;
myReuseableStylesheet.insertRule(
"#keyframes " + name + "{" + frames + "}", pos);
}
} else {
addKeyFrames = function(name, frames){
// Ugly and terrible, but users with this terrible of a browser
// *cough* IE *cough* don't deserve a fast site
var str = name + "{" + frames + "}",
pos = myReuseableStylesheet.length;
myReuseableStylesheet.insertRule("#-webkit-keyframes " + str, pos);
myReuseableStylesheet.insertRule("#keyframes " + str, pos+1);
}
}
Example usage:
addKeyFrames(
'fadeAnimation',
'0%{opacity:0}' +
'100%{opacity:1}'
);
Also, Alex Grande, I am pretty sure that document.getElementsByTagName('head')[0] and type = 'text/css' hasn't been needed since IE8, and #keyframes aren't supported till IE10. Just saying...
This is now easily achievable with the new Web Animations API, which looks like this:
const anim = document.getElementById("foo").animate(
[
{ transform: `rotate(${A_DYNAMIC_VALUE})` }
],
{ duration: 3000, iterations: Infinity }
);
// and later
anim.pause();
The first argument to .animate takes a list of keyframes, and the second takes the animation options (e.g. duration, how many times it repeats, etc).
You can change the style in CSSKeyframeRule, and this works fine for me in Chrome, just as the code below.
Hope this will help:)
<html>
<head>
<style>
#text {
display: inline-block;
}
</style>
</head>
<body>
<div id="text">TEXT</div>
<script>
// Dynamically create a keyframe animation
document.styleSheets[0].insertRule('\
#keyframes anim {\
from { transform: rotateZ(0deg); }\
to { transform: rotateZ(360deg); }\
}'
);
var div = document.getElementById('text');
div.style.animation = 'anim 1s linear forwards';
// This function will change the anim
function stopAtSomeDeg(d) {
var ss = document.styleSheets[0];
var anim;
for (var i in ss.cssRules) {
// Find your animation by name
if (ss.cssRules[i].name === 'anim') {
anim = ss.cssRules[i];
break;
}
}
var stopFrame = anim.cssRules[1]; // This indicates the second line of "anim" above.
// Change any attributes
stopFrame.style.transform = 'rotateZ(' + d + 'deg)';
}
stopAtSomeDeg(180);
</script>
</body>
</html>
With CSS variables: You can use the pseudo :root of the element to declare a css variable within the css rules, then manipulate that variable using Javascript.
:root {--variable-name:property;} which is basically the root element of the document <html>. Then change the value of the CSS root variable/s using JS with:
element.style.setProperty('--variable-name','value'). Pass the declared root variable --variable-name as the name and assign the new value. Then in your #keyframes css rules, add the root variable name, like: from: { top: var(--top-position)}, to the property within the offset #keyframe rule. Example:
:root {
--top-position-start: 0px;
--left-position-start: 0px;
--top-position-end: 200px;
--left-position-end: 200px;
}
.element {
top: var(--top-position-start);
left: var(--left-position-start);
animation: movePos 1s ease-in;
}
#keyframes movePos {
from: {
top: var(--top-position-start);
left: var(--left-position-start);
}
to: {
top: var(--top-position-end);
left: var(--left-position-end);
}
}
Then the JS would like something like:
let ran = getRandomInt(99);
let skew = ran + getRandomInt(10);
root.style.setProperty('--top-position-end', `${ran}vw`);
root.style.setProperty('--left-position-end', `${skew}vw`);
By using the CSS variable on the root element, you are able to pass it along to the #keyframes event.
See the following working example using randomly placed div using CSS left and background-color:rgb()(red, green, blue) passed using the html:root style to #keyframes within CSS.
let root = document.documentElement;
let rain = document.querySelectorAll('.drop');
function getMaxInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function getMinMaxInt(min, max) {
return Math.random() * (max - min) + min;
}
// set an interval to drop the div from randomly positioned view widths on the screen
setInterval(() => {
let ran = getMaxInt(86);
let skew = ran + getMaxInt(10);
let circle = `${getMinMaxInt(3,15)}px`;
root.style.setProperty('--keyframeLeftStart', `${ran}vw`);
root.style.setProperty('--keyframeLeftEnd', `${skew}vw`);
root.style.setProperty('--animationDuration', `${ getMaxInt(2500)}ms`);
root.style.setProperty('--width', circle);
root.style.setProperty('--height', circle);
root.style.setProperty('--red', getMinMaxInt(100, 255));
root.style.setProperty('--green', getMinMaxInt(100, 255));
root.style.setProperty('--blue', getMinMaxInt(100, 255));
}, getMaxInt(3500))
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
/* here we define some css variables for the document :root
essentially, these will be the first iteration of the elements style
then JS will take voer and set the values from script */
:root {
--keyframeTop: 0;
--keyframeBottom: 98vh;
--keyframeLeftStart: 2vw;
--keyframeLeftEnd: 10vw;
--animationDuration: 1s;
--width: 5px;
--height: 5px;
--red: 100;
--green: 100;
--blue: 100;
}
body {
width: 100vw;
height: 100vh;
background-color: #000;
}
#main {
width: calc(100vw - var(--width));
height: calc(100vh - var(--height));
display: flex;
justify-content: center;
align-items: center;
color: #fff;
}
.drop {
width: var(--width);
height: var(--height);
border-radius: 50%;
position: absolute;
animation: dropping var(--animationDuration) ease-in infinite;
top: var(--keyframeTop);
left: var(--keyframeLeftStart);
background-color: rgb(var(--red),var(--green), var(--blue));
}
#keyframes dropping {
0% {
top: var(--keyframeTop);
left: var(--keyframeLeftStart);
background-color: rgb(var(--red),var(--green), var(--blue));
}
50% {
background-color: rgb(var(--green),var(--blue), var(--red));
}
100% {
top: var(--keyframeBottom);
left: var(--keyframeLeftEnd);
background-color: rgb(var(--blue),var(--red), var(--green));
}
}
<div id="main">
<div class="drop"></div>
</div>
In JavaScript is it possible to access to the style sheet with document.styleSheets. Every sheet has a rule and/or cssRule list (browser depending) and a CSSStyleSheet.insertRule() method.
This method allows you to add a new keyframe raw as a string:
JavaScript
function insertStyleSheetRule(ruleText)
{
let sheets = document.styleSheets;
if(sheets.length == 0)
{
let style = document.createElement('style');
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
}
let sheet = sheets[sheets.length - 1];
sheet.insertRule(ruleText, sheet.rules ? sheet.rules.length : sheet.cssRules.length);
}
document.addEventListener("DOMContentLoaded", event =>
{
insertStyleSheetRule("#keyframes spinIt { 0% { transform: rotate(-20deg); } 100% { transform: rotate(20deg); } }");
insertStyleSheetRule("#box { " +
"animation: spinIt 1s infinite alternate cubic-bezier(0.5,0,0.5,1); " +
"width: 64px; height: 64px; background-color: red; border: 4px solid black; " +
"}");
});
html
<div id="box"></div>
demo: https://jsfiddle.net/axd7nteu/
You could create a new stylesheet with the animation you want in it.
For Example:
function addAnimation(keyframe){
var ss=document.createElement('style');
ss.innerText=keyframe;
document.head.appendChild(ss);
}
This would create a new stylesheet with your animation.
This method has only been tested in Chrome.
Setting a #keyframe in one call with JavaScript, and use it, using append(), Object.assign(), and template strings.
document.body.append(
Object.assign(document.createElement("style"), {
textContent: `#keyframes coolrotate { from { transform: scale(1, 1) translate(-0.1em, 0)} to { transform: scale(-1, 1) translate(0, 0) }} small { display: inline-block; font-size:2.3em; animation: 1s infinite alternate coolrotate } body {font-size: x-large}`
}),
Object.assign(document.createElement("span"), {
innerHTML: `<span>c</span><small>o</small><span>o</span><small>L</small><small>...</small>`,
style: "font-weight: 1000; font-size: 3.3em;"
})
)
the user7892745 wont work for me, need some little adjustement
1° "pos" not understand wot should be, but the console log say "undefined"
so I've remove " , pos"
2° " myReuseableStylesheet.insertRule" give me error " is not a function"
so I used "innerHTML" insted of "insertRule"
3° finally I've moved "
document.head.appendChild( myReuseableStylesheet );" at the end
but after this it work fine and it's exact what I looking for.
thanks a lot user7892745 :D
maybe the problem I had, come form the way I use it
this is the script i used with it
var getclass = document.getElementsByClassName("cls");
var countclass = getclass.length;
for (var i=0; i <countclass; i++ ){
getclass[i].addEventListener('mouseover', function(){
// get the data-name value to show element whose id are the same
var x= this.getAttribute("data-name");
var y =document.getElementById(x);
y.style.display="block";
// because the element to show have fixed width, but different text length, they have different height
// so I need to get the highness, then use the value of height to define the 100% value of animation
// or the longer ones will be cutted an the shorten have a lot of empty space a the end
var yHeig= Math.round(parseInt(getComputedStyle(y).getPropertyValue('height')));
yHeig_ = yHeig - 10; // to shorten a bit the time from end and new passage
console.log(yHeig+" - "+ yHeig_);
addKeyFrames(
'showMe',
'0%{top:35px;}' +
'100%{top:-'+ yHeig_ +'px;}'
);
y.style.animation="showMe 7s linear infinite";
},false);
getclass[i].addEventListener('mouseout', function(){
var x= this.getAttribute("data-name");
document.getElementById(x).style.display="none";
},false);
}
i know thath a html marquee cuold seem symple to do the same thing, but dont work well,
You can create a <style> element, set its content to the CSS you want, in this case, the declaration of your animation and add it to the <head> of the page.
Also, as others have suggested, if you need to create many different animations, then it would be better to reuse a single <style> tag rather than creating multiple of them and add the new styles using CSSStyleSheet.insertRule().
Lastly, if you can use ES6's template literals/strings, your code will look much cleaner:
let dynamicStyles = null;
function addAnimation(body) {
if (!dynamicStyles) {
dynamicStyles = document.createElement('style');
dynamicStyles.type = 'text/css';
document.head.appendChild(dynamicStyles);
}
dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
}
addAnimation(`
#keyframes myAnimation {
0% { transform: rotate(0); }
20% { transform: rotate(${ 360 * Math.random() }deg); }
60% { transform: rotate(${ -360 * Math.random() }deg); }
90% { transform: rotate(${ 360 * Math.random() }deg); }
100% { transform: rotate(${ 0 }deg); }
}
`);
document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
height: 100vh;
}
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
}
#circle {
width: 100px;
height: 100px;
box-shadow:
0 0 48px -4px rgba(0, 0, 0, .25),
0 0 0 4px rgba(0, 0, 0, .02);
border-radius: 100%;
position: relative;
overflow: hidden;
}
#circle::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translate(-2px);
border-left: 4px solid #FFF;
height: 24px;
box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>
Or even better:
let dynamicStyles = null;
function addAnimation(name, body) {
if (!dynamicStyles) {
dynamicStyles = document.createElement('style');
dynamicStyles.type = 'text/css';
document.head.appendChild(dynamicStyles);
}
dynamicStyles.sheet.insertRule(`#keyframes ${ name } {
${ body }
}`, dynamicStyles.length);
}
addAnimation('myAnimation', `
0% { transform: rotate(0); }
20% { transform: rotate(${ 360 * Math.random() }deg); }
60% { transform: rotate(${ -360 * Math.random() }deg); }
90% { transform: rotate(${ 360 * Math.random() }deg); }
100% { transform: rotate(${ 0 }deg); }
`);
document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
height: 100vh;
}
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
}
#circle {
width: 100px;
height: 100px;
box-shadow:
0 0 48px -4px rgba(0, 0, 0, .25),
0 0 0 4px rgba(0, 0, 0, .02);
border-radius: 100%;
position: relative;
overflow: hidden;
}
#circle::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translate(-2px);
border-left: 4px solid #FFF;
height: 24px;
box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>
Found a simple idea with JavaScript by using CSS data URI.
Solution
function addNewCSS(css_text) {
css_text = encodeURIComponent(css_text);
const url = `data:text/css,${css_text}`;
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = url;
document.head.appendChild(link);
}
Function accepts CSS code as text and adds it as a style.
Working
Converts the CSS text to URI encoded form (for passing as data URL). Then creates a link tag with href as the url and relation as "stylesheet" (here rel attribute is required and won't work if not added) Finally appends the link tag to head tag.
Example
function addNewCSS(css_text) {
css_text = encodeURIComponent(css_text);
const url = `data:text/css,${css_text}`;
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = url;
document.head.appendChild(link);
}
const duration = 1;
const colour = ["#2196F3", "#E91E63"];
const css_data = `
#keyframes change{
0% {
background: ${colour[0]};
}
100% {
background: ${colour[1]};
}
}
body {
animation: change ${duration}s linear infinite alternate;
}
`;
addNewCSS(css_data);
<html>
<head></head>
<body>
<h1>Wait to see JS adding background color animation</h1>
</body>
</html>
Conclusion
I haven't tested on all browsers, but works in chrome, and as it is added to the end of head tag it get priority from other tags in head, If you are planning to change values frequently, instead of adding new tags, try to edit the href of previously added tags.

Categories