Menu
07/03 2010

Flicker effect with jQuery

During the design process of a recent project homepage, I wanted to use an effect that native jQuery plugins or javascript effects could not achieve in the way I wanted them to. My idea was to have as spooky a theme as I could on the site and the main feature of the homepage would be a zombie girl lurking in the woods 🙂

Once I had the design down in photoshop, I was trying to figure out a way of making the girl stand out when it came to putting the design in a browser, just in case the user had missed her and the eerie effect proved useless. I love horror films and those spine tingling moments in films when something unsettles you. A particular scene in the film 'The Ring' inspired me to use a flickering effect on the girl to give the whole scene an unsettling appearance.

The first thing was to seperate the girl from the rest of the image using css, so that I could target her with jQuery more effectively.

<div id="topnav">
<ul>
    <li class="current_page_item"><a href="/"><span>run</span> home</a></li>
    <li><a href="/web-design-bournemouth">what <span>am i</span></a></li>
    <li><a href="/why-am-i">why <span>am i</span></a></li>
    <li><a href="/summon-me">summon <span>me</span></a></li>
</ul>
</div>
<script type="text/javascript">// <![CDATA[
  if(!$.browser.msie){$('#main .right .zombie').css({opacity:0});}
// ]]></script>

I did this by structuring the page and putting the zombie div after the topnav div. I also added a small piece of jquery just after the zombie div to hide it from view immediately. This is to make sure that everything is set up correctly before the sequence begins. The following shows the css rules applied to the zombie div.

As ever, IE shows problems when trying to animate opacity values and for now I decided not to make this effect available to IE browsers

#main .right .zombie {
background:transparent url(../images/zombie.png) no-repeat scroll 180px 185px;
height:370px;
position:relative;
}

Knowing that all I want to do for now is flicker the div, I was safe to add position and structure using css to move the zombie image where I wanted it.

As with any new idea, planning and setting things up with your goal in mind is essential. Most of the donkey work is done in setting things up correctly in the first place. I almost knew what the main jQuery needed to do once I'd reached this point in the development process. It mostly consists of stringed animations and pauses but timing them was the tricky part. Flickers needed to seem almost random, so I mixed long pauses in with quick changes in opacity till it looked right.

$zombie = $('#main .right .zombie');
if(!$.browser.msie){
$zombie.animate({opacity:0}, {duration:1})
.animate({ opacity: 0 },6000)
.animate({opacity:0}, {duration:1})
.animate({opacity:0}, {duration:100})
.animate({opacity:0.5}, {duration:10})
.animate({opacity:0}, {duration:300})
.animate({opacity:0.6}, {duration:100})
.animate({opacity:0}, {duration:200})
.animate({opacity:1}, {duration:100})
.animate({opacity:0}, {duration:100})
.animate({opacity:0.3}, {duration:100})
.animate({opacity:1}, {duration:10})
.animate({opacity:1}, {duration:10000});
function runit(){
$zombie
.animate({opacity:1}, {duration:200})
.animate({opacity:0}, {duration:100})
.animate({opacity:1}, {duration:10})
.animate({opacity:0}, {duration:10})
.animate({opacity:1}, {duration:10})
.animate({opacity:0}, {duration:50})
.animate({opacity:1}, {duration:100})
.animate({ opacity: 1 },20000, function(){runit();});
}
runit();
}

Another hurdle that needed jumping was the looping issue. I wanted the effect to be continuous. I got over this one by effectively having a function within a function. runit() has an animation sequence within it. This function is called after an initial animation sequence. The clever bit is that the function gets called at the end of itself, this keeps the flicker going forever.

Yet another thing that needed resolving was the fact that Different things load at different times. With everything else loading around it, the zombie girl animation was in danger of simply being lost because the user would be distracted by other elements popping up around it. I needed the girl to be the focus of the users attention for it to be effective. I utilised jQueries excellent bind feature to execute the above only after everything within the DOM window had loaded. I wrapped the animation sequence in this bind function and things worked brilliantly.

