Skip to content

Instantly share code, notes, and snippets.

@macgyver
Last active August 29, 2015 13:56
Show Gist options
  • Save macgyver/8874337 to your computer and use it in GitHub Desktop.
Save macgyver/8874337 to your computer and use it in GitHub Desktop.
calculate and execute css transitions to/from automatically computed values
# requires: jQuery as $ and underscore as _, uses Modernizr if available
# normalized string for transitionEnd event name
transitionEnd = "webkitTransitionEnd oTransitionEnd transitionend"
# feature test for CSS transitions in the browser
hasTransitions = Modernizr?.csstransitions or ( ->
return _.some [
"transition",
"webkitTransition",
"MozTransition",
"OTransition"
], (propertyName) ->
# silly, but _.has fails here, these are weird objects
# https://bugzilla.mozilla.org/show_bug.cgi?id=967061
return not _.isUndefined document.body.style[propertyName]
)()
# we can remove this nonsense once safari updates to a more current
# version of webkit without the rubber-banding auto css transitions
isSafari = window.navigator.vendor is "Apple Computer, Inc." and window.navigator.userAgent.indexOf("Safari") > -1
# helper for css transitions to auto-computed values,
# see _older_floats or notifications.coffee
# todo: In the future, in order to encourage the very best style,
# I'd like for the change to be based only on the toggle of
# a class name, but this pair of functions works ok for now
#
# $el - the element on which the transition will occur
# props - the properties being animated,
# most likely ⊂ ["height", "width"]
# change - a function that makes the change that will affect layout
# revert - a function that defines how to revert the change
# optional, defaults to the `change` param if omitted.
transitionAuto: ($el, props, change, revert=false) ->
# without transitions, just make the change and be done with it
if not hasTransitions or isSafari
return change()
# allow string input, representing an array with a single element
if (typeof props) is "string"
props = [props]
# if only one fn is provided, it is a toggle fn
revert = revert or change
setToAuto = ->
$el.removeAttr "style"
getStylesAsMap = ->
# jquery's .css seems busted for this signature (in our build) :(
# revisit this when/if we ever upgrade jQuery, `$el.css props` should suffice
_.reduce props, (map, prop) ->
map[prop] = $el.css prop
return map
, {}
# clear styles, letting auto-computed values define the "before" state
setToAuto()
beforeStyles = getStylesAsMap()
# quickly change, assess to determine the "after" state, then revert
change()
afterStyles = getStylesAsMap()
revert()
# set the css explicitly to the "beforeStyles"
$el.css beforeStyles
# finally trigger the transition to the explicit "afterStyles"
setTimeout _.bind( ->
change()
$el.addClass("transitioning").css afterStyles
# last of all, wait for the transition and then clean up
$el.one transitionEnd, ->
$el.removeClass "transitioning"
setToAuto()
, this), 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment