I have this stylesheet:
#-webkit-keyframes run {
0% {
-webkit-transform: translate3d(0px, 0px, 0px);
}
100% {
-webkit-transform: translate3d(0px, 1620px, 0px);
}
}
Now, I would like to modify the value of 1620px depending on some parameters. Like this:
#-webkit-keyframes run {
0% {
-webkit-transform: translate3d(0px, 0px, 0px);
}
100% {
-webkit-transform: translate3d(0px, height*i, 0px);
}
}
I would prefer to be able to use JavaScript and jQuery, though a pure CSS solution would be ok.
This is for an iPhone game that runs in it's mobile Apple Safari browser.
Use the CSSOM
var style = document.documentElement.appendChild(document.createElement("style")),
rule = " run {\
0% {\
-webkit-transform: translate3d(0, 0, 0); }\
transform: translate3d(0, 0, 0); }\
}\
100% {\
-webkit-transform: translate3d(0, " + your_value_here + "px, 0);\
transform: translate3d(0, " + your_value_here + "px, 0);\
}\
}";
if (CSSRule.KEYFRAMES_RULE) { // W3C
style.sheet.insertRule("#keyframes" + rule, 0);
} else if (CSSRule.WEBKIT_KEYFRAMES_RULE) { // WebKit
style.sheet.insertRule("#-webkit-keyframes" + rule, 0);
}
If you want to modify a keyframe rule in a stylesheet that's already included, do the following:
var
stylesheet = document.styleSheets[0] // replace 0 with the number of the stylesheet that you want to modify
, rules = stylesheet.rules
, i = rules.length
, keyframes
, keyframe
;
while (i--) {
keyframes = rules.item(i);
if (
(
keyframes.type === keyframes.KEYFRAMES_RULE
|| keyframes.type === keyframes.WEBKIT_KEYFRAMES_RULE
)
&& keyframes.name === "run"
) {
rules = keyframes.cssRules;
i = rules.length;
while (i--) {
keyframe = rules.item(i);
if (
(
keyframe.type === keyframe.KEYFRAME_RULE
|| keyframe.type === keyframe.WEBKIT_KEYFRAME_RULE
)
&& keyframe.keyText === "100%"
) {
keyframe.style.webkitTransform =
keyframe.style.transform =
"translate3d(0, " + your_value_here + "px, 0)";
break;
}
}
break;
}
}
If you don't know the order but do know the URL of the CSS file, replace document.styleSheets[0] with document.querySelector("link[href='your-css-url.css']").sheet.
Have you tried declaring the keyframe portion of your css in a <style> element in the head of your html document. You can then give this element an id or whatever and change it's content whenever you like with javaScript. Something like this:
<style id="keyframes">
#-webkit-keyframes run {
0% { -webkit-transform: translate3d(0px,0px,0px); }
100% { -webkit-transform: translate3d(0px, 1620px, 0px); }
}
</style>
Then your jquery can change this as normal:
$('#keyframes').text('whatever new values you want in here');
Well from your example it seems to me that CSS animations may be overkill. Use transitions instead:
-webkit-transition: -webkit-transform .4s linear; /* you could also use 'all' instead of '-webkit-transform' */
and then apply a new transform to the element via js:
$("<yournode>")[0].style.webkitTransform = "translate3d(0px,"+ (height*i) +"px,0px)";
It should animate that.
I didn't get when you wanted to modify these values (i.e. use variables) but nevertheless here are 3 to 4 solutions and 1 impossible solution (for now).
server-side calculation: in order to serve a different CSS from time to time, you can tell PHP or any server-side language to parse .css files as well as .php or .html and then use PHP variables in-between PHP tags. Beware of file caching: to avoid it, you can load a stylesheet like style.css?1234567890random-or-time it will produce an apparent different file and thus won't be cached
SASS is also a server-side solution that needs Ruby and will provide you an existing syntax, probably cleaner than a hand-made solution as others have already about problems and solutions
LESS is a client-side solution that will load your .less file and a less.js file that will parse the former and provide you variables in CSS whatever your server is. It can also work server-side with node.js
CSS being dynamically modified while your page is displayed?
For 2D there are jquery-animate-enhanced from Ben Barnett, 2d-transform or CSS3 rotate are pitched the other way around (they use CSS3 where possible and where there are no such functions, they fallback to existing jQuery .animate() and IE matrix filter) but that's it.
You could create a plugin for jQuery that would manage with a few parameters what you want to achieve with 3D Transformation and avoid the hassle of modifying long and complex CSS rules in the DOM
CSS only: you could use -moz-calc [1][2] that works only in Firefox 4.0 with -webkit-transform that works only in ... OK nevermind :-)
Try something like this:
var height = {whatever height setting you want to detect};
element.style.webkitTransform = "translate3d(0px," + height*i + ",0px)";
A 'Chunky' solution?
Create transforms for heights within your chosen granularity, say 0-99, 100-199, 200-299, etc. Each with a unique animation name identifier like:
#-webkit-keyframes run100 {
0% { -webkit-transform: translate3d(0px,0px,0px); }
100% { -webkit-transform: translate3d(0px,100px,0px); }
}
#-webkit-keyframes run200 {
0% { -webkit-transform: translate3d(0px,0px,0px); }
100% { -webkit-transform: translate3d(0px,200px,0px); }
}
then create matching css classes:
.height-100 div {
-webkit-animation-name: run100;
}
.height-200 div {
-webkit-animation-name: run200;
}
then with javascript decide which chunk you're in and assign the appropriate class to the surrounding element.
$('#frame').attr('class', '').addClass('height-100');
Might be ok if the granularity doesn't get too fine!
I used warmanp's solution and it worked, but with a bit of very important tweaking.
$('#ticket-marquee-css').text(
"#-webkit-keyframes marqueeR{ 0%{text-indent: -" + distanceToMove + "px;} 100%{text-indent: 0;} }" +
"#-webkit-keyframes marqueeL{ 0%{text-indent: 0;} 100%{text-indent: -" + distanceToMove + "px;} }"
);
In order to get the CSS transition to update, instead of using the previously-defined values, I had to make the animation stop, then restart. To do this, I placed a class of "active" on the elements, and made the CSS only apply the transition to the elements that had that class
#marquee1.active {-webkit-animation-name: marqueeL;}
#marquee2.active {-webkit-animation-name: marqueeR;}
Then I just had to toggle the "active" class off, wait for it to apply in the DOM (hence the setTimeout), then reapply it.
$('.ticket-marquee').removeClass('active');
setTimeout(function() { $('.ticket-marquee').addClass('active'); },1);
And that works great! Now I can dynamically change the distance the text moves!
Related
I am using transition(0.3s) in CSS when hover some texts for changing the color, but I also used transition in Javascript for "translate" the text. My problem now is that, when I hover them, they don't use anymore the transition in CSS (0.3s) but what I set in javascript. I tried using element.style.transition = "translate 5.4s ease" or in css I set delay for specific property but in vain.How can i set the transition in Js only for translate? Thank you in advance
CSS
social-media-texts p {
position:relative;
color:white;
font-size:20px;
transition: opacity 0.3s;
transform: translate(-300%);
opacity: 0;
}
JavaScript
socialTexts.forEach((element) => {
element.style.opacity = "1";
element.style.transform = "translate(0)";
element.style.transition = 1.1 * countP + "s";
countP += 0.3;
});
It is because you are overwriting the previous transition property. You would need to expand it by adding a comma followed by your new transition (eg. transform 1.1s)
That would result in the following property: transition: opacity 0.3s, transform: 1.1s;
See section Change Several Property Values: https://www.w3schools.com/css/css3_transitions.asp
I am creating an object which has 2 properties:
animationName - an array with the names of pre-made #keyfame animations
&
animate - a function which accepts a target, animation name, duration and timing function
I have the animate function checking that atleast one of the selected
targets exist and I am also making sure that the animation name
matches one of the indexes in animationName.
If I manually enter the style attribute and animation information, it works as I would expect, however, I cannot seem to get the code to work in the JS!
I have tried different things such as .prop() but I am pretty sure .attr() is right.
Here is the JS:
var animateElement = {
//put in our animations that we know exist
animationName: ["bounce", "shake"],
//set up an animate renderer
animate: function(target, animationName, duration, timingFunction) {
//cache the known animations in an easy to use variable
var selectedAnim = this.animationName;
//query the target to make sure it exists
var el = document.querySelectorAll(target);
//make sure atleast one of the targets exist
if (el.length != -1) {
//check if the parameter animation is equal to one of our available animations
if ($.inArray(animationName, selectedAnim) != -1) {
//if the animation exists, change the style attribute of the target element to run the animation
el.attr("style", "animation:" + animationName + " " + duration + " " + timingFunction);
} else {
//otherwise alert that the selected animation is invalid (doesn't match our array of known animations)
alert("invalid animation selected");
}
}
},
}
animateElement.animate("button", "shake", "0.25s", "infinite");
SASS:
#-webkit-keyframes shake
0%
transform: translateX(0)
25%
transform: translateX(-25px)
50%
transform: translateX(0)
75%
transform: translateX(25px)
100%
transform: translateX(0)
#keyframes shake
0%
transform: translateX(0)
25%
transform: translateX(-25px)
50%
transform: translateX(0)
75%
transform: translateX(25px)
100%
transform: translateX(0)
#-webkit-keyframes bounce
0%
transform: translateY(0)
25%
transform: translateY(-25px)
50%
transform: translateY(0)
75%
transform: translateY(25px)
100%
transform: translateY(0)
#keyframes bounce
0%
transform: translateY(0)
25%
transform: translateY(-25px)
50%
transform: translateY(0)
75%
transform: translateY(25px)
100%
transform: translateY(0)
There are two issues with your code which is preventing it from working properly and they are as follows:
document.querySelectorAll returns a nodelist and so you can't directly set attributes. You either have to loop through the returned nodes (or) assign the attributes to one single item in the node list using [x].
.attr() is a jQuery method but the el is not a jQuery object. You need to use the vanilla JS equivalent which is .setAttribute.
If you want to test by applying the animation property (through style attribute) for one node then use the below code and it will apply the property to only the first node returned.
el[0].setAttribute("style", "-webkit-animation:" + animationName + " " + duration + " " + timingFunction);
For your actual scenario, traverse through all nodes returned by using a for loop like below and then assign the animation property:
for (var i = 0; i < el.length; i++) {
el[i].setAttribute("style", "animation:" + animationName + " " + duration + " " + timingFunction);
}
Below is a sample snippet with a random animation effect added. I had included the prefix library in the snippet only for supporting the older browsers (I am using one :D).
var animateElement = {
//put in our animations that we know exist
animationName: ["bounce", "shake"],
//set up an animate renderer
animate: function(target, animationName, duration, timingFunction) {
//cache the known animations in an easy to use variable
var selectedAnim = this.animationName;
//query the target to make sure it exists
var el = document.querySelectorAll(target);
//make sure atleast one of the targets exist
if (el.length != -1) {
//check if the parameter animation is equal to one of our available animations
if ($.inArray(animationName, selectedAnim) != -1) {
//if the animation exists, change the style attribute of the target element to run the animation
el[0].setAttribute("style", "animation:" + animationName + " " + duration + " " + timingFunction);
} else {
//otherwise alert that the selected animation is invalid (doesn't match our array of known animations)
alert("invalid animation selected");
}
}
},
}
animateElement.animate("div", "shake", "0.25s", "infinite");
#keyframes shake {
from {
transform: translateX(200px);
}
to {
transform: translateX(0px);
}
}
div {
height: 200px;
width: 200px;
border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Some content</div>
I am trying to use the following code to rotate a website but am a bit of a beginner in javascript and have come a bit stuck...
func roatation {
body {
-webkit-transform: rotate(-30deg);
-moz-transform: rotate(-30deg);
}
}
I know the code for body was html? But can't work out how I would put this in a function?
Thanks
You can do this:
CSS
body.rotate {
-webkit-transform: rotate(-30deg);
-moz-transform: rotate(-30deg);
}
JS
function rotate() {
document.body.className = "rotate"; // apply .rotate class
}
rotate();
By moving the rotation definition to a class you can apply and remove the rotation by setting the class property of the body.
I need to adjust the transition time for a HTML5 <progress>-Bar with JS (jQuery) but I cannot find the right selector in jQuery doing this.
My current tries:
CSS:
progress::-webkit-progress-value {
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
-o-transition: all 0.5s;
-ms-transition: all 0.5s;
transition: all 0.5s; /* Works like a charm */
}
JavaScript (with no success):
// These lines do nothing when the progress value changes:
$(".progressSelectorClass[progress-value]").css({"-webkit-transition" : "all 6s"});
$(".progressSelectorClass > *").css({"-webkit-transition" : "all 6s"});
$(".progressSelectorClass").css({"-webkit-transition" : "all 6s"});
// This gets an error:
$(".progressSelectorClass::-webkit-progress-value").css({"-webkit-transition" : "all 6s"});
Is there any chance to select the progress::-webkit-progress-value in JavaScript (with or without jQuery)?
In this jsFiddle you will see more clearly what I try to do:
http://jsfiddle.net/rD5Mc/1/
Update:
I got the effect with an ugly workaround by adding/change a data-animation-time parameter to the <progress>-element and created several css-classes like this:
progress[data-animation-time="5"]::-webkit-progress-value { -webkit-transition: all 5s; }
progress[data-animation-time="10"]::-webkit-progress-value { -webkit-transition: all 10s; }
progress[data-animation-time="15"]::-webkit-progress-value { -webkit-transition: all 15s; }
progress[data-animation-time="20"]::-webkit-progress-value { -webkit-transition: all 20s; }
progress[data-animation-time="25"]::-webkit-progress-value { -webkit-transition: all 25s; }
...
It works, but I'm very unhappy with my solution. There must be a better way...
You can use the javascript to modify the css rules!
var rule;
$(".animationtimeFirst").change(function() {
time = $(this).val();
// Write out out full CSS selector + declaration
s = '.progressselector::-webkit-progress-value { -webkit-transition: all ' + time + 's; }';
// Check the rules
// If there's no rules,
if ((!rule && rule !== 0) || !document.styleSheets[0].cssRules.length) {
// Make one! -- Insert our CSS string into the page stylesheet
rule = document.styleSheets[0].insertRule(s, 0);
// I think this code is different in IE, beware!
console.log('Our rule is #' + rule);
} else {
// If we already have a rule we can change the style we've implement for the psuedo class
document.styleSheets[0].rules[rule].style.webkitTransitionDuration = time.toString() + 's';
}
});
Here's an updated fiddle: http://jsfiddle.net/trolleymusic/MHYY8/3/ -- hope it helps :)
progress::-webkit-progress-value is not a DOM-Element (it's part of the Shadow DOM, though). So you cannot acccess it with jQuery or any DOM method.
It all comes down to a workaround like yours.
EDIT:
It turns out that in recent versions of Chrome you actually can access the Shadow DOM with the webkitShadowRoot property. Unfortunately it does not work for the <progress /> element.
I have two keyframe animations "Bounce-In" and "Bounce-Out" the Bounce-In animation takes 1.2 seconds to complete, but if a user triggers the Bounce-Out function before it's finished it will jump to 100% scale and doesn't gracefully scale out from it's current animation position.
Is this possible with keyframe animations? I've seen it done with transition property but not using scale().
#-webkit-keyframes Bounce-In
{
0% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
60% { -webkit-transform: scale(0.7) }
80% { -webkit-transform: scale(1.0) }
90% { -webkit-transform: scale(0.9) }
100% { -webkit-transform: scale(1.0) }
}
#-webkit-keyframes Bounce-Out
{
0% { -webkit-transform: scale(1.0) }
40% { -webkit-transform: scale(0.1) }
60% { -webkit-transform: scale(0.4) }
80% { -webkit-transform: scale(0.1) }
90% { -webkit-transform: scale(0.2) }
100% { -webkit-transform: scale(0) }
}
I have a demo on JSFiddle: http://jsfiddle.net/Vn3bM/98/
*if you click the "Games" circle before the animation is finished you will notice the other two jump to 100% and then animate out (that's what I'm trying to make smooth).
I even tried removing the 0% keyframe from Bounce-Out and that didn't help...
In your case, the "jump" you notice in your animation comes from the change of animations you have installed on onmouseup. The "Bounce-Out" Animation has an initial scale of 1 (first Keyframe), and this is what the two circles immediately get set to when the animation is installed.
There are two solutions to this, which I can explain in some detail:
The Easy Way
You could just wait for the initial animation to end via the 'webkitAnimationEnd' Event and install the onmouseup event with a recursive function waiting for the animation to finish:
var initAnimationEnded = false;
document.getElementById('sports').addEventListener('webkitAnimationEnd', function() {
initAnimationEnded = true;
}, false);
And here's the onmouseup handler:
document.getElementById('games').onmouseup = function() {
function bounceOut() {
if (initAnimationEnded) {
events.style.webkitAnimationName = "Bounce-Out";
sports.style.webkitAnimationDelay = "0.2s";
sports.style.webkitAnimationName = "Bounce-Out";
} else {
setTimeout(bounceOut, 20);
}
}
bounceOut();
}
I installed a jsfiddle here so you can see it working. The Bounce Out animation is only triggered after the animation finished, nothing unusual about that.
The Hard Way
You can pause the animation and parse the current values of the transformation, then install a temporary keyframe animation to bounce out. This gets much more verbose though:
First, you have to stop the animations:
events.style.webkitAnimationPlayState = "paused";
sports.style.webkitAnimationPlayState = "paused";
Then, you set up a helper to insert new css rules:
var addCssRule = function(rule) {
var style = document.createElement('style');
style.innerHTML = rule;
document.head.appendChild(style);
}
Then create the css keyframe rules on the fly and insert them:
// get the current transform scale of sports and events
function getCurrentScaleValue(elem) {
return document.defaultView.
getComputedStyle(elem, null).
getPropertyValue('-webkit-transform').
match(/matrix\(([\d.]+)/)[1];
}
var currentSportsScale = getCurrentScaleValue(sports);
var currentEventsScale = getCurrentScaleValue(events);
// set up the first string for the keyframes rule
var sportsTempAnimation = ['#-webkit-keyframes Sports-Temp-Bounce-Out {'];
var eventsTempAnimation = ['#-webkit-keyframes Events-Temp-Bounce-Out {'];
// basic bounce out animation
var bounceOutAnimationBase = {
'0%': 1,
'40%': 0.1,
'60%': 0.4,
'80%': 0.1,
'90%': 0.2,
'100%': 0
};
// scale the animation to the current values
for (prop in bounceOutAnimationBase) {
sportsTempAnimation.push([
prop, '
{ -webkit-transform: scale(',
currentSportsScale * bounceOutAnimationBase[prop],
') } '].join(''));
eventsTempAnimation.push([
prop,
' { -webkit-transform: scale(',
currentEventsScale * bounceOutAnimationBase[prop],
') } '
].join(''));
}
// add closing brackets
sportsTempAnimation.push('}');
eventsTempAnimation.push('}');
// add the animations to the rules
addCssRule([sportsTempAnimation.join(''),
eventsTempAnimation.join('')].join(' '));
Then, you restart the animations with these rules:
events.style.webkitAnimationName = "Events-Temp-Bounce-Out";
events.style.webkitAnimationDelay = "0s";
sports.style.webkitAnimationDelay = "0s";
sports.style.webkitAnimationName = "Sports-Temp-Bounce-Out";
events.style.webkitAnimationPlayState = "running";
sports.style.webkitAnimationPlayState = "running";
Et voilà. I made a jsfiddle here so you can play around with it.
More Sugar
In your example, the circles bounce out alternating in bounce. You can easily get this back to work with the second solution by using setTimeout for all sports circle animations. I did not want to include it here because it would unnecessarily complicate the example code.
I know the provided examples are not really DRY, you could for example make all the stuff for events and sports work with half the lines of code (with meta properties), but in terms of readability, I think this example serves well.
To have this example working in all browsers with support for css3 animations, you need to normalize the transition properties. To do this in javascript, have a look here The Example works for animations and other properties as well, just replace 'transition' with the property you want
For a further read on modifying css3 animations on the fly, I found this post very useful, have a look at it as well.