Add Customizer Color Pickers for Hover Styles Without Refreshing the Preview Window

If you’ve ever used the WordPress color picker control in the customizer to alter colors relating to hover styles then you may have noticed the user experience isn’t ideal. Surely there’s a better way?

Let’s say that you want to implement a color picker in the WordPress customizer to change link colors when hovered over. There are plenty of tutorials to show you how to do this but the chances are that the preview window is required to do a full page refresh before you can access the new hover color!

The WordPress customizer supports two methods for updating the preview window whenever a control has been changed: real-time (preferred), or page refresh. We want to make our color pickers that control hover styles update the preview window in real-time.

Before we do this let’s see why hover colors are typically implemented via the refresh method. Check out the code below which is used to implement non-hover color changes in real-time.

  • I won’t be explaining the customizer code in detail as it has been covered in other tutorials. If you’re new to the WordPress customizer I’d recommend viewing the official docs.

add_action( 'customize_register', 'cph_customize_register' );
function cph_customize_register($wp_customize) {

	$wp_customize->add_setting( 'link-color', array(
		'default'        => '#555',
		'type'           => 'theme_mod',
		'transport'      => 'postMessage',
		'capability'     => 'edit_theme_options',
	) );

	$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link-color', array(
		'label'   => __( 'Link Color' ),
		'section' => 'colors',
		'settings'   => 'link-color',
	) ) );

	if ( $wp_customize->is_preview() && ! is_admin() )
		add_action( 'wp_footer', 'cph_customize_preview', 21);
}

Here, we’re simply registering a standard WordPress color picker control that’s tied to a setting to store the color picker value.

Notice that the transport type is set to postMessage which means changes to the color picker will instantly trigger changes in the preview window. To make that actually happen we need to add some JavaScript.

if ( $wp_customize->is_preview() && ! is_admin() )
	add_action( 'wp_footer', 'cph_customize_preview', 21);

When this code is encountered and we’re viewing the WordPress customizer then the cph_customize_preview() callback function is fired. This is where we’ll add our custom JavaScript.

function cph_customize_preview() {
    ?>
    <script type="text/javascript">
    ( function( $ ){
		wp.customize('link-color',function( value ) {
			value.bind(function(to) {
				$('a').css('color', to ? to : '' );
			});
		});
	} )( jQuery )
    </script>
    <?php 
}

This will instantly trigger changes in the preview window when the color picker value is updated. It works by applying CSS directly inline to the relevant element(s) overriding every other CSS definition. This is the standard way to implement color pickers that update the preview window in real-time.

However, this method does NOT work for hover colors! Let’s find out why now.

The key to this is the way we’re using JavaScript to apply the color in real-time. Because we’re basically adding inline styles via JavaScript this won’t work for hover styles because they belong to a set of classes called CSS pseudo classes. Unfortunately you can’t define these inline as you can with most other CSS styles. They just won’t work!

Therefore, you can’t define an equivalent inline version of the following CSS:

a:hover { color: red; }

This means you can’t use the traditional approach for implementing real-time changes to hover styles via color pickers. What are we to do?

Fortunately there is a solution which works nicely. Let’s run through the code to add a hover color picker that updates in real-time.

add_action( 'customize_register', 'cph_customize_register' );
function cph_customize_register($wp_customize) {

	$wp_customize->add_setting( 'link-hover-color', array(
		'default'        => '#777',
		'type'           => 'theme_mod',
		'transport'      => 'postMessage',
		'capability'     => 'edit_theme_options',
	) );
	$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link-hover-color', array(
		'label'   => __( 'Link Color (hover)' ),
		'section' => 'colors',
		'settings'   => 'link-hover-color',
	) ) );

	if ( $wp_customize->is_preview() && ! is_admin() )
		add_action( 'wp_footer', 'cph_customize_preview', 21);
}

First we add the color picker control for our hover color. The code is almost identical to last time. Now let’s add the custom JavaScript to update the hover color in real-time.

