March 21, 2016 | 47 Feedbacks

Ink Transition Effect

An ink bleed transition effect, powered by CSS animations.
Browser support
  • ie
  • Chrome
  • Firefox
  • Safari
  • Opera

I recently came across a couple of websites using ink bleeds as transition effects. A great example is the Sevenhills website. At first I thought they were using a HTML canvas powered technique (for allowing transparency), then I checked the source code and found out they weren’t using a video, but a PNG image sprite.

By using a PNG sprite and the steps() timing function in CSS, we can create video effects and use them as transitions! In our resource, we used this technique to fire a modal window, but you can use it to transition between two different pages as well.

The process to create these effects is simple, let me break it down for you:

First, you need a video with a filling effect and a transparent area. Then you need to export this video as a PNG sequence. We used After Effects to export the sequence (make sure to export the alpha channel as well).


Since our video is composed of 25 frames, the assets exported are 25 PNG images. Just to give you more info about the composition settings, we created a 640x360px video with a duration of 1 second and a frame rate equal to 25.


Finally the tedious part: you need to create the PNG sprite, by creating a new image that includes all frames on the same row. We did this manually using Photoshop, and combined all frames into a single 16000×360 pixels image.


In order to turn the sequence into a video, we just need to translate the PNG sprite, and use the steps() function to define the number of frames.

Do you want to learn more about CSS transforms and animations? Check out our course ;)

Now let’s jump into the code!

Creating the structure

The HTML structure is composed of 3 main elements: a for the page main content, a for the modal window and a for the transition layer.

Adding style

The .cd-modal window has, initially, visibility: hidden, height: 100% and width: 100% and is in fixed position.
When a user clicks the, the visibility of the modal window is changed to visible and its opacity to 1 (using the .visible class).

The element is used to create the transition ink effect: it has visibility: hidden, height: 100% and width: 100% and is in fixed position.

Its child element has the ink.png sprite as background-image, a background-size: 100%,  height: 100% and width: 2500% (the ink.png sprite is composed of 25 frames); its left/top/translate values are set so that, initially, the first frame of the ink.png sprite is centered inside the

Note: to center an element inside its parent, you would use:

In our case, though, we want to center the first frame of the ink.png sprite, and since width is 25 times the one of its parent, we use a translateX(-(50/25)%).

To create the ink animation, we change the translate value of the; we defined the cd-sequence keyframes rule:

This way, at the end of the animation, the last frame of the ink.png sprite is centered inside the element.

Note: since we have 25 frames, to show the last one you need to translate the .bg-layer of -100% * (25 – 1) = -96%; but then, to center it inside its parent, you need to add the additional -2%.

When a user clicks the, the .visible class is added to the .cd-transition-layer to show it, while the .opening class is used to trigger the ink animation:

Note that we used the steps() function: that’s because we don’t want the translate value to change continuously, but rather change through fixed steps, in order to show one frame at a time; the number of steps used is equal to our frames less one.

Events handling

We used jQuery to add/remove classes when user clicks the or .modal-close to open/close the modal window.

Besides, we change the .bg-layer dimensions in order not to modify the png frames aspect ratio. In the style.css file, we set .bg-layer height and width so that each frame has height and width equal to the ones of the viewport. Viewport and frames could have a different aspect ratio though and that could distort the single frame. The setLayerDimensions() function has been used to prevent this from happening:


Mar 21, 2016
  • Resource released by CodyHouse

Claudia Romano

