Categories:

Manipulating CSS3 transitions using jQuery- creating a dropping text effect

Created: Oct 16th, 13'

CSS3 transitions are great; they help offload the tedious work from JavaScript when it comes to performing transition effects on the web page, such as moving an element from point A to B, fading it in/out, or basically any effect that involves the changing of one CSS property value to another. Yes CSS3 animations are awesome, but lets face it, CSS3 isn't a programming language (and rightly so), and can never match the logical prowess of JavaScript. This means while you can use CSS3 to implement the majority of a transition effect, often times JavaScript is still needed to polish it off and achieve the desired outcome. In this tutorial we'll examine how JavaScript can help with CSS3 transitions in the following ways:

  • Dynamically set and reset the value of a CSS3 property
  • Respond to when a CSS3 transition has completed, via the transitionend event.

We'll implement a dropping text example with our new found knowledge, where each character of a header sequentially drops away until the very last, at which time the header resets itself.

We'll be using jQuery 1.8+ as the foundation of this tutorial, as it offers a lot of convenience when it comes to working with CSS3, which you'll soon see how.

Setting CSS (and CSS3) properties in jQuery

Setting a CSS property in jQuery is simple enough, using the .css() method:

$("#myelement").css({left:0, backgroundColor:'blue'})

This sets the element #myelement's "left" and "background-color" properties to the indicated values.

When it comes to setting CSS3 property values, things usually get a lot more hairy real fast. That's because of all the CSS3 vendor prefixes (ie: -moz-, -webkit- etc) one has to account for when setting the baseline property. To set the CSS3 property "transform", in jQuery your code may end up looking something like this:

$("#myelement").css({
 transform: 'translateY(300px) rotateZ(120deg)',
 MozTransform: 'translateY(300px) rotateZ(120deg)',
 WebkitTransform: 'translateY(300px) rotateZ(120deg)',
 msTransform: 'translateY(300px) rotateZ(120deg)'
})

Do that a few times, and the last thing you'll want to be doing again is setting CSS3 properties using JavaScript!

There is good news, however, and that's also where jQuery comes into play. Starting in jQuery 1.8+, the framework will automatically detect and set the CSS3 property supported by the browser for you, allowing you to work with just the baseline CSS3 property. So in jQuery 1.8+, the above code would just be:

$("#myelement").css({transform: 'translateY(300px) rotateZ(120deg)'})

Ah that's more like it! Lets illustrate the advantage of this collaboration between JavaScript and CSS3 with the following simple example, which randomly tilts the letters of a headline various degrees:

Demo:

Howdy  Mate!

The JavaScript code to tilt each letter of the text is:

jQuery(function(){
 var $header1 = $('#header1')
 $header1.lettering() // wrap <span class="charx"/ > around each character within header using Lettering.js
 var signage = [1,-1]
 $header1.find('span').each(function(){
  var degree = Math.round( Math.random() * 30 ) * signage[ Math.round(Math.random() * 1) ]
  $(this).css({transform: 'rotate(' + degree + 'deg)'})
 })
})

I'm using the plugin Lettering.js to automatically wrap a <span> element around each character of a text so they can be styled and referenced individually. The key here is how we're randomly generating a degree between -30 and 30, and setting each character's "rotate()" value so the degree of rotation is random. That's what JavaScript brings to CSS3- a sense of chaos- I mean logic!

Manipulating CSS3 transition related properties in jQuery

Time to see how JavaScript works with CSS3 transitions now. There are 4 transition related CSS3 properties, plus a shorthand property:

CSS3 transition properties
CSS Property JavaScript equivalent Description
transition transition Shorthand property to set up to 4 of the below property values at once. Here are some examples:

transition: all 0 ease 0; /* Default. No transition */

transition: color 25ms;

transition: opacity, left 3s ease-in;

transition: all 2s cubic-bezier(0, 0, 0.58, 1) 1s;

transition-property transitionProperty Sets the CSS properties that should be transitioned. Defaults to all, or all properties inside the CSS selector. Separate multiple CSS properties with a comma.
transition-duration transitionDelay The duration of the transition, such as 2s for 2 seconds, 2000ms for 2000 milliseconds etc. Defaults to 0, meaning no transition is rendered.
transition-timing-function transitionTimingFunction Defines the change in speed of the transition from start to finish using a designated keyword or a cubic-bezier curve function. Defaults to "ease", or the bezier function cubic-bezier(0.25, 0.1, 0.25, 1).

The following values are supported:

