Closed jods4 closed 10 years ago
Yep, great point. This is a common implementation detail that has the potential to trip people up.
Truth is that this may be technically a mess to implement. I'll keep this issue open as a feature suggestion and revisit it in the near future.
I just faced this problem myself while optimizing to use forcefeed instead of doing .velocity() two times on the same element with the first one having a duration of 0 just to reset it. My solution was to add .selector { opacity:0; } in my CSS.
In what way does this solution not work for you?
CodePen http://codepen.io/anon/pen/dFkoi
@tommiehansen: Exactly. Thanks for bringing this thread back to my attention.
This feature is redundant. The verbosity of doing .css(opacity, 0)
or, better yet, using stylesheets, is the same as the suggested fill mode syntax. Further, your code would be better structured and more legible if you did it outside of Velocity.
For most use cases, stylesheets will already be setting opacity to 0, including elements that are being generated on the fly.
Just not seeing the utility. Will close for now. Happy to continue discussion in this thread if more thoughts come to your guys' mind. I will read this thread when closed.
My only thought on this would be an option to set the initial value when there is one - literally just a shortcut so these would be identical: (var initial = 0
)
.css({opacity: initial}).velocity({opacity, [1, initial]})
.velocity({opacity, [1, initial]}, {setInitial:true})
Unlike the normal forcefeeding of calling .velocity({opacity: initial}, 0)
it would happen when parsing the options rather than on the next animation frame (ie, useful for pageload stuff so there's no FOUC when javascript is enabled and you want the css to be the no-javascript version).
The only benefits I can see to this are if jQuery (or Zepto etc) weren't there so you don't have an easy auto-prefix css setting method handy, and shortening the code slightly.
Two cases that I think are interesting.
First I would like to demonstrate that your CSS should contain final / normal styles for your elements and not your initial / transient state.
Say I have a .popup
bubble on my page, with a desired 70% opacity. When it is added to the page, I want to have it fade in. If I declare .popup { opacity: 0 }
and then animate to 0.7 with velocity, it means the final property is set by style and not class and it implies that I can't remove the style at the end of the fade in animation. Why is that bad? Say I also want the bubble to darken on mouse-over, to 80%. Now I can't do .popup:hover { opacity: 0.8 }
. :(
The good solution would by IMHO to declare .popup { opacity: 0.7 } .popup:hover { opacity: 0.8 }
. And when you add it to animate from 0 to 0.7 and then remove the style and have a "normal" page once the transition has ended.
It also means that we need additional classes for animation if some of my .popup
are animated, and other simply don't.
The second case is that you assume the force-fed value is a constant. What if I want to force-fed a dynamically computed starting position for transitionX
? I can't put that in the stylesheet, so unless Velocity has an equivalent to animation-fill-mode: backwards
, I will need to set it manually.
The biggest issue with that is the simple case that velocity is javascript, so there's no knowing when (or if) any call is made (unlike stylesheets which are generally thought of as static content once loaded) - so adding something that can only be used in very specific circumstances doesn't work that well.
Generally you need your :hover either entirely in css or entirely in javascript (and if you're mixing the two then make sure the attributes don't overlap) - the only way to do it otherwise is to change the stylesheet on-the-fly (which is incredibly expensive as it effectively causes a full page refresh on almost all browsers).
From the looks of things you're wanting the default opacity to be 0.7 - so it needs to be created (or set on page load) with an opacity of 0 before any FOUC, then when the animation is finished a complete:
callback to clear out the value (and let the class take over).
In my previous comment I was assuming a non-constant initial
value (hence not using a number) - but it was more in response to @tommiehansen as a specific use-case than a generic delay
issue (even setting duration: 0
waits for the next animation frame, which potentially causes a single frame flash of a value you don't want etc).
Don't forget that you can always use !important
in your stylesheets, and while it's frowned on by a lot of people (who generally think themselves perfect while totally ignoring the real world lol) things like :hover are perfect for that ;-)
About FOUC : yes for content that is loaded directly in your page. But a major use case for me is content added dynamically, in which case it doesn’t apply (except there’s the single frame flash, which has been logged in another ticket).
What you describe is a matter of API really. If you look at GSAP, you can do this: TweenLite.from({opacity: 0, clearProps: "opacity"})
. It’s awesome when putting new content on the page:
.from API applies values immediately, there is no 1 frame flash of new contents before the animation begins.
.from read the target value from the DOM. So you only define opacity: 0.7 in your CSS – which is where it should be – and it’s not duplicated in your JS.
clearProps removes the opacity style when the animation is over, so it leaves no trace behind and works perfectly well with anything after it.
You're both right. This feature is useless for page-load, but has value for dynamic content addition in the case that you're not using jQuery. @jods: correct me if I'm wrong, but if you have jQuery then doing $elem.css("opacity", 1).velocity() doesn't require any of the BS that modifying your stylesheets entails... and then the only benefit of this feature suggestion is making your code slightly more succinct.
Also, would this ever be realistically useful for properties other than opacity
?
I've got one page that's flat-file html, but if javascript is enabled then it immediately sets a whole load of css values for hiding elements (and one gets positioned), then after the page has loaded it animates them into place using various transitions and movements (I'll send you a link from work tomorrow if you'd like) - 95% are to do with opacity, with only a single element getting moved to the center of the screen (and staying visible) - if this was available I'd probably have shaved 100 bytes from the page and made it slightly more readable ;-)
@julianshapiro yes, calling $.elem.css("opacity", 0).velocity()
is equivalent to setting the start value of animation before it actually starts (the backwards fill).
Now real life is always a little bit funnier: (1) say I'm not using opacity but animate things from the left edge of the screen (add several items and some staggering and we have exactly this issue). I would probably use Velocity hook API instead of jQuery .css()
, because Velocity knows about translateX
and can compose it with others such as scale
, whereas jQuery only knows about transform
(yes, it's still doable. It would probably just look weird). Also I need to duplicate all my constants: $elem.css("transform", "translateX(-300px)").velocity({translateX: [0, -300]})
which is not very nice, versus: $elem.velocity({translateX: [0, -300]}, {fill: "backwards"})
.
(2) I am using Promises a lot and for me Velocity built-in support is a big plus. But I have to use $.Velocity
API, so it doesn't chain nicely with jQuery call.
I agree that although this is a convenient future, it's required only in specific cases (you need both a delay and a starting property value that would make a visible difference) and can be worked around.
Wrong comment button, sorry about the close/reopen thing :(
Thanks to @jods4, the UI pack is now doing this automatically for in
transitions. At this time, I don't plan on implementing this feature globally for all properties. It's a valid suggestion, but just set the value upfront yourself for now. I'll re-consider this in the near future.
The other @jods4 thread I was referring to: https://github.com/julianshapiro/velocity/issues/248
This is a suggestion / idea.
When force-feeding a value, it would be nice to have a way to set property values before a delayed animation actually starts, similar to CSS
animation-fill-mode: backwards
.Here's my use-case:
$("div").velocity({ opacity: [1, 0] }, { delay: 500 })
. If the div is not already at opacity 0, it would flicker or stay visible during the delay. So I ended up doing this:$("div").css("opacity", 0).velocity(...)
. Having an option for that would be nice.BTW: my real use-case was in fact more complicated:
$("div").velocity("transition.bounceIn", { stagger: 75})
. During the delay induced by stagger later elements would not be properly hidden (have opacity force-fed 0).