WordPress 5.0 and Gutenberg: A better way to handle CSS overload

As you may know, WordPress 5.0 introduced a new editor experience (for those that haven’t decided to explicitly disable it), and the response has been mostly “ok, cool.” from users, despite the controversial release schedule, and the decision to punt many accessibility and performance issues to subsequent patch releases.

And while I won’t try to overcompensate for the problems that have been pointed out, I will say that I mostly like the new editor experience, both from the perspective of a user (I’m writing this post in Gutenberg) and a developer.

And as a developer, I can’t help but notice that there is a pretty predictable problem staring down its nose at us.

The problem is front-end performance, and to be honest, it’s not really Gutenberg’s fault.

Some background

Gutenberg is a “block based” editor. Every piece of content in your post/entry is a block. Paragraphs, images, headings … all the normal stuff you’d put into entry content is a block.

And this opens up a world of opportunity for users to activate, as needed, new types of blocks.

Need a contact form on your contact page? There’s a block for that.

Need an image gallery? There’s a block for that.

Need a bunch of useful blocks in a single plugin? There’s a block library for that.

Now, in order to meet your needs in creating the kind of content you want, you may end up with several block plugins installed at once, in addition to the plugins you’re already using. Ignoring, for now, the risks of simply having too many plugins active, I want to focus on the bigger problem.

But first …

Waterfalls

When testing the performance of a website as it would appear to a user, developers do something called a waterfall analysis.

It’s basically a chart of every resource your site requires in order to load fully, and the time it took for each of those resources to download.

It’s a really good visual representation of page weight.

Waterfall for WordPress.org

I won’t explain waterfalls in too much detail; there are much better articles for that than this one. But to give a brief summary, each resource download your page uses is represented by a row. Each row has a colored line (far right) that indicates when the asset started downloading, and how long it took. Obviously, bigger files from slower servers are going to take longer, whereas small files from fast servers (like CDNs) will take less time.

In addition to helping you locate assets that are loading slowly (due to size or server speed), the waterfall shows you another useful metric: what resources are blocking other resources from downloading, and ultimately, blocking the page from rendering.

Although there are a few types of render blocking resources, for the purposes of this article, we’re going to focus on the most relevant one, stylesheets (CSS).

Render blocking stylesheets

Because there is currently no way to prevent stylesheets from blocking the render of a page (and for good reason, FOUC is no fun), we’ve basically just had to accept that our stylesheets were going to halt the render of our page until they’ve all downloaded.

Essentially, until all of the CSS is downloaded, nothing on the page will render.

So we invented little tricks to help minimize this issue, like minifying our CSS, combining all the CSS into a single stylesheet (where possible), and relying heavily on browser caching.

And when you have total control over your site, these aren’t terrible options.

But an extensible CMS will complicate things. Your theme loads some CSS, plugins load CSS, WordPress core load some CSS.

It’s not at all surprising to see a WordPress site loading 10+ stylesheets, and that’s just going to get worse with Gutenberg blocks needing their own CSS to render properly on the front end.

What’s worse, these stylesheets are being loaded regardless of whether they’re needed. If a page isn’t using a particular block, the block plugin will still likely load the CSS for that block.

But even if the block plugin were aware that the page was using the block, and only loaded the CSS when the block was being used on a page, we still have a problem! When you register and enqueue a stylesheet in WordPress (the Right Way), it will output to the <head>, as it is designed to do.

The problem is, now a stylesheet designed for a block that is used at the bottom of a blog post is blocking the render of the site header, or menu, or post title, etc.

Why should a block placed well below the fold affect the rendering of the site header?

Let’s Modularize

Conventional wisdom tells us that we need to serve as few CSS files as possible. Every HTTP request includes some network latency, and therefore reducing requests means less time until all our CSS is downloaded and the page is ready to render.

After all, if every CSS file is loaded in the <head>, and blocks the render of the entire page, then why wouldn’t you just combine all your CSS into a single file, a single HTTP request?

Note: although you could make the argument that modularizing your CSS files provides a more efficient cache busting opportunity, and HTTP2 allows for asynchronous CSS downloads, latency is still an issue so it’s still best for performance to combine CSS in production.

But, a couple of months ago, Jason Cohen shared and interesting link to the engineers at WP Engine. An excerpt:

due to a recent change in Chrome (version 69, I believe), and behaviour already present in Firefox and IE/Edge, <link rel="stylesheet" />s will only block the rendering of subsequent content, rather than the whole page.

CSS Wizardry

