Skip to content

WordPress CSS Customization — Additional CSS, Enqueuing Stylesheets and Best Practices

DodaTech Updated 2026-06-27 12 min read

In this tutorial, you'll learn to customize WordPress with CSS — using the Additional CSS panel, enqueuing stylesheets in functions.php, targeting WordPress-specific CSS classes, and following best practices for maintainable styles.

What You'll Learn

  • Using Additional CSS in the Customizer (live preview, beginner-friendly, limited scope)
  • Enqueuing styles in functions.php with wp_enqueue_style() and dependencies
  • Enqueuing scripts correctly with wp_enqueue_script()
  • Understanding WordPress body classes from body_class() (page slug, category, post type, logged-in)
  • Using post_class() for per-post CSS targeting
  • Targeting specific pages with body.page-id-42 and .post-123
  • Responsive breakpoints with mobile-first media queries
  • CSS specificity in WordPress themes
  • Child theme style.css loading order and overriding rules
  • Custom CSS plugins (SiteOrigin CSS, Simple Custom CSS)
  • Performance best practices (minify CSS, combine files, critical CSS)

Why It Matters

WordPress generates extensive CSS-friendly markup with dozens of body and post classes. Knowing how to properly add CSS — whether through the Customizer, functions.php, or child themes — lets you style any element precisely. Proper enqueuing prevents conflicts, ensures correct loading order, and maintains performance. Without this knowledge, you will fight specificity battles, lose styles on theme updates, and slow down your site.

Real-World Use

A blog needs category-specific styling: the "News" category should have a red accent color, "Tutorials" should have blue. Using body.category-news, the developer adds red link colors via Additional CSS. For a custom typeface, they enqueue Google Fonts in functions.php with proper dependency. The result is precise styling that survives theme updates and loads efficiently.

Learning Path

flowchart LR
  A[Theme Anatomy] --> B[Installing Themes]
  B --> C[Full Site Editing]
  C --> D[Customizer]
  D --> E[Widgets]
  E --> F[Menus]
  F --> G[Child Themes]
  G --> H[Template Hierarchy]
  H --> I[CSS Customization]
  style I fill:#4a90d9,color:#fff

Additional CSS in the Customizer

The Additional CSS panel is the safest entry point for CSS customization:

  1. Go to Appearance > Customize.
  2. Click Additional CSS.
  3. Write CSS in the live editor.
  4. See changes instantly in the preview pane.
  5. Publish to apply to the live site.

Advantages

  • Live preview — See every change in real time
  • Safe — Does not modify theme files; survives updates
  • Syntax highlighting — Easier to read and debug
  • Validation — WordPress highlights basic syntax errors

Limitations

  • CSS only (no JavaScript, no PHP)
  • 5000 character default limit (configurable via filter)
  • Tied to the active theme — if you switch themes, these styles are lost

Example: Additional CSS

body {
    font-family: 'Georgia', serif;
    line-height: 1.8;
    color: #333;
}

.site-title a {
    color: #1a73e8;
    text-decoration: none;
}

.wp-block-button__link {
    background: #1a73e8;
    border-radius: 4px;
    padding: 0.75rem 1.5rem;
}

@media (max-width: 768px) {
    .site-header {
        padding: 1rem;
    }
    .wp-block-image img {
        max-width: 100%;
        height: auto;
    }
}

Enqueuing Styles in functions.php

For production sites, enqueue styles properly instead of using Additional CSS for everything:

function my_theme_styles() {
    wp_enqueue_style(
        'my-theme-main',                                 // Handle (unique ID)
        get_template_directory_uri() . '/css/main.css',  // File URL
        array(),                                         // Dependencies
        '1.0.0',                                         // Version (for cache busting)
        'all'                                            // Media type
    );

    wp_enqueue_style(
        'my-theme-google-fonts',
        'https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap',
        array(),
        null
    );
}
add_action( 'wp_enqueue_scripts', 'my_theme_styles' );

Why wp_enqueue_style() Instead of Tags

  • Dependency management — Ensures stylesheets load in the correct order
  • No duplicates — If a plugin enqueues the same handle, it only loads once
  • Conditional loading — Load styles only on pages that need them
  • Cache busting — Change the version parameter to force browsers to reload

Conditional Enqueuing