$(window).bind('load', function() {
$zombie = $('#main .right .zombie');
if(!$.browser.msie){
$zombie.animate({opacity:0}, {duration:1})
.animate({ opacity: 0 },6000)
.animate({opacity:0}, {duration:1})
.animate({opacity:0}, {duration:100})
.animate({opacity:0.5}, {duration:10})
.animate({opacity:0}, {duration:300})
.animate({opacity:0.6}, {duration:100})
.animate({opacity:0}, {duration:200})
.animate({opacity:1}, {duration:100})
.animate({opacity:0}, {duration:100})
.animate({opacity:0.3}, {duration:100})
.animate({opacity:1}, {duration:10})
.animate({opacity:1}, {duration:10000});
function runit(){
$zombie
.animate({opacity:1}, {duration:200})
.animate({opacity:0}, {duration:100})
.animate({opacity:1}, {duration:10})
.animate({opacity:0}, {duration:10})
.animate({opacity:1}, {duration:10})
.animate({opacity:0}, {duration:50})
.animate({opacity:1}, {duration:100})
.animate({ opacity: 1 },20000, function(){runit();});
}
runit();
}
}});

11 Responses to Flicker effect with jQuery

  1. Richard says:

    very cool.
    I hadn’t heard of jquery before. it works well.

  2. Webegg says:

    Thanks for your comment Richard. Looking at your site it looks like you may want to have a play with HTML5’s new canvas features. Loads of stuff there.

  3. Errol Sirra says:

    In your final jquery script your last curly bracket should be a round bracket. Took me forever to go through your code to find out why it wasn’t working for me. Otherwise great script and implementation.

    1. Webegg says:

      Apologies Errol, the site was redesigned recently and I had a few issues with the code highlighting functionality on the site. I had to redo most of the code examples and obviously missed a few syntax details. On the bright side you improved your debugging skills a little.

  4. Errol Sirra says:

    One more thing, the animate opacity code does work in IE now. I was recoding your script to work with IE7 and IE8. I was making progress when I made a typo and called the old runit function and it began working. I removed your if statements and found it will work with IE as is. Also no problems with Safari, Chrome or Opera.

  5. Wills Bithrey says:

    Great article and a great demo of jQuery’s chainability!

    As per our conversation on Twitter yesterday, surely it’d be better to use JavaScripts setInterval() rather than making a recursive function?

    Perhaps like this: http://jsfiddle.net/aB8qU/2/

    1. Webegg says:

      Thanks, and I’m flattered you took the time to explore your idea. I did explore the setInterval option myself although I found a mixture of chaining animation and a recursive function to be much more robust. With setInterval you override the chaining rather than allowing things to flow in sequence. I will look into your point about comments though, thanks for the feedback.

  6. Wills says:

    Great comments, but I disagree (still 😉 A key principal of recursion is that each time the function recurses, it should lead one step to the solution (and the base case). As in your example you are simply animating forever, there is no base case and this goes against a principal requirement of the point of recursion! Of course it’s only a small function so your may not notice too many problems, but leave the recursion function going and your just eating up memory. In this case this may not be an issue, as how long are users likely to stay on the page with the effect, perhaps a few minutes at most usually. However, the point remains, your not (in my opinion) using the core principal of recursion properly with the example presented.

    Out if interest, what do you mean by the recursive version is “more robust”, since I didn’t see any problems with the setInterval version, infect it gave, as far as I can remember my quick implementation, exactly the same visually effect as the original , reviewing function. (I simply sped up the timings to show the looping more effectively).

    I’d be interested to hear you thoughts and comments.

    Thanks for a great article.
    Will

    1. Webegg says:

      I think I see what you’re getting at Wills. I think we’re going to have to agree to disagree though. With setInterval you are asking the browser for an extra action (to keep time an initiate something every so often). With the chaining method you are doing one thing at a time and then passing things on to the next action. In my opinion you are asking less, not more. I think your version would show problems with long delays, which is in the original example due to having a setInterval timing to change as well as an animation duration change being required.

      I do value everyones opinion and if you can provide an example to illustrate your point (timing changes and slow down) you might be able to change my mind.

  7. […] of your homepage, like in the demo you would see a zombie girl lurking in the woods. By adding very simple and short jQuery functions, you can promptly hide the element from view. It mainly involves stringed animations and pauses, […]

  8. […] Flicker effect with jQuery – Webegg […]

Leave a Reply

Your email address will not be published. Required fields are marked *

This article is in the jquery category. Here are some other related articles also in this category.