Saptak's Blog Posts

CSS Masking: Mask of Batman

Posted: 2018-01-04T13:23:00+05:30
Recently, I have been watching videos on CSS to know more about the various interesting features in CSS such as grid layout, flex, filter and so on. After all, it is one of the Turing Complete languages. One way I like to learn more about languages is by watching conference talks. So, I was going through the different talks in CSSConf 2015 when I came across this talk by Tim Holman titled Fun.css. It is a really fun talk but one thing that really caught my eyes was the transition between slides using a star wipe. I searched to see if I could find the code for how to do it with purely CSS but didn't get much help. This is when I decided to give it a try myself. But why Star? I would make a Bat Swipe.

So this is the final prototype I made using just CSS without any Javascript.


See the Pen Bat Swipe by Saptak Sengupta (@SaptakS) on CodePen.

The main CSS property that is used in the above example is mask-image and associated CSS Masking properties. What masking does is hiding parts of the visual section of the webpage by the mask layer. there are two ways of masking - CSS or SVG. So you can either use a CSS gradient or luminance to create a mask, or use an SVG image. In our example, we are going to take about how to use SVG.

<div class="content">
<p>Hover</p>
</div>
<div class="wipe">
<div class="content black">
<p>I am Batman!</p>
</div>
</div>

So, in the HTML code we basically have 2 layers. To create that, I made a <div class="content"> with the actual content inside a <div class="wipe">. So the text of the class "content" must remain hidden until the wipe class reveals the content.

Now it's time to implement the CSS code to make this thing happen.
.wipe {
mask-image: url(https://vignette.wikia.nocookie.net/logopedia/images/3/3c/Batman_symbol_%282008-2011%29.svg);
mask-repeat: no-repeat;
mask-position: 50% 50%;
mask-size: 0;
}

The above CSS code applies the mask over the content class so that only a part of the content is visible. Here we use mask-image which is a link to the SVG image which we want to use as our mask. Since it's a Bat Swipe, I have used the logo of Batman. You can use pretty much use any SVG image but I would suggest that you use a filled SVG image rather than line art. This is because the SVG masking uses the alpha factor of the image. Say in our case, since the Batman logo is a filled black image on top of a white background, so when we apply it as a mask, the visual area behind the black part of the image is visible, and the area behind white part gets masked or hidden.

The CSS properties mask-repeat and mask-position are used to ensure that there is only one mask no matter whatever the size of the mask and it stays always in the middle. You can modify these parameters based on your use case. Say, you wanted a polka dot mask style, you would want then want to have a black disk mask-image and mask-repeat as "repeat".

The CSS property mask-size is most important in our case to create the effect of swipe or reveal. By now, most of you must have already guessed that to get the effect, what we essentially need to do is increase the size of the image with time. I have done the entire animation of swiping on hover because it is the easiest way to display a transition with only CSS.

So at the beginning, we keep the mask-size as 0 and then we add a pseudo hover property to increase the mask-size to 500% (enough to cover the entire page over most resolutions) with a transition.

.wipe:hover {
mask-size: 500%;
transition: 3s;
}

We apply a transition over 3s using the CSS transition property. So, if you would like a really slow animation instead of a swiping action you can just increase the value of transition property so that the transition of size happens over a longer duration of time.

The only last thing remaining is cross-browser compatibility. So will this code work in all browsers? Sadly, no. As of now, the mask-image and associated CSS properties are fully supported only in Firefox since version 53. However, you can make it work in Google Chrome, Opera and Safari using the prefix "-webkit-". So if you add -webkit-mask-image property as well, then it starts working in chrome and safari as well. Sadly, IE, Edge and Opera Mini doesn't provide any kind of support.