function my_theme_styles() {
    wp_enqueue_style( 'my-theme-main', get_template_directory_uri() . '/css/main.css' );

    // Only load gallery styles on pages/posts with galleries
    if ( is_singular() && has_shortcode( get_post()->post_content, 'gallery' ) ) {
        wp_enqueue_style( 'my-theme-gallery', get_template_directory_uri() . '/css/gallery.css' );
    }

    // Only load contact page styles
    if ( is_page( 'contact' ) ) {
        wp_enqueue_style( 'my-theme-contact', get_template_directory_uri() . '/css/contact.css' );
    }
}
add_action( 'wp_enqueue_scripts', 'my_theme_styles' );

Enqueuing Scripts

JavaScript follows the same pattern with additional footer-loading control:

function my_theme_scripts() {
    wp_enqueue_script(
        'my-theme-navigation',                           // Handle
        get_template_directory_uri() . '/js/navigation.js', // URL
        array(),                                         // Dependencies (e.g., array('jquery'))
        '1.0.0',                                         // Version
        true                                             // Load in footer (true)
    );

    // Localize script for passing PHP data to JavaScript
    wp_localize_script(
        'my-theme-navigation',
        'myThemeData',
        array(
            'ajaxUrl' => admin_url( 'admin-ajax.php' ),
            'themeUri' => get_template_directory_uri(),
        )
    );
}
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' );

Loading jQuery Properly

Do not hardcode jQuery via CDN. WordPress includes jQuery:

