3

I seem to experiencing a problem with the JQuery animation. I can animate the background image in the positive direction, but not in the negative direction. Any suggestions as to how to remedy this?

$(this).parent().css('background-position-y', '19px');
$(this).parent().animate({ 'background-position-y': '-=19px' }, 1000, 'linear');
user1434739
  • 235
  • 4
  • 13

2 Answers2

14

Positioning the background via separate background-position-x/y is a feature that Internet Explorer introduced but never made it into a W3C specification. Any recommendations to add it to the spec have since been denied.

See: http://snook.ca/archives/html_and_css/background-position-x-y

You can always create your own little plugin, it's not that hard.

Using jQuery 1.8 we now have access to the $.Animation method that gives us the animated values directly without to much work, so we can do something like :

$.fn.animateBG = function(x, y, speed) {
    var pos = this.css('background-position').split(' ');
    this.x = pos[0] || 0,
    this.y = pos[1] || 0;
    $.Animation( this, {
        x: x,
        y: y
      }, { 
        duration: speed
      }).progress(function(e) {
          this.css('background-position', e.tweens[0].now+'px '+e.tweens[1].now+'px');
    });
    return this;
}

And then to use it we can do:

$("#background").animateBG(x-value, y-value, speed);​

FIDDLE

This is something I whipped up for another answer some days ago, and only works with pixels and does have some limitations, but it's simple and should work for most cases.

I guess something like this would do what you want:

$(this).parent()
       .css('background-position', '0 19px');
       .animateBG(0, 0, 1000);​
Community
  • 1
  • 1
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • While your solution provided me with a route to my solution, I still do not fully understand it. Could you please explain your use of the $.Animation and the e.tweens variables. – user1434739 Sep 11 '12 at 11:07
  • $.Animation is a new method in jQuery 1.8+ that is used to animate stuff, just like the regular animate() function. The difference it that $.Animate supports tweening and a bunch of other stuff, and the tweens used in the code above is the value as it is being animated, so it lets us assign that value to any CSS statement just like the regular animate() function would do when animating things like height or width, but the regular animate() only supports one value at the time, but with $.Animate we can animate both background values at the same time etc. – adeneo Sep 11 '12 at 11:23
  • So how then would I retrieve the current duration that the animation has been running for? And if I were to run an animation using the method, how would I stop it at any point? [$curMenuTop.animateBG(0, 19, 5000); $curMenuTop.stop(); The .stop doesnt seem to detect and stop the animation when it is active on the element. – user1434739 Sep 11 '12 at 12:38
  • 1
    Well, now you're not dealing with a method chained to the element but a medthod that accepts the element as an argument, so you would need to run stop() on the animated object and not the element being animated. Here's a [FIDDLE](http://jsfiddle.net/HN3Ba/25/) ... – adeneo Sep 11 '12 at 12:56
  • Ah fantastic. Getting it now :) Lastly, I can see how you retrieve the current X and Y at any point during the animation. Is there also a native way to get the current duration that the animation has been running for when the user clicks stop? Thanks for the help. Legend! Cheers Devin – user1434739 Sep 11 '12 at 14:15
  • 1
    Actually there is'nt a direct method that I know of to get the running time. The regular `animate()` function does'nt really have many options for this either, but at least in `$.Animate` you can get the `startTime`, and then all you have to do is subtract that from the time now, and you'll at least get an estimate of how long the animation ran, see [FIDDLE](http://jsfiddle.net/HN3Ba/27/) .. – adeneo Sep 11 '12 at 14:41
  • Hi Adeneo. I have created a fiddle, with comments. [http://jsfiddle.net/devin85/YRBmR/1/] The purpose is simple. When you click on a top menu, it will show its submenu and the black image behind the Top menu text will begin moving down. While you hover the submenu, it pauses the animation from moving down, and resumes when your hover leaves the menus. I have almost gotten this correct, but as you will see the animation jumps and restarts. I have commented where the stop and resume have been placed. Please could you tell me where I am going wrong. I seem to be employing all your advice. :/ – user1434739 Sep 11 '12 at 14:56
  • In short I have continued to test since the previous post. In my fiddle the .stop() method still does not fire, even though I assigned the instance of the animate to a var as to make it accessible. Any idea why? Sorry to bug you on this - http://jsfiddle.net/devin85/YRBmR/3/ – user1434739 Sep 11 '12 at 19:54
  • 1
    Sorry, was out and did'nt see your messages. In the example with stop() I'm returning the animation object, so the variable contains the returned animation, and that is why it works. You could always just assign it to a variable directly instead, like this [FIDDLE](http://jsfiddle.net/YRBmR/5/)... The way you did it, the animateBG() function still returns `this`, which is the element animated and not the animation object. Note that if you intend to chain other functions after `animateBG()`, like `$(element).animateBG(100,100,100).hide()`, that will only work if it returns `this` (the element). – adeneo Sep 11 '12 at 20:29
  • What I am noticing though is that when I stop the animation on 'mouseenter', then resume it after I 'moveleave', it doesnt continue from where the background last stopped, but rather starts the background from the top again. Do you know why this happens? – user1434739 Sep 11 '12 at 20:44
  • After further testing I have noticed that when you stop/resume the animation the background resets its position to 0. I can't figure this out, as in my fiddle [http://jsfiddle.net/devin85/YRBmR/7/] when I alert the value you can see that it still shows the Y-Pos as where the animation was stopped. I have also read though that support for background-position-x/y is problematic in some browsers. This however doesnt explain the animation restarting. Any thoughts? – user1434739 Sep 11 '12 at 21:51
  • Ok just solved the problem. It was in your animateBG method you assumed 0 on the this.x/y variable. I have now changed it to read: this.x = pos[0], this.y = curY; .... and in the progress of the animation set curY: curY = e.tweens[1].now; ... This means that I can stop and resume the animation and the background position retains its state. Thanks again for all your help!!! Really appreciated it. Cheers Devin – user1434739 Sep 12 '12 at 10:26
  • What would we add to this to make it an infinite loop? – klewis Nov 20 '13 at 20:13
1

@adeneo: this solution only works if you set

this.x = pos[0].split('px')[0] || 0;
this.y = pos[1].split('px')[0] || 0;

Otherwise the starting position will be set to zero.

Tim
  • 5,893
  • 3
  • 35
  • 64
Falk
  • 621
  • 2
  • 9
  • 23
  • Thank you @adeneo and Tim. Thanks to both of you I got it working - it's great! https://gist.github.com/1eccc45e93d9d2ae43c3ba0056c36d3e – Christopher Jul 07 '19 at 15:12