If all the stylesheets are linked in the <head>, this new information doesn’t really change much. It’s still blocking everything after the link … every visual element on your site.

But what if we split CSS into multiple files, each corresponding to a piece of content that needed styling. And instead of linking them all in the <head>, these CSS files would only be linked directly before the content they were designed to style was present.

It still blocks rendering, just like the traditional method, but because we’re linking the CSS file in the <body> right before the content it’s designed to style, we don’t block rendering of content before that point in the source code.

The practical upshot of this is that we’re now able to progressively render our pages, effectively drip-feeding styles to the page as they become available.

CSS Wizardry

Put another way, we’re drip feeding styles to the page as needed.

It also has the added benefit of strategically blocking the rendering of any content which doesn’t have corresponding CSS dowloaded yet. No FOUC.

Time to first render

So why is this a big deal? Because page speed (the actual time it takes for your full site to load) and perceived page speed (the time it takes for a user to think your site has loaded) are very different things.

And it turns out, users don’t care that much about how long your site actually takes to load. They’re not watching the waterfall, they’re watching the screen.

Anything we can do to reduce the time a user has to wait until they first start to see things loading on our page is a win for visitor retention. Users don’t see the footer when the page first loads. And with more and more traffic coming from mobile, there’s even less that is actually seen when a page is first accessed.

This presents a big opportunity! We can decrease the time to first render, and delay the rendering of elements further down the screen until after their related CSS has been loaded.

So, Blocks?

Admittedly, this is hard. WordPress is very specific about the way it wants you to load your CSS files.

Currently, you have the option to register a stylesheet with one function, and another function enqueues it (it also will do the job of registration, but you should really register and enqueue separately).

When you enqueue styles this way, every stylesheet link gets output to the <head>. Each stylesheet is registered with a unique handle, so the same stylesheet link doesn’t get linked more than once.

I’m not suggesting that we start linking our own stylesheets outside the WordPress way. But something does have to change.

What if you could register stylesheets the same way, but instead of enqueueing them to be output in the <head>, you could call a function manually that would output the stylesheet link (with any dependencies) immediately before a block. Once a link is rendered, the WordPress stylesheet manager could make sure it doesn’t get rendered again.

As it turns out, you can!

Here’s a quick proof of concept (and a gist). It’s using the CTA block from Atomic Blocks as the example, but obviously production code would look a bit different.

// this snippet requires PHP 5.3+
add_action( 'wp_enqueue_scripts', function() {
	wp_register_style( 'atomic-blocks/ab-cta', '/path/to/atomic-blocks/css/ab-cta.css', array(), '1.0.0' );
} );

add_filter( 'render_block', function( $block_content, $block ) {
	if ( 'atomic-blocks/ab-cta' === $block['blockName'] ) {
		ob_start();
		wp_print_styles( $block['blockName'] );
		$block_content = ob_get_clean() . $block_content;
	}

	return $block_content;
}, 10, 2 );

You essentially register the modular CSS as you normally would. Then, leveraging the render_block filter, you can output a stylesheet link “just in time”, so that the content gets CSS to style it before it gets rendered, but the CSS doesn’t block the rendering of anything before it in the source.

This is legitimately amazing. By using wp_register_style() and wp_print_styles(), we are working within the existing WordPress stylesheet loader, and we get all the benefits of doing so. But by not enqueueing the styles, and instead printing them directly where we want them, we can output the stylesheet links right before the block they style, and only if the block is actually used. Yes, we have to use output buffering, but that’s sometimes unavoidable, and in this case, it’s worth it.

Themes?

This method isn’t limited to blocks. Entire themes could be built this way. Instead of a master stylesheet that styles everything, use separate stylesheets for each section of your site and output the stylesheet link right before the section it styles.

Has it ever bothered you that WordPress themes load CSS for the comments section on pages with comments disabled, or on archives, or on the homepage? Yeah, me too.

By only linking a stylesheet when it’s needed, you only load CSS for sections that actually exist on the page. This can significantly decrease total page weight, in addition to the decreased time to first render mentioned before.

Plugins

Plugins have the exact same opportunity that themes and blocks do.

It’s really not complicated. Simply register your stylesheet as you normally would, then use wp_print_styles() to output the CSS as part of any rendering functionality your plugin uses. If your plugin provides a widget, then make sure the widget styles get output when the widget renders … don’t enqueue the stylesheet like you used to!

Gotchas

So what’s the catch?

Currently this method works in all major browsers except Safari. It doesn’t break or anything, it just treats each linked stylesheet as if it were in the <head>. That is, each linked stylesheet is render blocking for the entire page.

