• Original address: Codrops
  • Original post by Robin Delaporte

Preview online download source code

Today we want to show you how to use CSS Masks to create an interesting transition effect. Similar to clipping, masks are another way to define visibility and composition with elements. In the following tutorial, we will show you how to apply new properties to transition effects in a simple rotation diagram. We’ll use Steps () to time the feature animation and move the mask PNG over the image for interesting transitions.

Note: Keep in mind that this effect is still experimental and only supported by modern browsers (Chrome, Safari and Opera).

CSS Masks

Method of masking part of an element with the selected image

W3C Candidate Recommendation

The following versions are supported:

A desktop application

Mobile applications

Detailed support can be found at caniuse.com

Keep in mind that Firefox only partially supports it (it only supports inline SVG mask elements) so we will have a fallback version. Hopefully CSS Masks will soon be supported by all modern browsers. Please note that we are adding Modernizr to check for support.

Let’s start happily together!

Create a mask image

In this tutorial, we’ll cover the first example (Demo 1).

For the mask transition effect to work, we need an image that hides/shows some part of the underlying image. The mask image will be a PNG with transparent parts. This PNG will be a Sprite image and it will look like this:

The black part will show the current image, but the white part (which is actually transparent) will be the masked part of our image and will show the second image.

To create a Sprite image, we will use this video. We imported it into Adobe After Effects to reduce the time of the video, removed the white portion and exported it as a PNG sequence.

To reduce the duration to 1.4 seconds (the Time we want to convert), we will use the Time Stretch Effect.

To remove the white part, we will use Keying -> extract and set the white point to 0. In the screenshot below, the blue part is our composite background, the transparent part of the video.

Finally, we can save the composited video as a PNG sequence and then use Photoshop or CSS Sprite to generate a single image:

This is a Sprite image with a very consistent look. We will create another “reverse” Sprite for another effect. You will find all the different Sprite images in the IMG folder of the demo file.

Now that we have created the mask image, let’s simply implement the HTML structure of our example multicast diagram.

HTML structure

We will create a simple carousel diagram to show the mask effect. Our carousel will fill the screen, and we’ll add some arrows that will trigger a carousel switch. The idea is to overwrite the wheel plot and then change the z-index of the wheel plot at the end of the animation. The structure of the rotation chart is as follows:

<div class="page-view">
	<div class="project">
		<div class="text"> <h1> "All good things are <br> wild & Free" </h1> <p>Photo by Andreas Rønningen</p> </div> <div class="project">
		<div class="text"> <h1> "Into the wild" </h1> <p>Photo by John Price</p> </div> </div> <div class="project">
		<div class="text"> < h1 > "Is spring" coming?" </h1> <p>Photo by Thomas Lefebvre</p> </div> </div> <div class="project">
		<div class="text"> < H1 > "Stay curious" </ H1 > <p>Photo by Maria</p> </div> </div> <nav class="arrows">
		<div class="arrow previous">
			<svg viewBox="208.3 352 4.2 6.4">
				<polygon class="st0" points="212.1,357.3 211.5,358 208.7,355.1 211.5,352.3 212.1,353 209.9,355.1"/>
			</svg>
		</div>
		<div class="arrow next">
			<svg viewBox="208.3 352 4.2 6.4">
				<polygon class="st0" points="212.1,357.3 211.5,358 208.7,355.1 211.5,352.3 212.1,353 209.9,355.1"/>
			</svg>
		</div>
	</nav>
</div>
Copy the code

The Page View is our global container that will contain all of our projects; Each one contains a title and a legend. In addition, we will set up a separate background image for each carousel.

The arrow acts as a trigger for the next or previous animation and navigates through the wheel cast diagram.

Let’s take a look at the style.

CSS styles

In this section, we will add CSS to our effects.

We’ll set up the layout with some centered headings and navigation at the bottom left of the page. In addition, we will define some media queries for mobile-compatible presentations.

In addition, we set Sprite images as an invisible background in the global container so that we can start loading them when we open the page.

.demo-1 { background: url(.. /img/nature-sprite.png) no-repeat -9999px -9999px; background-size: 0; } .demo-1 .page-view { background: url(.. /img/nature-sprite-2.png) no-repeat -9999px -9999px; background-size: 0; }Copy the code

Each page has a different background image:

.demo-1 .page-view .project:nth-child(1) { background-image: url(.. /img/nature-1.jpg); } .demo-1 .page-view .project:nth-child(2) { background-image: url(.. /img/nature-2.jpg); } .demo-1 .page-view .project:nth-child(3) { background-image: url(.. /img/nature-3.jpg); } .demo-1 .page-view .project:nth-child(4) { background-image: url(.. /img/nature-4.jpg); }Copy the code

This is of course something you’ll implement dynamically, but we’re interested in effects, so let’s keep it simple.

We define a class called Hide, which we can add whenever we want to hide an element. The class definition contains the Sprite diagram that we use as a mask.

