Loading CSS mid-page, HTML5, WordPress & Passing Validation Part 2

With HTML5 it’s possible to declare CSS stylesheet inside the body tag. This gives WordPress developers a better solution for including CSS on the fly, such as via a shortcode. It instantly makes several workarounds redundant. The native WordPress function wp_enqueue_style can now be called mid-page, which will print a stylesheet in the footer. Two disadvantages arise from this method and here is an alternative solution that solves it.

In part 1 we learned that

<link>

elements inside the body tag don’t validate at the moment. While browsers handle them just fine, it’s always nice to pass validation without errors. An alternative to this was to alter the output and use the style tag with the new scoped attribute instead. Then, the code will show up valid like:

<style scoped>@import url(stylesheet.css); </style>

The second disadvantage is that our CSS now loads at the end of the page, after the content we want to style. This may cause some styling issues during pageload. Since we can load the CSS anywhere inside the body tag, there is no real reason why it needs to be printed in the footer. If we do that, we also limit the styling issues on pageload.

We can write a function that prints the stylesheet declaration immediately. Let’s say you have a shortcode that inserts a slider, your shortcode would include a special function that prints the CSS before the rest of the slider output. The easy way would be simply to write a function that outputs the required html directly and this is what many developers tend to do. WordPress has specific ways of dealing with styles and scripts to help reduce conflicts and redundancies, so it is important we take advantage of that. So what we are going to do is tap into the API WordPress uses.

The first step is to register your CSS stylesheet with wp_register_style by wrapping it into a function and loading it into the wp_enqueue_scripts hook. Here is an example where we are including the Media Element Player.
<pre>
function register_mediaelementjs() {
wp_register_script( ‘mediaelementjs’, get_bloginfo(‘template_url’).’/inc/mediaelementjs/mediaelement-and-player.js’, array(‘jquery’), ‘2.6.3’, true );
wp_register_style( ‘mediaelementjs’, get_bloginfo(‘template_url’).’/inc/mediaelementjs/mediaelementplayer.css’ );
}
add_action( ‘wp_enqueue_scripts’ , ‘register_mediaelementjs’ );

Next we want to make a function that runs through the styles API. In other words, we want to check if our style has been registered (this is important because a user might decide to deregister your style) and hasn’t been printed already. We also have to make sure that WP knows we printed the style to avoid duplication.

function print_inline_stylesheet( $handle ) {
	// continue only if the style has been registered and hasn't been printed yet. 
	if ( wp_style_is( $handle, 'registered') && ! wp_style_is( $handle, 'done' ) ) {
		// gain access the wp_styles object 
		global $wp_styles;
		// make sure the style is formatted with html 5 markup
		add_filter( 'style_loader_tag', 'html5_inline_stylesheet', 10, 2 );
		$print = $wp_styles->do_item( $handle );
		// set this style to 'done' status
		$wp_styles->done[] = $handle;
		// remove from to do just in case the style was invoked elsewhere for the footer.
		$to_do = $wp_styles ->to_do;
		if ( is_array( $to_do ) ) {
			foreach( $to_do as $key => $to_do_handle ) {
				if( $to_do_handle == $handle ) {
					unset( $wp_styles->to_do[$key] );
				}
			}
		}
	}	
}

If you are outputting functionality via a shortcode you will want to call print_inline_stylesheet before your output. The handle argument needs to be passed to it and coincide with the handle you passed to register_style for your stylesheet. All that is left here is our function for modifying the standard WordPress output.

function html5_inline_stylesheet( $output ) {
	$url = preg_match("/(href=')(.+)(' type)/", $output, $styleurl);
	$output = '<style scoped>@import url('.$styleurl[2].');</style>';
	return $output;
}

Notes:
– I haven’t tested this with CSS stylesheet dependencies – the code may need some alterations for that.
– If you are including the functions in your project, remember to add a prefix unique to your theme or plugin in front of all the functions.
– I haven’t tested this is in all browsers, but from what I’ve researched this should work universally.
– HTML5 is still in a working draft, the scoped attribute hasn’t been set in stone – it’s possible things may change.
– To validate, you need to make sure the validator is set to HTML5.

If you have thoughts on improving this solution or the code, please leave some feedback below!

UPDATE 5/05/2013
For copy pasters, in the above example I used Media Element JS which is now shipped by default with WP 3.6+. While the example was for demonstration purposes, if you are using media element js, don’t enqueue your own version, load the one that ships with WP.

One comment

Leave a Reply

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