We are using a jQuery plugin for some UI-effects. The plugin works great, but in chrome it melts the cpu's. The plugin tries to css-transform an image. Here is an image example:
<img width="1600" height="568" alt="" src="foo.png" style="width: 1598px; height: 567px; left: -209px; top: -2px; opacity: 1; transform-origin: center top 0px; transition-duration: 0s; transform: scale(1);">
and here the code that is causing the problem in chrome ($img beeing an jQuery object):
$img.css({
"-webkit-transition-duration":"20s",
"-webkit-transition-timing-function":"ease",
"-webkit-transform":"scale(0.73) rotate(0.1deg)",
"-webkit-perspective":"0"
});
The problematic part is "-webkit-transform". In Firefox there is no performance problem with the equivalent CSS transformation.
Is this issue known, is there an alternative way doing it?
EDIT:
Using the 3d variant does not solve the problem here:
$img.css({
"-webkit-transition-duration":"20s",
"-webkit-transition-timing-function":"ease",
"-webkit-transform":"scale3d(0.73,0.73,0.73) rotate3d(0,0,0,0.1deg)",
"-webkit-perspective":"0"
});
EDIT2:
After looking more into the chrome devtools timeline, I can see lots of "Composite Layers" events (every 15ms). I also noticed (after enabling the FPS counter) that the framerate always is about 60 FPS when using the css transformation.
If I use a simple $.animate() to scale the image the FPS is around 20 max and there are less "Composite Layers" events (about every 40ms).
Looks like the heavy (re-)painting causes the problem.
You should use 3d transformations with the depth transform as the identity transformation to force the GPU to handle the operation instead of the CPU. Use scale3d and rotate3d instead of scale and rotate.
To rorate images I use jQueryRotate plugin, to scale you can change width and height of img tag with jQuery animate method.
See this link.
$(document.body).ready(function(){
$("img").mouseover(function(){
var width = $(this).width();
var height = $(this).height();
var toResize = Math.random() * 20 - 10;
var newWidth = parseInt(width + toResize * width/height);
var newHeight = parseInt(height + toResize * height/width);
$(this).animate({
width: newWidth + 'px',
height: newHeight + 'px'
}, 100, function(){
//complete
});
var angle = Math.random() * 360;
$(this).rotate({animateTo: angle});
});
});
Related
folks I want to make a demo design of this and I got confused how to achieve this. should I go for parallax scrolling or should I prefer skrollr or scrollmagic or just simple css with few jquery code? suggest the simplest way to achieve this.
Thanks :)
Here is working example;
Html
<div class="rotate"></div>
Css
body{
height: 1000px;
background: yellow;
}
.rotate{
background: url("http://i.imgur.com/zZ3fMuh.png");
width: 101px;
height: 102px;
position: fixed;
}
Js
$(function() {
var rotation = 0,
scrollLoc = $(document).scrollTop();
$(window).scroll(function() {
var newLoc = $(document).scrollTop();
var diff = scrollLoc - newLoc;
rotation += diff, scrollLoc = newLoc;
var rotationStr = "rotate(" + rotation + "deg)";
$(".rotate").css({
"-webkit-transform": rotationStr,
"-moz-transform": rotationStr,
"transform": rotationStr
});
});
})
In this particular case they used CSS with the help of JavaScript but the part what you are watching at is CSS (really fluent) and it get executed my an scroll handler.
In this specific case they used the transform: translate3d() property to rotate the yellow background.
If you want to rotate the background when scrolling, look this: https://codepen.io/sarkiroka/pen/gByRmd
In nutshell it uses the sidebar elements for this effect. This elements has :before property with background setting, and a little javascript calculate the rotating degree from the scrollTop. And this javascript overwrite the defined css rule transform property.
What would be an elegant solution to proportionally scale and center an entire website to fit a browser window (and updating as it's re-sized)
Assume the base layout is 720x500px
Content should proportionally scale to fit, and then re-center.
Essentially, operating like this Flash plugin: http://site-old.greensock.com/autofitarea/ (though base size is known)
Site will contain several different types of elements in that 720x500 area... ideal solution would just scale the whole thing, not needing to style each individual element (in case it matters- images will be SVG and so scaling should have no negative affect on resolution)
Depending on the browsers you need to support (IE9+), you could achieve that with simple CSS transform.
See an example (using jQuery) in this jsfiddle
var $win = $(window);
var $lay = $('#layout');
var baseSize = {
w: 720,
h: 500
}
function updateScale() {
var ww = $win.width();
var wh = $win.height();
var newScale = 1;
// compare ratios
if(ww/wh < baseSize.w/baseSize.h) { // tall ratio
newScale = ww / baseSize.w;
} else { // wide ratio
newScale = wh / baseSize.h;
}
$lay.css('transform', 'scale(' + newScale + ',' + newScale + ')');
console.log(newScale);
}
$(window).resize(updateScale);
If you need backwards compatibility, you could size everything in your site with % or em, and use a similar javascript to control the scale. I think that would be very laborious though.
One solution I'm using is working with a container in which I put an iframe that's being resized to fit as much available screen as possible without losing it's ratio. It works well but it's not completely flexible: you need to set dimensions in your content page in % if you want it to work. But if you can manage your page this way, I think it does pretty much what you want.
It goes like this. You create a container html page that's basically only styles, the resize script and the iframe call. And you content goes into the iframe page.
<style>
html, body
{
border: 0px;margin: 0px;
padding:0px;
}
iframe
{
display: block;
border: 0px;
margin: 0px auto;
padding:0px;
}
</style>
<script>
$(document).ready(function(e){
onResizeFn();
});
$(window).resize(function(e){
onResizeFn();
});
// this stretches the content iframe always either to max height or max width
function onResizeFn(){
var screen_ratio = 0.70 // this is your 720x500 ratio
if((window.innerHeight/window.innerWidth) > screen_ratio){
var theWidth = window.innerWidth
var theHeight = (window.innerWidth*screen_ratio);
} else {
var theHeight = window.innerHeight;
var theWidth = (window.innerHeight/screen_ratio);
}
document.getElementById("your_iframe").width = theWidth + "px"
document.getElementById("your_iframe").height = theHeight + "px"
}
</script>
// And then you call your page here
<iframe id='your_iframe' src='your_content_page' scrolling='no' frameborder='0'"></iframe>
I'm trying to animate a menu where the hovered block is getting bigger, while the siblings are offering their space for this size increase. All blocks together are taking up the whole window width.
I successfully accomplished that using some basic Jquery, but the result is a bit clunky.
The rightmost div suffers from all the calculations and rounding :
var width = $(window).width() - 44;
var blockwidth = width/12;
var blockwidthLarge = blockwidth+154;
var blockwidthSmall = blockwidth-14;
$('.headerblock').css('width',blockwidth+'px').hover(function()
{
$(this).siblings().stop(false,false).animate({width: blockwidthSmall},300);
$(this).stop(false,false).animate({width: blockwidthLarge},300);
},function()
{
$(this).siblings().stop(false,false).animate({width: blockwidth},300);
$(this).stop(false,false).animate({width: blockwidth},300);
});
This is a working jsfiddle (I would recommend to resize the preview frame to something larger to increase the effect's visibility):
jsfiddle
How can I improve this to have the boxes appear stable? Maybe this has already been developed?
The website should be IE8+ compatible, so I cannot use fancy css rules.
There's a jQuery plugin called hoverIntent by Brian Cherne that might solve your issue.
Basically, what it does is only firing the hover event when it thinks that the user actually meant to hover. It's a little less fluid than the original, but it works big time and looks fancy.
Here's a fiddle with the plugin added under "External Resources" and the
$('.headerblock').hover(function() {
changed to ".hoverIntent"
http://jsfiddle.net/Matze/c4uyR/1/
var width = $(window).width() - 44;
var blockwidth = Math.round(width / 12);
var blockwidthLarge = blockwidth + 154;
var blockwidthSmall = blockwidth - 14;
$('.headerblock').css('width', blockwidth + 'px').hoverIntent(function ()
{
$(this).siblings().stop(false, false).animate({
width: blockwidthSmall
}, 300);
$(this).stop(false, false).animate({
width: blockwidthLarge
}, 300);
}, function () {
$(this).siblings().stop(false, false).animate({
width: blockwidth
}, 300);
$(this).stop(false, false).animate({
width: blockwidth
}, 300);
});
I noticed whenever I use jquery animate with long time and small change animation becomes incredibly jerky! The only way to fix this seems to decrease time considerably and scale more. But in some projects this is not possible...
I looked into css transitions. And it didn't provide better results. Animation itself was better, but firefox was horridly jerky and in chrome animation finishes were not quite there with smoothness.
So my question is this, is there any other library with animation engine that can provide smooth scaling of images? or is there a technique that I'm missing?
This is my animation:
$('.item a').mouseover(function(){
//
var this_img = $(this).find('.img_grayscale');
var css_w = parseInt(this_img.attr("width"), 10);
var css_h = parseInt(this_img.attr("height"), 10);
// 10% of height and width calc here
var css_p_w = css_w * 10 / 100;
var css_p_h = css_h * 10 / 100;
//
var css_top = -(css_p_h / 2);
var css_left = -(css_p_w / 2);
//
this_img.stop().animate({ opacity:1 }, 100, function(){
this_img.animate({width:css_w + css_p_w, height:css_h + css_p_h, top:css_top, left:css_left}, 1200, "linear");
});
//this_img.transitionStop().transition({ opacity:1 }, 100, function(){
// this_img.transition({ scale:1.05, rotate:0.02 }, 2500, "ease");
//});
//
}).mouseout(function(){
//
var this_img = $(this).find('.img_grayscale');
var css_w = parseInt(this_img.attr("width"), 10);
var css_h = parseInt(this_img.attr("height"), 10);
//
this_img.stop().animate({ width:css_w, height:css_h, top:"0", left:"0" }, 1200, "linear", function(){
this_img.animate({ opacity:0 }, 100);
});
//this_img.transitionStop().transition({ scale:1 }, 2500, "ease", function(){
// this_img.transition({ opacity:0, rotate:0.02 }, 100)
//});
//
});
Commented out parts are jquery.transit plugin tests, this plugin provides css3 transitions.
Live example: http://mac.idev.ge:800/test/ (hover images)
Why don't you use simple CSS transitions, here's a demo.
<img src="some-image.jpg" />
CSS
img {
width: 400px;
height: 300px;
position: absolute;
top: 100px;
left: 100px;
transition: all 0.2s linear;
}
img:hover {
width: 440px;
height: 330px;
top: 85px;
left: 80px;
}
To get the smoothest look and best performance I would definately recommend using css scale transform.
There's some gotchas to be aware of though. It seems some browsers try to be clever and optimizes transforms which only results in a size change in the image. The trick is to also apply a small rotation:
-webkit-transform: scale(1.2, 1.2) rotate(0.1deg);
transform: scale(1.2, 1.2) rotate(0.1deg);
Here's a demo: http://jsfiddle.net/g2Qrv/
It scales smoothly in Chrome, FF, IE10, Opera and Safari on iOS.
I was wondering is there any alternatives to Jquery for animating Div heights in JavaScript? While Jquery is great and relatively small, I dont want to load the entire jquery just for this one functionality. And considering this is for a WebOs app (not a web app), I need to keep the loading time as small as possible.
Thanks
function animateHeight(obj, height){
var obj_height = obj.clientHeight;
if(obj_height <= height){ return; }
else {
obj.style.height = (obj_height - 5) + "px";
setTimeout(function(){
animateHeight(obj, height);
}, 500)
}
}
Nice fiddle: http://jsfiddle.net/maniator/Z6cbq/
WebOS uses mobile WebKit, so you could do most of the work with CSS:
#someElement {
-webkit-transition: height 100ms linear;
height: 0;
}
Then your JavaScript is really easy:
document.querySelector('#someElement').style.height = '100px'
// - or -
document.querySelector('#someElement').className += ' open';
// where #someElement.open has a defined height.
Here's some more details: http://pre101.com/blog/2009/11/10/a-guide-to-css-transitions-in-webos/
A bare bones animation library weighing in at 1 KB:
https://github.com/relay/anim/