Scenario : Using pure Javascript only (no libraries), I need to increment (or decrement) the background colour opacity of an HTML element without affecting the opacity of any child element. The new opacity can be anywhere in the range of fully opaque to fully transparent. Support for browsers prior to IE9 is not required hence the chosen method to accomplish this is by using background-color property from getComputedStyle. I have only seen this return a string in two formats (using pure white as an example) :
rgba(255, 255, 255, 0.5) when opacity is applied.
rgb(255, 255, 255) when fully opaque - it changes to this format when opacity is 1.
I need to reset the background colour in the format, rgba(255, 255, 255, 0.5)
Code fragment :
myBG = window.getComputedStyle( myElement, null ).getPropertyValue( "background-color" );
myElement.style.backgroundColor = myBG.replace( /(.*)\((\s*\d+)\,(\s*\d+)\,(\s*\d+)(?:\,|\))(.*)/ , 'rgba( $2, $3, $4, ' + myNewOpacity.toString() + ' )' );
This works in the limited testing I have conducted - However :
Question 1. I am a beginner to Javascript and web development. Will I get any return formats that do not match the two above (cross browser compatibility issue) ?
Question 2. I am a complete novice to regular expressions. My solution seems heavy and/or inelegant. Is there a better regular expression I can use ? Is there a better alternative to using replace/regex ?
As far as I know, there are no other possible return values. If opacity is set, there can only be an rgba(...) return value, so in the mindset of defensive programming, you should only parse and modify the value if it is rgba (See also In Javascript how can I set rgba without specifying the rgb?)
See the above link for an easier to read solution without regex.
Related
I run the following code in the Firebug console.
$('img').css('border', 'solid 2px red').css('border');
The red image borders appear, but it returns an empty string, why is this?
It works fine in Chrome and Safari developer tools.
Update: The jQuery docs say that shorthand properties are not supported when getting CSS values. However I have also tried the following with no luck in Firefox (All work in Chrome and Safari)
$('img').css('border-style', 'solid').css('border-style');
$('img').css('borderStyle', 'solid').css('borderStyle');
$('img').css('border', 'solid 2px green').css('borderStyle');
Quoting .css docs.
Shorthand CSS properties (e.g. margin, background, border) are not supported. For example, if you want to retrieve the rendered margin, use: $(elem).css('marginTop') and $(elem).css('marginRight'), and so on.
For the case of border, you need to use the border-width, border-style and border-color related properties.
e.g. border-color:
$('img').css('border-top-color', 'red').css('borderTopColor');
$('img').css('border-right-color', 'red').css('borderRightColor');
$('img').css('border-bottom-color', 'red').css('borderBottomColor');
$('img').css('border-left-color', 'red').css('borderLeftColor');
Try this:
var border = $('img').css('border', '2px solid red')[0].style.border;
FIDDLE
Supported properties in firefox:
'border-top-color'
'border-right-color'
'border-bottom-color'
'border-left-color'
'border-top-width'
'border-right-width'
'border-bottom-width'
'border-left-width'
'border-top-style'
'border-right-style'
'border-bottom-style'
'border-left-style'
Are the supported longhands :) Cheers! Enjoy!!!
You can still use shorthand to set border in most cases.
If you are sure they are the same do something like
var borderString = $('img').css('border-top-width') + " "
+ $('img').css('border-top-style') + " "
+ $('img').css('border-top-color');
to get the string like "2px solid rgb(255,255,255)'
Perhaps you are trying to use multiple properties
use the following syntax
$('img').css({'border':'solid 2px red','color':'green'})
the shorthand property not supported in Jquery.
var objImage = $('img').css('border', 'solid 2px red');
objImage.css('border-top-color');
objImage.css('border-top-width');
objImage.css('border-top-style');
Not just for top, it is also applicable for right, left, and bottom.
This is also a non-working code :
objImage.css('border-style');
Since border, margin, padding properties of CSS is seperately editable. If border-top is different than border-left, browser may be confused which it must return when you just asked border.
Okay I want to change my websites colors on the press of a button. So i have this code:
$( window ).konami({
code : [38,38], // up up
cheat: function() {
$('*').filter(function() {
var match = 'rgb(255, 165, 0)'; // match background-color: black
/*
true = keep this element in our wrapped set
false = remove this element from our wrapped set
*/
return ( $(this).css('color') == match );
}).css('color', 'purple'); // change background color of all black spans
}
});
Now the problem is I want to add bunch of other attributes like background-color, border-color and even active and hover color - though these two might be problematic with this code snippet I think.
Any help adding named attributes to the fray is welcomed - as I'm not an javascript expert by no means.
Also bonus question my webpage is on AngularJS and when I used this konami code, it seems to only work on colors that are currently on display. So on different pages I would have to enter the keys again. Any simple workaround or I gotta deal with it?
Please consider the code snippet below:
<!DOCTYPE html>
<html>
<body>
<div id="mydiv">Sample Text</div>
<script type="text/javascript">
var md=document.getElementById("mydiv");
md.style.cssText="background-color:yellow !important;color:red;font-size:70px;font-weight:bold;";
setTimeout(function(){
md.style.backgroundColor="blue";
md.innerHTML+="<br/>Updated!";
},2000);
</script>
</body>
</html>
Explanation: I am trying out the cssText browser support and noticed that cssText is not working as per my expectation in Firefox, Opera browsers.
The above code defines "background-color:yellow !important" and after 2 seconds the background-color is changed to blue. But since I have specified '!important' in my cssText, I assume the background-color should not get updated. This works in IE, Chrome, Safari. But not in Firefox, Opera.
Can someone please suggest.
EDIT: I want to specify the !important rule for a css property and restrict further changes to it via javascript. I would like to achieve this using JavaScript i.e. specifying !important via JavaScript. Any help on this would be appreciated.
Stumbled across this question while googling for something else.
The first thing to understand, is that cssText doesn't create another style: It is merely a shorthand that lets you assign multiple styles at once. The following are roughly identical:
element.style.cssText = "background-color:yellow;color:red;";
element.style.backgroundColor = "yellow";
element.style.color = "red";
The only real thing to note, is that I believe that assigning to cssText will overwrite any existing element styles. Eg, the following will result in a style that is exactly equal to color:red; and not equal to background-color:yellow;color:red;. cssText effectively removes any existing element styles before applying the ones specified:
element.style.backgroundColor = "yellow";
element.style.cssText = "color:red;";
The second thing to realize, is that !important doesn't make a style read-only. It only prevents defined styles of higher specificities being used, and only does so as long as it is defined. When you assign the background color value of blue, you are effectively removing !important from the declaration. You'd have to set your background color as background-color:blue !important; in order to keep it.
In short, if something overwrites your background-color:yellow !important; with background-color:blue;, there's nothing you can do about it. Unless you do some other fancy work, like creating a timer interval that every X milliseconds resets the yellow !important style. But then you run into problems of having to keep track of the interval, especially if you may actually want to set the background color to some other value, otherwise it will just get overwritten on you!
var element = ...;
setInterval(1000, function(){
if (element.style.backgroundColor != "yellow !important") {
element.style.backgroundColor = "yellow !important";
}
});
The one thing I can think of, is if these styles are set in stone, you could just make them actual rules instead of inline element styles. You can keep the !important tag if you make it a rule:
.bg-yellow {
background-color: yellow !important;
}
element.className = "bg-yellow";
Here is your JS modified code. I've checked in FF 27 and it is working.
var md=document.getElementById("mydiv");
md.style.cssText="background-color:yellow !important;color:red;font-size:70px;font-weight:bold;";
setTimeout(function(){
md.style.setProperty="background-Color:blue"; //modified this line
md.innerHTML+="<br/>Updated!";
},2000);
Here is the Working Demo for you.
http://jsbin.com/kifozeka/2/edit
I have a piece of JS code to generate random numbers and output them as variables to be used here in place of the rotation values
#-webkit-keyframes rotate {
0% {-webkit-transform: rotate(-10deg);}
100% {-webkit-transform: rotate(10deg);}
}
#dog{
/*irrelevant settings*/
-webkit-animation: rotate 5s infinite alternate ease-in-out;
}
The code above works fine however when I try to stick the variables from the javascript into rotate(variable); I cannot get it to work. I am new to this so I'm 90% sure I just haven't got the syntax right for the variable (seriously I am terrible at remembering if something needs brackets, quotes, squigglys etc and I have tried all I can think of).
Or it might be because the variable is local to the function and CSS cannot read that.
So basically I just need some kind stranger to tell me the correct syntax and how to get CSS to read the variable if possible.
Otherwise it looks like I will need the function to create the entirety of:
#-webkit-keyframes rotate {
0% {-webkit-transform: rotate(-10deg);}
100% {-webkit-transform: rotate(10deg);}
}
...which might be a bit messy since the random variable will likely be applied to multiple css elements.
Oh and currently the variable is formatted to include the deg after the number so that is not the issue. In fact, for the sake of ease just assume I am using var dogValue = "20deg"; and forget the random element.
Thanks.
Okay, not what your actual code looks like, but you can't throw JavaScript variables into CSS, it won't recognize them.
Instead, you need to create the CSS rules through JavaScript and insert them into the CSSOM (CSS Object Model). This can be done a few ways -- you can either just create a keyframe animation and add it in, or you can overwrite an existing animation. For this sake of this question, I'm going to assume you want to continually overwrite an existing keyframe animation with different rotation values.
I've put together (and documented) a JSFiddle for you to take a look at: http://jsfiddle.net/russelluresti/RHhBz/2/
It starts off running a -10 -> 10 degree rotation animation, but then you can click the button to have it execute a rotation between random values (between -360 and 360 degrees).
This example was hacked together primarily from earlier experimentation done by Simon Hausmann. You can see the source here: http://www.gitorious.org/~simon/qtwebkit/simons-clone/blobs/ceaa977f87947290fa2d063861f90c820417827f/LayoutTests/animations/change-keyframes.html (for as long as that link works, gitorious is pretty bad at maintaining urls).
I've also taken the randomFromTo JavaScript function code from here: http://www.admixweb.com/2010/08/24/javascript-tip-get-a-random-number-between-two-integers/
I've added documentation to the parts of the Simon Hausmann script that I've taken from him (though I've slightly modified them). I've also used jQuery just to attach the click event to my button--all other script is written in native JavaScript.
I've tested this for Chrome 18 and Safari 5.1, and it seems to work fine in both browsers.
Hope this helps.
In chrome 49 onwards and Firefox 48 onwards you can leverage the new Javascript API element.animate() to push in your keyframe animations.
Please be informed that this API is experimental and doesn't work cross browser except for the aforementioned.
Dated solutions like adding class or injecting keyframes could be leveraged for backward compatibility. A shim for the same was not available immediately.
Yanked the MDN example
document.getElementById("tunnel").animate([
// keyframes
{ transform: 'translateY(0px)' },
{ transform: 'translateY(-300px)' }
], {
// timing options
duration: 1000,
iterations: Infinity
});
refer:
caniuse.com/#feat=web-animation
MDN documentation
For anyone that is looking for this answer in 2017 here's what's changed in RussellUresti answer.
In his example this won't work anymore:
keyframes.insertRule("0% { -webkit-transform: rotate(" + randomFromTo(-360,360) + "deg); }");
keyframes.insertRule("100% { -webkit-transform: rotate(" + randomFromTo(-360,360) + "deg); }");
This is due to .insertRule() being a non standard name. It is now .appendRule(), so RusselsUresti's code will now be:
keyframes.appendRule("0% { -webkit-transform: rotate(" + randomFromTo(-360,360) + "deg); }");
keyframes.appendRule("100% { -webkit-transform: rotate(" + randomFromTo(-360,360) + "deg); }");
(Simply replace insertRule with appendRule.)
More information on the CSSKeyframeRule can be found here
Why this example not working in IE http://jsfiddle.net/8RZVt/
I'm getting this error in IE8.
Message: Invalid argument.
Line: 156
Char: 295
Code: 0
URI: http://code.jquery.com/jquery-1.4.4.min.js
According to jQuery, this is because, as stated on the animate documentation page:
All animated properties should be a
single numeric value (except as noted
below); properties that are
non-numeric cannot be animated using
basic jQuery functionality....
So, in fact, in Firefox you are using undefined behavior. The correct thing to do would be to animate on backgroundPositionX, however Firefox does not support this.
There is, however, a jQuery plugin that does what you want:
http://plugins.jquery.com/project/backgroundPosition-Effect
Update
On closer inspection, the plugin does not support += or -= formats.
I hacked it into this example:
http://jsfiddle.net/CxqSs/ (See new example at bottom.)
Could definitely use some cleanup, and should probably be added to that plug-in, but it works in both browsers and doesn't rely on undefined behavior.
BTW, I don't know if it's worth noting, but if you leave this animation running a long time, it will eventually overflow the value and break. This could be overcome by animating the full length of the background image and then resetting the offset to 0px in the callback before the next animate. This would also avoid needing the += format.
Also,
It should be noted that speed: 1, step: 1 and speed: 50, step: 50 are equivalent.
The reason they look different speeds is because
There is more overhead in a speed of 1 (which is really a millisecond duration) because animate gets called more often.
The default easing is "swing", meaning that the animation speeds up and slows down slightly throughout it's course, meaning that the overall speed is affected a bit. You should change the easing to "linear" for your scrolling case:
var animate = function() {
element.animate({
...
}, speed, "linear", animate);
};
This means that you could use the backgroundPosition-Effect plugin, without the '+=', by setting your step to 2247 (the width of the image), like I stated above.
And that finally brings us to... wait for it...
http://jsfiddle.net/zyQj3/20/
Cross-platform, non-kludgy, non-overflowing, correctly easing, extra parameter-lacking, solution.
The script fails at this point because you are passing an invalid CSS value:
element.animate({
backgroundPosition: animStep + " 0px" /* evaluates to "+=50px 0px" */
}, speed, animate);
OK here we go again :D
http://jsfiddle.net/c7rKV/1/
Again identical to original however again just animating backgroundPositionX when in IE.
Apologies on not actually looking at FF/Chrome last time.
Additionally: this of course is not very graceful and Adam Prax is absolutely correct on what the problem is. I just wanted to post a solution to it.
If you check the source code of jQuery, you will see it uses this regexp to parse the parameter (which in your case is +=50px 0px). So it will see it as += (increase) 50 (to fifty) px 0px (unit, append after the number). When trying to read the current value, jQuery uses parseFloat, which just grabs the number at the start of the string. So it works perfectly, even if a multi-dimensional property is probably not what the jQuery programmers had in mind.
Except that IE8 does not support getting the current value of background-position. There is background-position-x and background-position-y but no background-position. Duh. So your best bet is checking the browser type, and animating either background-position or background-position-x depending on that: http://jsfiddle.net/22UWW/
(There is actually a jQuery bug report about this, with a more elegant solution.)