How to Create a Switch UI Using CSS Mask

In image processing, masking is a technique that allows you to hide an image with another. A mask is used to make a portion of an image see-through. You can perform masking using CSS with the help of masking properties.

In today’s post we’ll create a masked image by using two PNG images and CSS masking techniques, and allow users to handle the two states of the image (day and night) with the help of a switch UI.

Because of some browser-compatibility issues — not all masking properties are supported in every browser (as of June 2016) — I will show two techniques for adding masks, one for Webkit-based browsers, and one for Firefox. The two first steps in this three-step tutorial are the same for every browser, but there will be a difference in the third step.

Step 1. Create A Basic Switch

Since a typical switch has two states with only one enabled at a time, you can use a radio button group of two to create the working components of the switch. Place each radio button at the left and right ends of their parent element.

Radio button groups are created by giving each radio button the same name attribute. In a radio button group, only one radio button can be checked at a time.

I added the opacity:0 rule to the .radio class in order to hide the radio buttons. The last rule in the code block below, cursor: pointer; shows the pointer cursor for the unchecked radio button, so that users know which button to click to toggle the switch state.

Screenshot of the switch UI with radio buttons in the Chrome browser

Step 2. Add Skins to the Switch

In this step, we’ll add two <div> tags for the two skins below the radio buttons in our HTML file, and a background image to each skin in our CSS.

The pointer-events: none; rule is added to the skins so that the click events on the switch can pass through them, and reach the radio buttons.

With the pointer-events CSS property you can set the circumstances under which a graphic element can be targeted by mouse events.

As an alternative for the code above, two <img> tags (with source images) inside the <div> tags can also work. They will be the skins for the two switch states.

Screenshot of switch with skins in chrome

Step 3a. Add Mask (Webkit version)

For Chrome and other Webkit-based browsers, I will use the mask-image CSS property, which — as of the writing of this post — only works with the -webkit prefix in Webkit browsers. The mask-image property lets you specify the image to be used as the mask.

In general, there are two kinds of masking: luminance and alpha.

In luminance masking, the dark portion of the mask image hides the image it is masking: the darker a portion is in the mask image, the more hidden that portion is in the image being masked.

In alpha masking, the transparent portion of the mask image hides the image it is masking: the more transparent a portion is in the mask image, the more hidden that portion is in the image being masked.

In Chrome (as of version 51.0.2704.103, Win10), only alpha seems to currently work.

I used the -webkit-mask-image property to create the initial mask image. Its value uses the radial-gradient() CSS function that’s used to create an image from a pre-defined shape, a radial gradient, and the center of the gradient.

For the night skin, I created a transparent circle, and I made the remaining part of the container opaque. For the day skin, I did the opposite: created an opaque circle with the radial-gradient() function, and made the remaining portion transparent.

Although it’s not yet supported in Webkit browsers, I added the mask-type property to the CSS for future reference.

Screenshot of switch with Night skin selectedScreenshot of switch with Day skin selected

As you can see above, the border of the circle isn’t very smooth. To hide the rough edges, add a <div> after the skins in the shape of a circle (same size as the mask circle) with a box shadow. The shadow will hide the rough edges of the circle mask.

Step 3b. Add Mask (Firefox version)

The mask-image CSS property is actually a longhand property, and it’s part of the shorthand property mask that lets you specify the image to be used as a mask as well. While mask-image isn’t supported in Firefox yet, mask is.

Although the mask property should accept an image created with the radial-gradient() CSS function as a value, just like the mask-image property did, there’s no support for that in Firefox yet.

So, instead of a radial-gradient() image, let’s use an SVG image as the mask image with the mask type luminance.

The SVG image above looks like a combination of a white rectangle and a black circle. Add this, and another one with a black rectangle and a white circle as masks to the HTML we used in the Webkit version.