So basically, in Safari, we end up with the same outcome we’d have if we didn’t implement this method at all.

Sure, by using this method, you might sacrifice some performance in Safari (until they fix things) by not concatenating all your CSS into a single file, but by having a stylesheet for each major section or content type, and only linking it when that section or content type is actually in use, you also gain some performance by reducing your total page weight.

One possible issue is that on pages where we’re not actually reducing total page weight – a page that uses a lot of sections, blocks, etc. – we might technically be increasing the total pageload time by modularizing our stylesheet loading method. It’s possible that search engines like Google, who prioritize speed, might penalize you for choosing time to first render over time to full render. But in my opinion, this is unlikely.

Am I wrong?

the best way to get the right answer on the internet is not to ask a question; it’s to post the wrong answer.

Ward Cunningham, Cunningham’s Law

So, what did I miss? I want to kick off a discussion of this problem, the proposed solution, and also kick around other ideas.

I’d also love to see actual metrics for this method. I haven’t been able to do a lot of testing, so this post is pretty theoretical when it comes to the performance benefits I’m predicting.

If you want to discuss this on Twitter, you can find me at @nathanrice

In Defense of Theme Frameworks

At the risk of sounding dismissive, I have to admit that I roll my eyes most of the time I see people pronounce the inferiority of WordPress theme frameworks. I’ve been hearing this argument since before Genesis was even a conversation, much less an actual product.

But if I’m honest, I can see why some people don’t care for them, or denounce them by proxy for a particular segment of the WordPress community — “the users” — as being more, not less, difficult to use than a traditional theme.

I remember the first time I used a WordPress theme. This was before the days of documentation abundance. You couldn’t really just do a search for a question and expect there to be 100 answers available.

I was lost. I gave up. It took a year for me to try again.

Believe it or not, WordPress theming didn’t “click” with me until I cracked open one of Brian Gardner’s themes and looked at the code. Now we work together!

I know better than most how incredibly intuitive a WordPress theme’s structure is. Header stuff in header.php. Footer stuff in footer.php. The stuff in between was in template files, named logically.

It all made sense. The PHP didn’t seem overwhelming because it blended with the HTML. It was natural, intentionally simple.

FWIW, even traditional themes have moved beyond this simple HTML + PHP structure. Even the default themes use filters, custom functions, etc. So, making the case against frameworks by referencing modern themes seems like a reach. But I digress …

So, Why Build a Framework?

If I loved traditional themes so much, what made me decide to build a framework?

At the time, I was building themes full time. Every new theme felt tedious, like I was doing the same work over and over.

I tried building a “starter theme”, but I would inevitably find things that could be improved, and though the starter theme (and future themes built from it) would get the benefit of the improvements, all previous themes will live in perpetuity with flaws.

That bothered me. I figured a good framework, appropriately abstracted, could reduce development time, resulting in more themes for users, and standardize an optimized markup structure. So I started building.

Soon after, Brian approached me and it turned out that we had similar goals, so I came to work for StudioPress.

Turns out, building themes on a framework isn’t such a bad idea. Hundreds of thousands millions of sites have used Genesis since its introduction. I think that speaks for itself.

Other Benefits

After building, and continuing to build a framework for over 3 years, we realized that the benefits started to add up.

1. Change the look, not the code

Users are able to change the look of their site, while leaving their code in place. Their markup doesn’t change. Switching between one Genesis child themes is almost entirely CSS and images. This eliminates a good bit of the up front effort associated with switching themes. Also, search engines like the consistency.

And because theme settings remain the same between themes built on a framework, you don’t have to configure things more than once. That’s a time saver.

2. Updates

Also, because framework customizations exist separate from the framework itself, we (the developers of the framework) can push updates to users and fix bugs, add features, and improve their site with a simple upgrade process … something we made even better with the 1-click upgrade system in Genesis (the first commercial theme to offer this functionality).

3. Community

But perhaps the biggest benefit of using a framework like Genesis is the amazing developer community that a consistent and actively managed project cultivates. I’ll come back to this in a second.

But Frameworks Suck, because …

There are some valid complaints about using frameworks. And in a vacuum, comparing a framework to a traditional theme, frameworks do seem more complicated.

HTML doesn’t live directly in the template files. Output is abstracted and hooked. I don’t know what a function is, and a filter is something I use to make coffee. This doesn’t make sense!

I think we’ve done a good job at mitigating these effects, though.

