Providing accessible SVG social menus in WordPress

Sami Keijonen, owner of a theme and plugin shop called Foxland, posed the following question on Twitter yesterday:

Sami is referring to a technique outlined here by Justin Tadlock, and one that I’m familiar with because there’s a social icon menu location in Adaline.

I quickly got to work on a technique that would allow theme developers to inject relevant SVG icon code based on the URLs users input in the WordPress menu system to known social networking sites.

tl;dr: Check out the Social Menu Theme repo too see how to do it. And be wary of using this technique in a publicly released theme. Considering current browser support for styling SVGs with CSS (or lack there of), it’s unavoidably messy.

Why use SVGs for social menus?

Icon fonts are sufficient for most social menus. But SVGs offer unparalleled flexibility when it comes to code-based image manipulation.

With icon fonts, you can pretty much just change the fill color, and not much else.

SVGs also offer the opportunity to add ARIA labels and other accessibility features which can better describe the icon imagery to screen readers.

This post will quickly recap the icon font method of making WordPress social link menus, and show how to alter it slightly to allow for inline SVG instead.

Icon Font Method Refresher

The SVG method will be closely based on the icon font way of doing things, so let’s go over how to make a WordPress social menu with an icon font first.

Step 1: Register a menu location

Just like you normally would in functions.php. Users will select this menu location when they want a social link menu to display instead of a normal list of links.

If you’d like to follow along with my reduced test case theme, your functions.php file should look like this with (essentially) blank index.php and style.css files at this point.

Step 2: Output the menu location

We’re going to place this in our previously blank index.php file, along with some super basic HTML to prevent the W3C validator from spitting out errors.

Optionally, you can wrap the text with a screen-reader-text class to make sure that the anchor text is visible to screen readers only.

We’ll grab that CSS from the Underscores theme, as seen in our updated style.css file.

We’ll also need to enqueue the stylesheet, and add some other basic WordPress theme hooks and functions. Here is our reduced test case theme after step 2 is complete.

Step 3: Enqueue an icon font

At this point, people not using screen readers will see an empty list, because the link text is visible to screen readers only. To remedy this, we need to pull in an icon font.

I’ll use Font Awesome because it has a gigantic selection of social icons, but Genericons is also a good choice if you just need the basics.

Add the following in within your existing script enqueue function to include Font Awesome.

wp_enqueue_style( 'font-awesome', '//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css' );

Note: Don’t use CDN references in themes you submit to the WordPress.org repository. This is just a crude example.

This is what our functions.php file should look like now. All other files are unchanged in this step.

Step 4: Style links to known social networking websites

For example purposes, we’ll just anticipate Facebook and Twitter links being added to the menu, and use a generic share icon for everything else.

Considering the container class we set in step 2, let’s add the following CSS to our stylesheet.

.social-icon-font a {
	text-decoration: none;
}

.social-icon-font a:before {
	content: "\f1e0";
	font-family: FontAwesome;
}

.social-icon-font a[href*='facebook.com']:before {
    content: '\f230';
}

.social-icon-font a[href*='twitter.com']:before {
    content: '\f099';
}

The value of each content property corresponds with the respective Unicode for each icon.

For example, Twitter is f099. You just have to precede it with a forward slash so the browser doesn’t think that literally “f099” is the value.

Cerauno is a free real life example of a theme that uses this technique.

Adapting for SVG-based icons

We’ll keep all the work we did in steps 1-3, but after that the icon font method and the SVG method begin to diverge.

Set up jQuery Selectors

Instead of using CSS to target links to known social networks, we’ll use jQuery instead (with similar URL-based selectors) so we can prepend the relevant SVG code.

So enqueue jQuery if you haven’t already, and a script with the following in it to get started:

jQuery(function() {
	jQuery('.social-svg a[href*="facebook.com"]').prepend('Facebook SVG here');
	jQuery('.social-svg a[href*="twitter.com"]').prepend('Twitter SVG here');
});

We’ll also register a new menu location and output it, just like we did for the icon step, for our reduced test case theme.

This is what we have so far.

If you’re following along on your own install, make sure to check off the newly registered “Social SVG” menu location for your already existing Twitter and Facebook menu.

Use actual SVG code instead of placeholders

We’ll replace the “SVG code here” type text with *drumroll* the raw SVG code for the relevant social icon as found in this clutch GitHub repo.

Your main.js file should look like this now:

jQuery(function() {
	jQuery('.social-svg a[href*="facebook.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1376 128q119 0 203.5 84.5t84.5 203.5v960q0 119-84.5 203.5t-203.5 84.5h-188v-595h199l30-232h-229v-148q0-56 23.5-84t91.5-28l122-1v-207q-63-9-178-9-136 0-217.5 80t-81.5 226v171h-200v232h200v595h-532q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960z"/></svg>');
	jQuery('.social-svg a[href*="twitter.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1684 408q-67 98-162 167 1 14 1 42 0 130-38 259.5t-115.5 248.5-184.5 210.5-258 146-323 54.5q-271 0-496-145 35 4 78 4 225 0 401-138-105-2-188-64.5t-114-159.5q33 5 61 5 43 0 85-11-112-23-185.5-111.5t-73.5-205.5v-4q68 38 146 41-66-44-105-115t-39-154q0-88 44-163 121 149 294.5 238.5t371.5 99.5q-8-38-8-74 0-134 94.5-228.5t228.5-94.5q140 0 236 102 109-21 205-78-37 115-142 178 93-10 186-50z"/></svg>');
});