Web developer, fan of The Big Bang Theory and good food. Co-founder of CodyHouse and Nucleo. You can follow her on Twitter.

  • Terror Byrd

    Here’s a way to speed up the spritesheet process it’s a script that loads the images in photoshop and creates the spritesheet for you:

  • Huy Le

    I think if you put every tutorial including this one on Youtube, you definitely get tons of subscribers in just a few days! I’ll be the first one :))
    Thanks for this awesomeness!

  • Edmundo Santos

    Great idea and execution, love the effect! Thanks :D

  • Oren Zur-Shavit


  • cytronaute

    Couldn’t the png size be a problem for low connexions? I’d like to understand when it will be loaded by the user, let me know !

  • Samiur

    This reminds me of Call of duty:Ghosts.

  • cfc

    Is there any benefit to doing it this way instead of just using an animated GIF?

    • Nick Borisov

      Gif will have huge size

    • Luca Bobbio

      GIFs are much bigger and have a fixed speed, this technique seems more flexible

      • cfc

        While PNG compression is better than GIF compression for static images, PNGs are not optimized for storing frames of animation, whereas animated GIFs are. Basically, this means that a PNG sprite sheet will potentially duplicate a ton of data that doesn’t change between frames, whereas an animated GIF will only store that data once. It’s possible PNG’s superior compression is enough to make up for that, but unless someone’s done a size comparison for this animation, I wouldn’t assume that a PNG sprite sheet is actually smaller than it would be as an animated GIF.

        As for flexibility, I’m not sure how that applies here. CSS and sprite sheets will allow you to define different variants of the animation, but unless I’m forgetting something, this tutorial didn’t do anything like that. All it does is play the animation back at a fixed speed, exactly as you would with an animated GIF.

        There are plenty of good use cases for animating sprite sheets with CSS or JavaScript. I just don’t see what makes this effect one of them.

  • davidhellmann

    I hope you’re fine with it when I steal the PNG File. No after effects skills here! :)

  • Matt (Minopolis)

    This is the same technique YouTube used to animate the logo during rewind btw. (They changed the image position with JS though)
    Close the wayback machine’s header and inspect the youtube logo to see it.

  • Boba Fett

    Amazing. Works for me. Can’t wait till the next assignment!

  • Олег Сергеев


  • John Golt

    Thanks for the great article! Where do you find these wonderful sites for inspiration?

    • Gregory Zancanaro Carniel

      Sevenhills was featured on :D

  • skyriam

    Is there a way to control the playback of the sprite? I want to do something similar, an ink bleed but from bottom to top, controlled by the user’s scroll position.

  • Kelpie

    Is it possible to make it open more than just one modal, i.e. from different links on the same page?

    • Arvind Vel

      Did you get the answer

  • Savion Terrance Smith

    Would also love to see if there was a way to add multiple links with different modules

  • Stephan de Vries

    Where did you get the original video from though? What if I want to change the color?

    • Sebastiano Guerriero

      you can open the ink.png file in Photoshop anche use blending options to add a color overlay to the ink effect

  • Last Day

  • Stephan de Vries

    Extremely glitchy in Opera.

    • Claudia Romano

      Hi Stephan, just tested it in Opera 36.0 (on Mac) and it’s working perfectly fine. Are you having this issue with our demo or a local version? Which version are you using? Thanks

  • Jason

    Nice, but not worth it.

  • Chris Three

    Hi, Do you have an example of the page transition version?

  • suresok

    Is there a way to combine it with bootstrap. When I’m using bootstrap the image modal-bg.jpg will not show up and I get a white background. If I delete bootstrap.css everything works fine.
    Anyone know how to fix this?

  • Seth Wieder

    For advanced users, you can use to automate the sprite creation process.

  • Soufiane Abid

    Thanks you miss :D

  • Kenjirou

    What syntax theme are you using in your code examples? It’s awesome!

  • Pierre

    Hi. Have anyone got this to work with multiple modals? I know the question has been asked before but no answer yet. :)

  • Diego

    Hi, I have started learning JS and i did a version in pure js.

    (function modal(){
    var modalClick = document.getElementById(‘cd-modal-trigger’);
    var modalClose = document.getElementById(‘modal-close’);
    var transition = document.getElementById(‘cd-transition-layer’);
    var modalWindow = document.getElementById(‘cd-modal’);

    modalClick.addEventListener(‘click’, function() {

    // var delay = document.setAttribute(‘class’, ‘no-cssanimations’).length > 0 ) ? 0 : 600;
    modalWindow.setAttribute(‘class’, ‘cd-modal visible’);
    document.getElementById(‘cd-modal’).setAttribute(‘class’, ‘cd-modal visible’);
    }, 600);

    transition.setAttribute(‘class’, ‘cd-transition-layer visible opening’);

    modalClose.addEventListener(‘click’, function() {

    modalWindow.setAttribute(‘class’, ‘cd-modal’);

    transition.setAttribute(‘class’, ‘cd-transition-layer visible closing’);
    transition.removeAttribute(‘class’, ‘visible closing’);
    }, 1000);


    • Sacharias Sjöqvist

      Hi Diego! I like the structured of your code and want to do something similar in JS, how did you learn JS? Do you have some recommendations of resources?

  • Sylvain Prevost

    Thanks for this, i’ll to reproduce dogstudio page transition effects this week end :p

  • Justin Wilson

    This should be the most you emulate from this design/dev agency (Immersive Garden). Every one of their projects bloat the page over 10-20MB and load incredibly slow on modern browsers. While it’s flashy and cool, most of their interactive experiences are really impractical, which is unfortunate…

  • iew

    Hi, does anyone know how to do this transition between two different pages?
    Thank you.

    • Dave Stockley
    • Nnatt BV

      Hi, I make the possible solution.
      Please change the code:
      modalTrigger.on(‘click’, function(event){
      var url = || event.srcElement.href;
      transitionLayer.addClass(‘visible opening’);
      var delay = ( $(‘.no-cssanimations’).length > 0 ) ? 0 : 600;
      setTimeout(function(){, “_self”);
      }, delay);
      href=”porfolio.html” class=”cd-btn cd-modal-trigger”>Portfolio

  • Drakan

    It’s nice effect, but it’s not the effect I saw on other websites. I mean, right now it’s just nice ink animation that goes from different color, to background color. And then the real content is showing up. But how to achieve true ink animation that goes from a color to real content (some background image for example). Like it is here: (when You go from page to page for example)

  • Fewzi RAFFED

    Hi, I would like to use this effect between two pages in a wordpress theme. Do you know how can I do that?
    Thanks in advance

    • Kevin Huddy

      You simply have to add this transition effect at the start of a loading page when coming from another page of your website.

  • Olivier Wenders

    Can someone explain why requestAnimationFrame() is necessary ? And resize = true ?
    Why not only:

    $(window).on(‘resize’, function() {
    Thanks in advance.

  • Nik Christodoulakis

    I have got a question to you Claudia, I would like create the same kinda animation but stop just on the central splash (only one splash to be visible). I cannot really understand how to do such would it be easy for you to give me a hint?

  • Karyl Lamoureux

    Did someone is how to put several modal on the same page ?