function cph_customize_preview() {
    ?>
    <script type="text/javascript">
    ( function( $ ){

		wp.customize( 'link-hover-color', function( value ) {
			value.bind( function( to ) {

				var style, el;

				style = '<style class="hover-styles">a:hover { color: ' + to + '; }</style>'; // build the style element
				el =  $( '.hover-styles' ); // look for a matching style element that might already be there

				// add the style element into the DOM or replace the matching style element that is already there
				if ( el.length ) {
					el.replaceWith( style ); // style element already exists, so replace it
				} else {
					$( 'head' ).append( style ); // style element doesn't exist so add it
				}
			} );
		} );
	} )( jQuery )
    </script>
    <?php 
}

This is different from the usual implementation. This time, a specific style element is created in the DOM for each hover color. As you change the color with the color picker the style element is continuously replaced with an updated version containing the new color.

So, instead of changing the CSS inline directly on the HTML element we’re adding them to a style element which means we can use the full range of pseudo classes!

Here is the full code listing, wrapped up in a plugin, which includes adding the hover color style to the site header outside of the customizer:

<?php
/*
Plugin Name: Color Picker Hover
Description: A new way to implement a color picker for hover styles the does not require the preview window to be refreshed.
Version: 0.1
Author: David Gwyer
Author URI: http://www.wpgothemes.com
*/

/*  Copyright 2009 David Gwyer (email : david@wpgothemes.com)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

add_action( 'customize_register', 'cph_customize_register' );
add_action( 'wp_head', 'cph_add_css' );

function cph_customize_register($wp_customize) {

	$wp_customize->add_setting( 'link-hover-color', array(
		'default'        => '#777',
		'type'           => 'theme_mod',
		'transport'      => 'postMessage',
		'capability'     => 'edit_theme_options',
	) );

	$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link-hover-color', array(
		'label'   => __( 'Link Color (hover)' ),
		'section' => 'colors',
		'settings'   => 'link-hover-color',
	) ) );

	if ( $wp_customize->is_preview() && ! is_admin() )
		add_action( 'wp_footer', 'cph_customize_preview', 21);
}

function cph_customize_preview() {
    ?>
    <script type="text/javascript">
    ( function( $ ){

		wp.customize( 'link-hover-color', function( value ) {
			value.bind( function( to ) {

				var style, el;

				// build the style element
				style = '<style class="hover-styles">a:hover { color: ' + to + '; }</style>';

				// look for a matching style element that might already be there
				el =  $( '.hover-styles' );

				// add the style element into the DOM or replace the matching style element that is already there
				if ( el.length ) {
					el.replaceWith( style ); // style element already exists, so replace it
				} else {
					$( 'head' ).append( style ); // style element doesn't exist so add it
				}
			} );
		} );
	} )( jQuery )
    </script>
    <?php 
}

function cph_add_css() {

	$value = get_theme_mod( 'link-hover-color' );
	echo '<style type="text/css">a:hover { color: ' . $value . '; }</style>';
}

There is one caveat which is that this won’t work so well in Internet Explorer 8 and below because there’s a browser limit for the amount of style sheets per document, and each individual style element counts as one style sheet. There isn’t any known issues for all modern browsers though.

It would be preferable to add all the color picker code to one style element, and therefore remove the style sheet limit for older browsers but this is a pretty nice solution if you want your hover styles to work in real-time in the WordPress customizer.

Our WordPress theme Minn uses this method for all color pickers that control hover styles. We also implemented a custom color picker control to add multiple color pickers in a compact space. The end result is a much more seamless user experience.

Multi Color Picker

Thanks to Braad Martin for coming up with a solution to this problem from my initial idea.

About David Gwyer

Founder of WPGO themes and lead developer. I love creating themes that are intuitive and easy to use but deceptively powerful! I also enjoy tinkering around with plugins.

Leave a Reply

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