viewport meta tag "content" property attributes
Property Description
ease The default vale, which equates to cubic-bezier(0.25, 0.1, 0.25, 1). The speed increases gradually before reaching a peak, then slows down at the very end, like a slope.
linear A linear, constant speed from start to finish, equivalent to cubic-bezier(0, 0, 1, 1).
ease-in An initial slow start before increasing in speed. Equivalent to cubic-bezier(0.42, 0, 1, 1)
ease-out An eventual slow end, equivalent to cubic-bezier(0, 0, 0.58, 1).
ease-in-out A slow start and ending, similar to "ease". Equivalent to cubic-bezier(0.42, 0, 0.58, 1)
steps([<integer>, [start, end]?) Specifies a stepping function for the speed curve. The first parameter specifies the number of intervals in the function (integer > 0). The second parameter, which is optional, is either the value ‘start’ or ‘end’, and specifies the point at which the change of values occur within the interval. If the second parameter is omitted, it is given the value ‘end’. The value steps(4, end) renders a transition with 4 intermediate steps from start to finish.
cubic-bezier(x1, y1, x2, y2) Defines a custom bezier curve function to be used as the speed curve. The x values must be within 0 to 1, while the y values can exceed that.
transition-delay transitionDelay Sets the delay before the transition will begin (in s or ms). Defaults to 0, which means immediately.

Lets create a header now that when clicked on, its characters fall down one by one. We'll set each character's transitionDelay property to be incrementally larger than the previous character's, so the dropping action occurs sequentially:

Demo:

Click  on  me!

Lets look at this one's code in full. First, the CSS:

#header2{
font-family: 'Orbitron', sans-serif; /* font style. Default uses Google fonts */
text-shadow: 2px 2px #B4EAF3, 3px 3px #B4EAF3, 4px 4px #B4EAF3, 5px 5px #B4EAF3, 6px 6px #B4EAF3;
font-size: 64px; /* font size of text */
color: #207688;
letter-spacing: 15px;
font-weight: 800;
text-transform: uppercase;
position: relative;
}

#header2 span{
display: inline-block;
}

.dropped span{
-moz-transform: translateY(300px) rotateZ(120deg); /* rotate, translate, and disappear */
-webkit-transform: translateY(300px) rotateZ(120deg);
transform: translateY(300px) rotateZ(120deg);
opacity: 0;
-moz-transition: all 0.3s ease-in;
-webkit-transition: all 0.3s ease-in;
-ms-transition: all 0.3s ease-in;
transition: all 0.3s ease-in;
}

We define a "dropped" CSS class that we'll defer adding to #header2 until the header is clicked on, applying the drop down effect. Now, to the JavaScript portion, which helps us do 3 things:

  • Set the transition delay of each SPAN so their values increase sequentially from the previous.
  • Add the "dropped" class to #header2 when header is clicked on.
  • Reset the text effect once we think all the text have fallen, by dynamically removing the "dropped" class. The way we deduce when the animation has finished is by adding up the animation time of all the SPANs; we'll see a much better approach later, but for now this will suffice.

<script>

jQuery(function(){
 var $header2 = $('#header2')
 $header2.lettering() // wrap <span class="charx"/ > around each character within header
 var $spans = $header2.find('span')
 var delay = 0
 $header2.on('click', function(){
  $spans.each(function(){
   $(this).css({transitionDelay: delay+'s'}) // apply sequential trans delay to each character
   delay += 0.1
  })
  $header2.addClass('dropped') // Add "dropped" class to header to apply transition
  setTimeout(function(){ // reset header code
   $spans.each(function(){
    $(this).css({transitionDelay: '0ms'}) // set transition delay to 0 so when 'dropped' class is removed, letter appears instantly
   })
   $header2.removeClass('dropped') // remove class at the "end" to reset header.
   delay = 0
  }, 1800) // 1800 is just rough estimate of time transition will finish, not the best way
 })
})

</script>

<body>

<h3 id="header2" class="header">Click &nbsp;on &nbsp;me!</h3>
</body>

When $header2 is clicked on, we loop through each SPAN element containing a character and set its transitionDelay property to 0.1s greater than the previous. Following that, the "dropped" class gets added to it to kick off the dropping animation, with one letter falling after the next. To reset the animation at the end, a setTimeout() function is used to estimate when the animation will finish, and when that happens, set transition-delay on each character to 0 before finally removing the "dropped" class on their parent container. Setting transition-delay to 0 is necessary, as otherwise, the same sequential delay of each character will be applied when they reappear.

So we've seen how CSS3 properties- such as those related to transitions- can be accessed in JavaScript to our delight. But this collaboration extends beyond that. Whenever a transition runs, JavaScript's transitionend event handler fires at the very end to let you respond programmically. It's what we'll be using to supplant our setTimeout() function above with for more precise reaction to transition events. Lets look at that next.

Using transitionend event to detect when a transition has finished