Remove Gutenberg Block Library CSS in WordPress

WordPress loads the Gutenberg block library CSS on the front end even when a site is built with the classic editor or a page builder and never shows a block. To remove the Gutenberg block library CSS in WordPress, this snippet dequeues wp-block-library and the related block styles, and lets you choose which parts go.

Be clear about the trade-off first: this CSS is what makes blocks look right. Remove it on a site that renders blocks and columns collapse, buttons lose their style and image alignments break. The snippet therefore keeps the CSS on block themes and on single posts and pages built with blocks, unless you turn that off.

The snippet

<?php
/**
 * Remove the Gutenberg block CSS from the WordPress front end on sites that do not use blocks.
 */

// ===== Config: what to remove (true) or keep (false) =====
function dpc_block_css_config() {
	$config = array(
		'block_library'    => true,  // wp-block-library and wp-block-library-theme: styles for core blocks.
		'global_styles'    => true,  // global-styles: theme.json presets (--wp--preset--* variables, has-*-color classes).
		'classic_theme'    => true,  // classic-theme-styles: default button and file block styles in classic themes.
		'woocommerce'      => true,  // WooCommerce and Storefront block styles.
		'keep_with_blocks' => true,  // Keep everything on single posts and pages whose content uses blocks.
		'block_themes'     => false, // Block themes are built from blocks; leave their CSS alone.
	);
	// ===== End of config =====

	return (array) apply_filters( 'dpc_block_css_config', $config );
}

add_action( 'wp_enqueue_scripts', 'dpc_remove_block_css', 100 );

function dpc_remove_block_css() {
	$config = dpc_block_css_config();

	if ( empty( $config['block_themes'] ) && wp_is_block_theme() ) {
		return;
	}
	if ( ! empty( $config['keep_with_blocks'] ) && is_singular() && has_blocks( get_queried_object_id() ) ) {
		return;
	}

	$handles = array();
	if ( ! empty( $config['block_library'] ) ) {
		$handles = array_merge( $handles, array( 'wp-block-library', 'wp-block-library-theme' ) );
	}
	if ( ! empty( $config['classic_theme'] ) ) {
		$handles[] = 'classic-theme-styles';
	}
	if ( ! empty( $config['woocommerce'] ) ) {
		$handles = array_merge( $handles, array( 'wc-blocks-style', 'wc-blocks-vendors-style', 'storefront-gutenberg-blocks' ) );
	}
	if ( ! empty( $config['global_styles'] ) ) {
		$handles[] = 'global-styles';
		// Block themes and some classic themes print global styles again in the footer.
		remove_action( 'wp_footer', 'wp_enqueue_global_styles', 1 );
	}

	foreach ( $handles as $handle ) {
		wp_dequeue_style( $handle );
	}
}

How it works

  • WordPress enqueues the block styles on wp_enqueue_scripts at the default priority. The snippet runs on the same hook at priority 100 and dequeues the handles you switched on.
  • block_library removes wp-block-library and wp-block-library-theme. classic_theme removes classic-theme-styles. woocommerce removes WooCommerce’s and Storefront’s block styles.
  • global_styles removes the inline global-styles CSS generated from theme.json: the --wp--preset--* variables and classes such as has-primary-color. Some themes and plugins use those variables outside blocks, so check your pages after switching it on. WordPress can print the same CSS again in the footer, so that callback is removed too.
  • The checks run on every request, so a site that uses blocks on a few pages only keeps the CSS there and drops it everywhere else.

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor, edit the config and publish. Leave Action/Hook empty. The code only acts on front-end requests; wp-admin and the block editor keep their styles.

The same code also works unchanged in a small plugin or an mu-plugin.

Customise it

  • Keep something: set its line to false, for example 'global_styles' => false if your theme uses the preset colour classes.
  • No blocks anywhere: leave the defaults. Set 'keep_with_blocks' => false only if you are sure no post shows block markup.
  • Block theme: 'block_themes' => true makes the snippet run there too, but expect broken layouts unless you replace the styles.
  • To drop single per-block styles instead of the whole library, see Deregister Gutenberg Inline Styles. For other front-end extras see Disable Emojis in WordPress Without a Plugin.

Gotchas

  • keep_with_blocks looks at the current single post or page only. Archives, widgets and page builder templates that show block content are not detected; if they look wrong, set block_library to false.
  • Themes that load core block CSS per block (should_load_separate_core_block_assets) print styles such as wp-block-paragraph separately; this snippet does not remove those.
  • Caching and optimisation plugins may have combined the CSS already. Clear their cache before comparing.

The older version of this post removed everything everywhere, including on pages that use blocks. The Scripts Organizer library version also removed global styles and an SVG filter callback that WordPress no longer uses. This version keeps those removals, adds classic-theme-styles, and makes each part optional.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.