February 15, 2017 | 11 Feedbacks

Image Mask Effect

An immersive transition effect powered by image masks and CSS transforms.
Browser support
  • ie
  • Chrome
  • Firefox
  • Safari
  • Opera

We’ve been publishing in our library some nice mask effects powered by SVG properties. This time we took advantage of the PNG transparencies to zoom through the mask layer, into a project background image.

If you want to change the color of the .png masks, you can easily do it in Photoshop (or any other graphic tool) by applying a color overlay to the whole image layer. If you plan to create your own masks, please note that this effect works only if there’s an empty space in the very center of the mask.

Inspiration: Offsite Homepage Animation by Hrvoje Grubisic.

Images: Unsplash

Creating the structure

The HTML structure is composed of a list of <section>s wrapped in a .cd-image-mask-effect element. Each <section> contains a div.featured-image (project image), a div.mask (image mask) and a for the project content.

The project content is not included in the HTML but is loaded using JavaScript.

Adding style

Each .cd-project-mask has a height of 100vh (viewport height) and a width of 100%; the project image is set as background-image of the .featured-image element, while the mask image is wrapped inside the .mask element.
Four .mask-border elements have been used to create a frame around the image mask to make sure the project featured image is not visible outside the mask (we used <span> elements rather than pseudo elements because their behaviour was buggy on Safari 9).

When the user selects a project, the class .project-view (added to the wrapper .cd-image-mask-effect) is used to hide all the other projects.
The .mask element is then scaled up to reveal the project featured image and the project content is loaded (more in the Events handling section).

Events handling

To implement this image mask effect, we created a ProjectMask object and used the initProject method to attach the proper event handlers.

When the user selects a project, the revealProject method is used to scale up the mask image while the uploadContent method takes care of loading the project content (using the load() function) and adding the new page to the window.history (using the pushState() method).



Feb 15, 2017
  • 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.

  • Alejandro Gutiérrez Olarte

    Here you ment “.png” right?
    Excellent article!! Greetings!

    • Claudia Romano

      Yes I did! Fixed now ;)

  • Boba Fett

    WOW Caludia. This is a very nice stuff. I don’t think I will be able to replicate it in Weebly. The index file calls another html file and I haven’t been able to figure that thing out yet.

  • SlimSloughi

    Awesome !

  • david cunningham

    super work Claudia. You continue to amaze. Not sure what I’m missing here. I followed through the instructions but when I click on the explore project link nothing happens. Any pointers? Thanks so much. Dave

    • Claudia Romano

      hey Davis, if you are testing this in Chrome then you need a local server for the load() function to work. Hope this helps!

      • Mc Cavandish

        thanks Claudia got it up and running with local server. sorry to be so bothersome but when i make changes to the stylesheet they don’t take effect but obviously it is working as the elements are getting their original styling. does css work differently when running through the local server? thanks again

  • Ajat Sudrajat

    Interesting effect! But you have reason why you don’t use modern properties/techniques (for example SVG masks) but simply PNG images? Putting borders around to hide the rest of the page content seems a bit chunky and not so elegant solution. This looks more like a fallback maybe.

    • Sebastiano Guerriero

      Hi! We’ve been experimenting with SVG masks a lot here on CodyHouse (, but for this kind of effect PNG did seem like the simplest approach.

  • dokMixer

    Super interesting effect !
    Small room for improvement : the way you use pushState is correct, but using the “back” button in the browser doesn’t work. A way to catch the previous/next buttons should be implemented to trigger again the animations :)
    Cheers !

  • Joao Guerreiro

    Looks great Claudia, thanks for sharing!