An Alternative to @import in WordPress Child Themes

Using Child Themes in WordPress is a great way to modify an existing theme, however the CSS @import directive is slower than it has to be, so you should try and avoid it. Here’s why.

If it takes 200ms to load the child theme’s stylesheet, and 200ms to load the parent theme’s CSS, a modern web browser should take approximately 200ms to load both of them, because modern browsers load assets in parallel.

Unfortunately this is not true for CSS @import. Let me quote Google:

The browser must download, parse, and execute first.css before it is able to discover that it needs to download second.css.

Which means that instead of 200ms, with @import it’ll take the web browser approximately 400ms to load both stylesheets. Here’s a typical child theme’s CSS:

/**
 * Theme Name: My Child Theme
 * Template: parent-theme
 */
@import url(../parent-theme/style.css);

/* My Child Theme CSS */

We can drop the @import statement, and make good use of functions.php and the wp_enqueue_style() function:

// Faster than @import
add_action( 'wp_enqueue_scripts', 'my_child_theme_scripts' );
function my_child_theme_scripts() {
    wp_enqueue_style( 'parent-theme-css', get_template_directory_uri() . '/style.css' );
}

And we don’t need to re-declare dependencies because the child theme’s functions.php is loaded before the parent theme’s. Unless, of course, the parent theme uses a different action priority, in which case we should just match it.

That’s +1 to our PageSpeed score :)

About the author

Konstantin Kovshenin

WordPress Core Contributor, ex-Automattician, public speaker and consultant, enjoying life in Moscow. I blog about tech, WordPress and DevOps.

18 comments

  • Wow, kudos to this. I always heard using @import was not the best idea but now I understand the reasoning behind it. You have a great solution. Now what about adding Google Fonts that the spreadsheet requires? Would you suggest enqueueing them too?

  • I was thinking the same thing and this is how I load all the styles from parent theme now. SUFFIX mean .min files.

    /* Enqueue parent theme styles. */
    wp_enqueue_style( 'parent-style', trailingslashit( get_template_directory_uri() ) . 'style' . THEME_SUFFIX . '.css', array(), THEME_VERSION );
    
    /* Enqueue right to left styles. */
    if ( is_rtl() ) {
        wp_enqueue_style( 'theme-rtl-style', trailingslashit( get_template_directory_uri() ) . 'style-rtl' . THEME_SUFFIX . '.css', array( 'theme-style' ), THEME_VERSION );
    }
    
    /* Enqueue child theme styles. */
    if ( is_child_theme() ) {
        wp_enqueue_style( 'theme-child-style', get_stylesheet_uri(), array(), null );
    }
    • Hey Sami, thanks for your comment! Doing it from the parent theme is certainly an option, but only if you’re in control of the parent theme itself. Then again, you’ll have to somehow tell your users that there’s no need to reimport or re-enqueue stylesheets when creating a child theme, otherwise they may be loading it twice, especially if they use a different version number in the enqueue function.

    • you’ll have to somehow tell your users that there’s no need to reimport

      In premade child theme style.css there big text: DO NOT USE @IMPORT RULE TO LOAD PARENT THEME STYLES. THEY ARE LOADED AUTOMATICALLY. ENTER YOUR STYLES AFTER THIS COMMENT.

      In my opinion this way it’s better because average user don’t have a clue how to add wp_enqueue_style function in their child themes functions.php.

  • Thanks for the posts Kovshenin,
    My very basic skill is front-end web dev, I knew @import is really bad for performance but I thought we should always follow the official guide(codex) to use @import in child theme

    • Using @import is easier because you don’t have to deal with PHP. I guess that’s the reason why it’s used in the Codex examples in the first place. Also note that the codex is a wiki that anybody could change it, so there’s no guarantee it’s 100% correct.

      I just went in to add a note about @import in CSS, turns out somebody already did it last night :) Yey community!

  • Since it’s important for the parent theme’s CSS to get loaded before the child theme’s, does this cause the parent stylesheet to load before the child theme’s stylesheet?

    • Hey Dave, given that both the parent theme and the child theme enqueue their styles during the same priority in wp_enqueue_scripts, your child theme’s stylesheet will be correctly loaded after the parent theme’s.

      That’s because the child theme’s functions.php is executed before the parent, and we’re loading our parent CSS in the child theme, and our child CSS (with get_stylesheet_uri()) in the parent theme (confusing, eh?).

      You will, however, need to adjust the priority accordingly, if the parent theme runs its wp_enqueue_script callbacks at a lower (than 10) priority.

  • i’ve made a post about it, but it is in portuguese: http://origgami.com.br/blog/como-criar-child-themes-no-wordpress-de-forma-otimizada/

    I think you are right but you could improve it a little bit, like this:

    // Faster than @import
    add_action( 'wp_enqueue_scripts', 'my_child_theme_scripts' );
    function my_child_theme_scripts() {
        wp_enqueue_style( 'parent-theme-css', get_template_directory_uri() . '/style.css' );
        wp_register_style('my-child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-theme-css'));
        wp_enqueue_style('my-child-style');
    }
    

    Like this, you make sure the child style is loaded after the parent.

    And it is always a good idea to remove not used fonts from being loaded, like this:

    wp_deregister_style('open-sans'); 
    wp_deregister_style('twentyfourteen-lato');
    
    • Thanks for your comment Pablo! Re child/parent, as mentioned earlier, the child theme functions.php is executed before the parent theme, which already makes sure the parent CSS is enqueued before the child, but sure, you can take that little extra step.

      Also good point about dequeuing/deregistering styles, though I wouldn’t deregister Open Sans because it’s still used by the WordPress Dashboard, admin bar, etc.

  • Do you think it would be handy if core handles the parent theme loading as well as the child ? This way no action is needed by the user beyond specifying the parent theme.

    • Not really. It already does handle the loading of both themes, just not style.css. Also, many child themes don’t use the parent theme’s CSS file at all, and build their CSS from scratch.