Justin Tadlock have invented social nav menu system. Pretty much everybody is using it on public themes because users can create social links using WordPress menu system. And social links can be drag ‘n dropped in any order you want. It is great! Here is a screenshot how it might look like.
But lately (several months) I’ve been thinking can we use SVG icons in Social Menu instead of icon fonts. Leland Fiegel picked up my question in Twitter and rolled his own idea. It’s not bad solution but what if we could do this without Javascript.
I’ll try to explain how and why I’m using social menu with SVG icons. Some WordPress theme works as an demo example and it can be found in Github also.
There is nothing wrong using icon fonts. Just make sure you are using icon fonts in a accessible way. But there are several reasons why SVG images are a little better than icon fonts. CSS Tricks article Inline SVG vs Font Icons explains the differences really well. Comparison included these bullet points:
There are also other articles about SVG vs icon fonts:
I like the summarize on Github article:
By switching from icon fonts, we can serve our icons more easily, more quickly, and more accessibly. And they look better. Enjoy.
I have only used service called Icomoon App. It has it’s own icons but you can also import any icons you want in there. I usually import icons from Genericons or Fontawesome. Great thing about Icomoon App is that you can pick the icons you want, generate SVG code one be one, or download example .zip file which includes SVG sprite file. It’s called symbol-defs.svg. At the moment I manually clean up the file a little bit by removing all titles and fills.
You can also use Gulp tools to generate SVG sprite for you. wd_s starter theme has a perfect example.
In custom projects I also import all icons from designer and let Icomoon App generate the SVG code for me.
There are two main ways to use SVG sprite system.
I both ways we can use helpful function for generating SVG markup. By the way read everything what Sara Soueidan writes about SVG images.
The code below demonstrates how to use inline SVG sprite:
<body> <?php // 1. Include SVG images from assets/images folder right after <body> element. $svg_icons = get_template_directory() . '/assets/images/svg-icons.svg'; require_once( $svg_icons ); // 2. Include for example Twitter icon from SVG sprite. This can be anywhere in your markup. ?> <svg class="icon icon-twitter"> <use xlink:href="#twitter-icon"></use> <svg> <?php // 3. Or even better use function _s_get_svg() found in wd_s to generetate the markup. // @link: https://github.com/WebDevStudios/wd_s/blob/master/inc/template-tags.php#L124 echo _s_get_svg( array( 'icon' => 'twitter' ) );
The problem with inline SVG can be caching. If you have lot’s of icons and they are included in every page after body element, page might render a little bit slower.
If you have only couple of icons in your SVG sprite, I’d still use inline sprite method. Caching can be solved using external SVG sprite.
Using external SVG image is pretty much the same but you don’t need to include SVG icons after body element. And in <use>
-element you reference the external SVG file.
<body> // 2. Include for example Twitter icon from SVG sprite. This can be anywhere in your markup. ?> <svg class="icon icon-twitter"> <use xlink:href="path/to/icons.svg#twitter-icon"></use> <svg> <?php // 3. Or even better use function some_get_svg() found in "Some" to generetate the markup. // @link: https://github.com/samikeijonen/some/blob/master/inc/template-tags.php#L41 echo some_get_svg( array( 'icon' => 'twitter' ) );
There is one big problem in this method also. IE browsers (Edge does) doesn’t support external SVG in <use>
. Luckily there is polyfill called svgxuse and it’s licensed by MIT.
I my tests even Firefox didn’t show external SVG icons without the svgxuse polyfill. Go figure.
We are finally ready to talk about how to use SVG icon in social menu. Let’s start with with social menu markup. It’s the same as in Justin’s tutorial but we’re using rating-full icon (star) as a fallback icon. See the link_after
argument.
<nav class="menu-social social-navigation menu" role="navigation"> <?php wp_nav_menu( array( 'theme_location' => 'social', 'container_class' => 'social-menu-wrapper', 'menu_id' => 'menu-social-items', 'menu_class' => 'menu-social-items', 'depth' => 1, 'link_before' => '<span class="screen-reader-text">', 'link_after' => '</span>' . some_get_svg( array( 'icon' => 'rating-full' ) ), 'fallback_cb' => '', ) ); ?> </nav><!-- .menu-social -->
And finally the most important part. How are we going to replace fallback icon to social icon we support? The magical filter is walker_nav_menu_start_el.
/** * Display SVG icons in social navigation. * * @since 1.0.0 * * @param string $item_output The menu item output. * @param WP_Post $item Menu item object. * @param int $depth Depth of the menu. * @param array $args wp_nav_menu() arguments. * @return string Menu item with possible description. */ function some_nav_social_icons( $item_output, $item, $depth, $args ) { // Supported social icons. $social_icons = apply_filters( 'some_nav_social_icons', array( 'codepen.io' => 'codepen', 'digg.com' => 'digg', 'dribbble.com' => 'dribbble', 'dropbox.com' => 'dropbox', 'facebook.com' => 'facebook', 'flickr.com' => 'flickr', 'foursquare.com' => 'foursquare', 'plus.google.com' => 'googleplus', 'github.com' => 'github', 'instagram.com' => 'instagram', 'linkedin.com' => 'linkedin-alt', 'mailto:' => 'mail', 'pinterest.com' => 'pinterest-alt', 'getpocket.com' => 'pocket', 'polldaddy.com' => 'polldaddy', 'reddit.com' => 'reddit', 'skype.com' => 'skype', 'skype:' => 'skype', 'soundcloud.com' => 'cloud', 'spotify.com' => 'spotify', 'stumbleupon.com' => 'stumbleupon', 'tumblr.com' => 'tumblr', 'twitch.tv' => 'twitch', 'twitter.com' => 'twitter', 'vimeo.com' => 'vimeo', 'wordpress.org' => 'wordpress', 'wordpress.com' => 'wordpress', 'youtube.com' => 'youtube', ) ); // Change SVG icon inside social links menu if there is supported URL. if ( 'social' == $args->theme_location ) { foreach ( $social_icons as $attr => $value ) { if ( false !== strpos( $item_output, $attr ) ) { $item_output = str_replace( $args->link_after, '</span>' . some_get_svg( array( 'icon' => esc_attr( $value ) ) ), $item_output ); } } } return $item_output; } add_filter( 'walker_nav_menu_start_el', 'some_nav_social_icons', 10, 4 );
Edit: Styling and accessibility chapter have been added after the this post was published.
I use these base styles for all icons which are recommended by Icomoon:
.icon { display: inline-block; fill: currentColor; height: 1em; width: 1em; vertical-align: middle; position: relative; /* Align more nicely with capital letters */ top: -0.0625em; }
After that it’s totally up to you and CSS how you want style individual icons. For example changing the size and color in social menu looks like this:
.menu-social .icon { color: #fafafa; /* You can use fill: rule also. */ width: 2em; height: 2em; }
In my some_get_svg() function I use aria-hidden="true"
by default in my SVG markup because in most cases SVG icon in just decorative image. For example generated markup inside social menu look like this:
<a href="https://twitter.com/samikeijonen/">
<span class="screen-reader-text">Follow me on twitter</span>
<svg class="icon icon-twitter" aria-hidden="true">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-twitter"></use>
</svg>
</a>
In 404 page I have experiment where I try to set SVG icon arguments in away that also screen readers could access the icon info.
Uh, that’s it. As mentioned before Some theme works as an example. Play around with the code in Github and let me know if there is better way to do this.