We’ll also add some CSS rules to constrain the SVG sizes so they’re not gigantic. For some reason, that repo’s SVGs declare a height and width of 1792 pixels.

.social-svg svg {
	height: auto;
	max-width: 50px;
}

This is what we have so far.

Give SVGs a gradient fill

One of the primary reasons to use an inline SVG over an icon font is the previously mentioned flexibility when it comes to manipulating the image.

Let’s flex our SVG manipulating muscles by adding a simple linear gradient fill.

Unfortunately, this means adding more code within the SVGs in your JavaScript file, including the color codes. For this reason alone, I would avoid using this technique in publicly released themes.

If we replace our main.js file with the following, we’ll have subtle gradients based on the official brand colors each social network.

jQuery(function() {
	jQuery('.social-svg a[href*="facebook.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="FacebookGradient"><stop offset="5%" stop-color="#3b5998" /><stop offset="95%" stop-color="#627AAD" /></linearGradient></defs><path fill="url(#FacebookGradient)" d="M1376 128q119 0 203.5 84.5t84.5 203.5v960q0 119-84.5 203.5t-203.5 84.5h-188v-595h199l30-232h-229v-148q0-56 23.5-84t91.5-28l122-1v-207q-63-9-178-9-136 0-217.5 80t-81.5 226v171h-200v232h200v595h-532q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960z"/></svg>');
	jQuery('.social-svg a[href*="twitter.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="TwitterGradient"><stop offset="5%" stop-color="#3cf" /><stop offset="95%" stop-color="#0084B4" /></linearGradient></defs><path fill="url(#TwitterGradient)" d="M1684 408q-67 98-162 167 1 14 1 42 0 130-38 259.5t-115.5 248.5-184.5 210.5-258 146-323 54.5q-271 0-496-145 35 4 78 4 225 0 401-138-105-2-188-64.5t-114-159.5q33 5 61 5 43 0 85-11-112-23-185.5-111.5t-73.5-205.5v-4q68 38 146 41-66-44-105-115t-39-154q0-88 44-163 121 149 294.5 238.5t371.5 99.5q-8-38-8-74 0-134 94.5-228.5t228.5-94.5q140 0 236 102 109-21 205-78-37 115-142 178 93-10 186-50z"/></svg>');
});

You’ll notice a new defs tag within each SVG, and a fill attribute referencing it on the respective path element.

Make SVGs more ARIA-friendly

At this point, I’m super grossed out by having to declare gradient colors inside of HTML inside of a JS file, but there is a silver lining for accessibility proponents.

Another advantage of using inline SVGs is the ability to add ARIA labels to make it more descriptive and friendly to screen readers.

To wrap up, we’ll add a title and description as recommended by the Tips for Creating Accessible SVG on SitePoint.

Your main.js file should now look like this:

jQuery(function() {
	jQuery('.social-svg a[href*="facebook.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" aria-labelledby="FacebookTitle FacebookDesc"><title id="FacebookTitle">Facebook Icon</title><desc id="FacebookDesc">A Facebook logo with a horizontal linear gradient from a bluish purple color to a subtly lighter bluish purple color.</desc><defs><linearGradient id="FacebookGradient"><stop offset="5%" stop-color="#3b5998" /><stop offset="95%" stop-color="#627AAD" /></linearGradient></defs><path fill="url(#FacebookGradient)" d="M1376 128q119 0 203.5 84.5t84.5 203.5v960q0 119-84.5 203.5t-203.5 84.5h-188v-595h199l30-232h-229v-148q0-56 23.5-84t91.5-28l122-1v-207q-63-9-178-9-136 0-217.5 80t-81.5 226v171h-200v232h200v595h-532q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960z"/></svg>');
	jQuery('.social-svg a[href*="twitter.com"]').prepend('<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" aria-labelledby="TwitterTitle TwitterDesc"><title id="TwitterTitle">Twitter Icon</title><desc id="TwitterDesc">A Twitter bird logo with a horizontal linear gradient from a sky blue color to a subtly lighter sky blue color.</desc><defs><linearGradient id="TwitterGradient"><stop offset="5%" stop-color="#3cf" /><stop offset="95%" stop-color="#0084B4" /></linearGradient></defs><path fill="url(#TwitterGradient)" d="M1684 408q-67 98-162 167 1 14 1 42 0 130-38 259.5t-115.5 248.5-184.5 210.5-258 146-323 54.5q-271 0-496-145 35 4 78 4 225 0 401-138-105-2-188-64.5t-114-159.5q33 5 61 5 43 0 85-11-112-23-185.5-111.5t-73.5-205.5v-4q68 38 146 41-66-44-105-115t-39-154q0-88 44-163 121 149 294.5 238.5t371.5 99.5q-8-38-8-74 0-134 94.5-228.5t228.5-94.5q140 0 236 102 109-21 205-78-37 115-142 178 93-10 186-50z"/></svg>');
});

Please check the Social Menu Theme repo for a complete version of all the above code.

Update: Sami, who originally inspired this post, released his own take on SVG social menus. I believe his idea of using a custom walker or template part will be a bit more performant than my idea of stuffing the entire SVG into a jQuery prepend. Definitely check it out if you’re interested in learning more about SVG social menus.

Update #2: Sami also wrote more about this in a blog post: SVG Social Menu in WordPress.

2 comments

  1. I think using jQuery for inserting raw SVG is not a good idea. It’s hard to maintain and affects the performance of the web (as the job is done by JavaScript). I’m wondering if that can be done by filtering the output of the menu and add code for SVG.

Leave a Reply

Your email address will not be published. Required fields are marked *