CSS Mask Icons

Create an accessible, flexible system that allows an icon to have its color customized for use in a variety of instances. Each icon is a single SVG file, allowing it to be easily managed.

Demo

HTML

The markup is an unordered list with a class to target its styling, and contains anchors that also have a class to display the appropriate icon. The anchor also contains descriptive text that will be read aloud by screen readers.

<ul class="social">
	<li>
		<a href="#link-to-facebook" class="social__facebook">Visit our Facebook Page</a>
	</li>
	<li>
		<a href="#link-to-instagram" class="social__instagram">Visit our Instagram Page</a>
	</li>
	<li>
		<a href="#link-to-pinterest" class="social__pinterest">Visit our Pinterest Page</a>
	</li>
	<li>
		<a href="#link-to-twitter" class="social__twitter">Visit our Twitter Page</a>
	</li>
	<li>
		<a href="#link-to-youtube" class="social__youtube">Visit our YouTube Page</a>
	</li>
</ul>

CSS

The unordered list uses CSS Flexbox to align the list items horizontally, and the icon is set up using the ::before Pseudo-element and set to the minimum touch target size of 44x44. While we could have defined the icon as a background image of the anchor, the CSS Mask would have prevented the :focus ring from being displayed, which is an unacceptable outcome.

Since IE 11 doesn't support CSS Masks, the @supports CSS at-rule is used to the define the enhanced styling for browsers that support mask-image. This approach allows IE 11 to still display the default color of the icon that's defined in the SVG, and it should be noted that the -webkit prefix is required for modern browsers, aside from Firefox.

To avoid the unnecessary duplication of defining the URL of the icon in multiple places, the URL is set up as a CSS Variable and allows it to be managed in a single place.

.social {
	display: flex;
	flex-wrap: wrap;
	margin-left: 0;
}
.social	a {
	display: block;
	font-size: 0;
	overflow: hidden;
	text-indent: 100%;
}
.social	a::before {
	background-image: var(--url);
	background-position: center center;
	background-repeat: no-repeat;
	display: block;
	content: '';
	height: 44px;
	width: 44px;
}
.social__facebook::before {
	--url: url(/img/icons/facebook.svg);
}
.social__instagram::before {
	--url: url(/img/icons/instagram.svg);
}
.social__pinterest::before {
	--url: url(/img/icons/pinterest.svg);
}
.social__twitter::before {
	--url: url(/img/icons/twitter.svg);
}
.social__youtube::before {
	--url: url(/img/icons/youtube.svg);
}

.social a:focus {
	box-shadow: inset 0px 0px 3px 1px firebrick;
	border-radius: 50%;
	outline: none;
}

@supports (mask-image: url()) or (-webkit-mask-image: url()) {
	.social a::before {
		background-color: black;
		background-image: none;
		-webkit-mask-image: var(--url);
		-webkit-mask-position: center center;
		-webkit-mask-repeat: no-repeat;
		mask-image: var(--url);
		mask-position: center center;
		mask-repeat: no-repeat;
		transition: all 300ms ease-in-out;
	}
	.social a:focus::before,
	.social a:hover::before {
		background-color: firebrick;
	}
}

Browser Support