Knowing that one frame is 100% of the screen and our animation contains 23 images, we need to set the width to 23 * 100% = 2300%.

Now we add CSS animations using steps. We want our Sprite image to stop at the beginning of the last frame. Therefore, to achieve this goal, we need one step less than the total, namely 22 steps:

.demo-1 .page-view .project:nth-child(even).hide { -webkit-mask: url(.. /img/nature-sprite.png); mask: url(.. /img/nature-sprite.png); -webkit-mask-size: 2300% 100%; mask-size: 2300% 100%; - Webkit-Animation: mask-play 1.4s Steps (22) forward; Animation: Mask-Play 1.4s Steps (22) forward; } .demo-1 .page-view .project:nth-child(odd).hide { -webkit-mask: url(.. /img/nature-sprite-2.png); mask: url(.. /img/nature-sprite-2.png); -webkit-mask-size: 7100% 100%; mask-size: 7100% 100%; - Webkit-Animation: mask-play 1.4s Steps (70) forward; Animation: Mask-Play 1.4s Steps (70) forward; }Copy the code

Finally, we define the animation keyframe:

@-webkit-keyframes mask-play { from { -webkit-mask-position: 0% 0; mask-position: 0% 0; } to { -webkit-mask-position: 100% 0; mask-position: 100% 0; } } @keyframes mask-play { from { -webkit-mask-position: 0% 0; mask-position: 0% 0; } to { -webkit-mask-position: 100% 0; mask-position: 100% 0; }}Copy the code

Now we have the structure and style of the rotation diagram. Let’s add some kinetic effects to it!

JavaScript performance

We’ll do this using Zepto.js, a very lightweight JavaScript framework similar to jQuery.

Start by declaring all variables, setting duration and elements.

Then we initialize the event, get the current and next wheel map, and set the correct Z-index.

function Slider() {
	// Durations
	this.durations = {
		auto: 5000,
		slide: 1400
	};
	// DOM
	this.dom = {
		wrapper: null,
		container: null,
		project: null,
		current: null,
		next: null,
		arrow: null
	};
	// Misc stuff
	this.length = 0;
	this.current = 0;
	this.next = 0;
	this.isAuto = true;
	this.working = false;
	this.dom.wrapper = $('.page-view');
	this.dom.project = this.dom.wrapper.find('.project');
	this.dom.arrow = this.dom.wrapper.find('.arrow');
	this.length = this.dom.project.length;
	this.init();
	this.events();
	this.auto = setInterval(this.updateNext.bind(this), this.durations.auto);
}
/**
 * Set initial z-indexes & get current project
 */
Slider.prototype.init = function () {
	this.dom.project.css('z-index', 10);
	this.dom.current = $(this.dom.project[this.current]);
	this.dom.next = $(this.dom.project[this.current + 1]);
	this.dom.current.css('z-index', 30);
	this.dom.next.css('z-index', 20);
};
Copy the code

We listen for click events on the arrow, and if the current playback diagram does not involve animation, we check to see if the click is on the next or previous arrow. We toggle the rotation chart while adjusting the value of the “next” variable.

/**
 * Initialize events
 */
Slider.prototype.events = function () {
	var self = this;
	this.dom.arrow.on('click'.function () {
		if (self.working)
			return;
		self.processBtn($(this));
	});
};
Slider.prototype.processBtn = function (btn) {
	if (this.isAuto) {
		this.isAuto = false;
		clearInterval(this.auto);
	}
	if (btn.hasClass('next'))
		this.updateNext();
	if (btn.hasClass('previous'))
		this.updatePrevious();
};
/**
 * Update next global index
 */
Slider.prototype.updateNext = function () {
	this.next = (this.current + 1) % this.length;
	this.process();
};
/**
 * Update next global index
 */
Slider.prototype.updatePrevious = function () {
	this.next--;
	if (this.next < 0)
		this.next = this.length - 1;
	this.process();
};
Copy the code

This function is at the heart of our playlist: we add the class “hide” to the current playlist, and once the animation is over, we decrease the z-index of the previous playlist, add one from the current playlist, and remove the class that hides the previous playlist.

/**
 * Process, calculate and switch between slides
 */
Slider.prototype.process = function () {
	var self = this;
	this.working = true;
	this.dom.next = $(this.dom.project[this.next]);
	this.dom.current.css('z-index', 30);
	self.dom.next.css('z-index', 20);
	// Hide current
	this.dom.current.addClass('hide');
	setTimeout(function () {
		self.dom.current.css('z-index', 10);
		self.dom.next.css('z-index', 30);
		self.dom.current.removeClass('hide');
		self.dom.current = self.dom.next;
		self.current = self.next;
		self.working = false;
	}, this.durations.slide);
};
Copy the code

Adding the appropriate class will trigger our animation, and the mask image will be applied to our rotation diagram. The main idea is to move the mask image in the animation function to create a transition flow.

That’s it! I hope you found this tutorial useful and had fun creating your own cool mask effects! Don’t hesitate to share your creations, I’d love to see them!