function my_theme_scripts() {
    wp_enqueue_script(
        'my-theme-custom',
        get_template_directory_uri() . '/js/custom.js',
        array( 'jquery' ),
        '1.0.0',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' );

WordPress already has jQuery registered. Declare it as a dependency and let WordPress handle the version.

WordPress Body Classes

The body_class() function in header.php outputs an HTML attribute full of useful CSS hooks:

<body <?php body_class(); ?>>

Typical output:

<body class="home blog logged-in admin-bar no-customize-support wp-custom-logo">
<body class="page page-id-42 page-template-default logged-in">
<body class="single single-post postid-123 single-format-standard category-news tag-css author-admin">

Common Body Classes

Category Classes Example
Page type home, blog, archive, single, page, search, 404 body.home
Post ID postid-{id} body.postid-123
Page ID page-id-{id} body.page-id-42
Post slug post-slug-{slug} body.post-slug-hello-world
Page slug page-slug-{slug} body.page-slug-about
Category category-{slug} body.category-news
Author author-{nicename} body.author-admin
Logged in logged-in body.logged-in
User role role-{role} body.role-administrator
Browser (varies by theme)

Targeting Specific Categories with CSS

/* All posts in News category */
body.category-news .entry-title a {
    color: #d32f2f;
}

/* All posts in Tutorials category */
body.category-tutorials .entry-title a {
    color: #1976d2;
}

/* Different accent color per category */
body.category-news .wp-block-button__link {
    background: #d32f2f;
}
body.category-tutorials .wp-block-button__link {
    background: #1976d2;
}

Targeting Specific Pages

/* Style only the About page */
body.page-id-42 .entry-content {
    font-size: 1.1rem;
    max-width: 800px;
    margin: 0 auto;
}

/* Style only the Contact page */
body.page-slug-contact .wpforms-container {
    background: #f5f5f5;
    padding: 2rem;
    border-radius: 8px;
}

Post Classes with post_class()

The post_class() function adds CSS classes to each post article:

<article <?php post_class(); ?>>

Output:

<article class="post-123 post type-post status-publish format-standard hentry category-news tag-wordpress">

Common Post Classes

  • post-{id}, post, type-post, status-publish, format-standard
  • category-{slug}, tag-{slug}
  • hentry (microformat)

Targeting Specific Posts

/* Style the first post differently */
.hentry:first-of-type {
    border-top: none;
    padding-top: 0;
}

/* Style a specific post by ID */
.post-123 .entry-title {
    font-size: 2rem;
    color: #1a73e8;
}

/* All posts in a specific category */
.category-news .hentry {
    border-left: 4px solid #d32f2f;
    padding-left: 1rem;
}

Responsive Breakpoints

Build mobile-first with min-width media queries:

/* Base styles (mobile first) */
.site-header {
    padding: 1rem;
    flex-direction: column;
}

/* Tablet */
@media (min-width: 768px) {
    .site-header {
        flex-direction: row;
        padding: 1.5rem 2rem;
    }
    .main-navigation {
        display: flex;
    }
}

/* Desktop */
@media (min-width: 1024px) {
    .site-header {
        padding: 2rem 4rem;
    }
    .content-area {
        max-width: 1140px;
        margin: 0 auto;
    }
}

/* Large desktop */
@media (min-width: 1440px) {
    .site-header {
        padding: 2rem 8rem;
    }
}

Common WordPress Breakpoints

/* Mobile: < 768px — default styles */
/* Tablet: 768px+ */
@media (min-width: 768px) {}

/* Desktop: 1024px+ */
@media (min-width: 1024px) {}

/* Wide: 1366px+ */
@media (min-width: 1366px) {}

CSS Specificity in WordPress Themes

WordPress themes often include complex CSS specificity chains:

.site-content .entry-content .wp-block-image figcaption {
    font-size: 0.875rem;
    color: #666;
}

To override, you need equal or higher specificity:

/* This overrides because it comes later (same specificity) */
.site-content .entry-content .wp-block-image figcaption {
    color: #333;
}

/* This also works — higher specificity with body class */
body .site-content .entry-content .wp-block-image figcaption {
    color: #1a73e8;
}

Specificity Tips

  • Use the parent theme's selectors (from browser DevTools) for reliable overrides
  • Add one body class (e.g., body) to increase specificity without !important
  • Avoid !important — it makes future overrides difficult
  • In child themes, the child style.css loads after parent, so same-specificity overrides work

Child Theme style.css Loading Order

In a child theme, the stylesheets load in this order:

  1. Parent theme's enqueued stylesheets
  2. Child theme's enqueued stylesheets (if parent is declared as dependency)
  3. Additional CSS from Customizer (inline, highest priority)

Because the child style.css loads after the parent styles, you can override with the same selectors:

/* Child theme style.css */
.site-title a {
    color: #34a853; /* Overrides parent's #1a73e8 */
}

This only works if the child theme properly declares the parent style as a dependency:

wp_enqueue_style( 'child-style', get_stylesheet_uri(), array( 'parent-style' ) );

Without this dependency, the child CSS may load before the parent CSS, and your overrides will be overwritten.

Custom CSS Plugins

When you need more than Additional CSS but less than a full child theme:

Plugin Features
SiteOrigin CSS Visual CSS editor with live preview, attribute-based selectors
Simple Custom CSS Minimal textarea for CSS, no frills
Jetpack Includes Custom CSS module (site-wide)
CSS Hero Point-and-click CSS editing (premium)

These plugins store CSS in the database, separate from themes. They are useful for clients who want to make style changes without developer involvement.

Performance Best Practices

Minify CSS

Use a build tool (Webpack, Gulp) or a plugin (Autoptimize, WP Rocket) to minify CSS:

# Example using clean-css CLI
cleancss -o style.min.css style.css

Combine CSS Files

Fewer HTTP requests = faster load times. Only combine if you have many small files:

// Instead of 5 separate enqueues, combine into one CSS file
wp_enqueue_style( 'my-theme-combined', get_template_directory_uri() . '/css/combined.min.css' );

Critical CSS

Inline above-the-fold CSS in the <head> and defer full stylesheets:

function my_theme_critical_css() {
    $critical = file_get_contents( get_template_directory() . '/css/critical.css' );
    echo '<style id="critical-css">' . wp_strip_all_tags( $critical ) . '</style>';
}
add_action( 'wp_head', 'my_theme_critical_css', 1 );

function my_theme_defer_styles( $tag, $handle ) {
    if ( 'my-theme-main' === $handle ) {
        return str_replace( "rel='stylesheet'", "rel='preload' as='style' onload='this.rel=\"stylesheet\"'", $tag );
    }
    return $tag;
}
add_filter( 'style_loader_tag', 'my_theme_defer_styles', 10, 2 );

Use Version Parameters

Always version your enqueued assets. Change the version when you update the file to break browser cache:

wp_enqueue_style( 'my-theme-main', get_template_directory_uri() . '/css/main.css', array(), '1.0.3' );

Common Mistakes

  1. Hardcoding and