For starters, we’ve tried to bring some of that discoverability into our framework. For instance, we have a folder in Genesis called /structure/. In this folder, we have files like header.php and footer.php that contain the code that outputs HTML to those locations. I’ve had numerous people tell me how much that helps when transitioning from traditional themes to Genesis.

But remember when I mentioned that developer community above? The standardization and active development of a single codebase (the central concept of a theme framework) has a lovely side effect: people can figure things out, share them with others via blog posts, and the information is essentially valuable for ever.

And these tutorials accumulate and multiply.

So, while it may be a little harder to figure things out as a newbie DIY blogger just by looking at the theme code, there is a wealth of information and resources out there that will walk you through just about any question you have.

And that’s not even considering the OFFICIAL support you’ll receive if you purchase a reputable theme framework.

The Users

At the end of the day, it’s all about users. What do they like? What do they want? Obviously, developers can do it all, traditional themes or frameworks.

But beginners fall into two categories: the turn key blogger who just wants to get his theme installed, flip a couple of switches, and start blogging, and the person in the temporary state of needing to move past turn key but isn’t yet at the point where you can call them a developer.

For this person, it certainly seems like a traditional theme is more accessible.

But considering the starter choices they have in the abundance of child themes, the numerous resources from which they can find help and tutorials for common tasks, and the wealth of benefits offered by a framework, it seems like a small concession to give up the only real benefit a traditional theme offers.

Conclusion

So, who should use a framework? In my opinion, it’s the best choice for almost everyone. I know that’ll be a controversial statement, but I believe it.

At this point in time, rolling your own theme just doesn’t make a lot of sense. We’ve put literally thousands of hours into developing Genesis. Do you have time to give your self-rolled WordPress theme that kind of time?

And if you’re relying on a 3rd party for your theme, do they have the ability to deliver updates to your themes if they find a bug? Without a framework, this is nearly impossible to do.

In the end, I’m convinced the long term benefits significantly outweigh the temporary drawbacks of using a framework. My recommendation? I think you can figure that one out.

New Loop Hooks in Genesis 2.0

If you haven’t heard, Genesis 2.0 is coming soon (you can run Genesis beta by using this plugin). And with it comes the ability to make your site output HTML5 markup and Schema.org microdata, which put a new emphasis on semantics in the way we mark up out content.

With this in mind, it became clear to us that our old loop hooks just didn’t pass the smell test. “post” simply does not accurately describe the types of content you can manage with WordPress. For instance, pages. Or worse, the infinite possible content types you can create and manage with Custom Post Types.

Using the genesis_before_post_content hook to insert something before the page content makes very little sense.

So we decided to update the Genesis loop function to reference the “entry” instead. We also updated our tag classes to follow this same pattern: entry, entry-header, entry-title, entry-meta, entry-content, entry-footer … you get the idea.

Note: if you’re using Genesis without HTML5 activated, all the old hooks and markup work as before. Genesis 2.0 is 100% backward compatible.

If HTML5 is not active, it uses the legacy loop (with all the old hooks and markup).

So, if you want to insert something after a post, page, or custom post type, you need to use the genesis_after_entry hook.

Pretty simple.

But the same goes for the things that you would want to unhook.

If you want to remove something from executing, you need to remove it from the new hook, rather than the old one. Here’s a list of the default entry element actions:

	add_action( 'genesis_entry_header', 'genesis_do_post_format_image', 4 );
	add_action( 'genesis_entry_header', 'genesis_entry_header_markup_open', 5 );
	add_action( 'genesis_entry_header', 'genesis_entry_header_markup_close', 15 );
	add_action( 'genesis_entry_header', 'genesis_do_post_title' );
	add_action( 'genesis_entry_header', 'genesis_post_info', 12 );

	add_action( 'genesis_entry_content', 'genesis_do_post_image', 8 );
	add_action( 'genesis_entry_content', 'genesis_do_post_content' );
	add_action( 'genesis_entry_content', 'genesis_do_post_content_nav', 12 );
	add_action( 'genesis_entry_content', 'genesis_do_post_permalink', 14 );

	add_action( 'genesis_entry_footer', 'genesis_entry_footer_markup_open', 5 );
	add_action( 'genesis_entry_footer', 'genesis_entry_footer_markup_close', 15 );
	add_action( 'genesis_entry_footer', 'genesis_post_meta' );

	add_action( 'genesis_after_entry', 'genesis_do_author_box_single', 8 );
	add_action( 'genesis_after_entry', 'genesis_adjacent_entry_nav' );
	add_action( 'genesis_after_entry', 'genesis_get_comments_template' );

So there you go! New semantic HTML5 hooks in Genesis 2.0. Enjoy!