WordPress customization guide

How to add custom CSS to a WordPress theme

Use the least invasive method that fits the change: built-in Styles controls, Additional CSS, a child theme, a dedicated stylesheet, or WordPress’s inline-style API.

Do not place permanent customizations directly in a parent theme’s files. A theme update can replace those files and erase the changes. WordPress now provides several safer options, and the best choice depends on whether the adjustment is visual, theme-specific, reusable, dynamic, or part of a larger development project.

Choose the right CSS method

Block theme

Styles and Additional CSS

Use the Site Editor for site-wide design settings, global CSS, or CSS applied to a specific block type.

Classic theme

Customizer Additional CSS

Use the live-preview CSS editor for small theme-specific overrides without changing files.

Maintainable files

Child theme stylesheet

Use a child theme when custom CSS belongs in version control or accompanies template and PHP changes.

Theme or plugin code

Enqueued or inline styles

Use WordPress asset functions when CSS is shipped as code, loaded conditionally, or generated from settings.

Situation Recommended method Main limitation
One small visual override Additional CSS Stored for the active theme and normally does not follow a theme switch.
Change supported by WordPress design controls Styles, block settings, or theme settings Available controls depend on the active theme and block.
Several reusable CSS files and template changes Child theme Requires file access, testing, and ongoing maintenance.
CSS provided by a custom theme or plugin wp_enqueue_style() Requires PHP development and correct dependency handling.
Small dynamic CSS generated by code wp_add_inline_style() The target stylesheet must already be registered and queued.

Method 1: Add CSS in a block theme

Block themes use the Site Editor and Global Styles system. Start with the available typography, color, spacing, layout, border, and block controls before writing CSS. Native controls are easier to preview, reset, and maintain.

Site-wide Additional CSS

  1. Open the Site Editor. Go to Appearance > Editor.
  2. Open Styles. Select the Styles area for the active theme.
  3. Open the options menu. Use the ellipsis menu in the Styles header.
  4. Select Additional CSS. Add complete CSS selectors and declarations.
  5. Preview and save. Review templates and pages at several widths before publishing.
.site-header {
  border-bottom: 1px solid #dfe5ef;
}

.site-header a:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: 3px;
}

CSS for a block type

Inside Styles > Blocks, supported installations provide an Additional block CSS area for a selected block type. A basic declaration can be entered without repeating the block selector because WordPress scopes it to that block type.

border-radius: 0.5rem;
font-weight: 700;

Pseudo-classes and nested targeting require a rule structure. For example, a hover state may use:

:hover {
  transform: translateY(-1px);
}

Method 2: Use Additional CSS with a classic theme

For classic themes that expose the Customizer, open Appearance > Customize > Additional CSS. The editor provides a live preview and stores the CSS separately from the theme’s physical files.

  1. Open Additional CSS. Navigate through the Customizer.
  2. Add a focused rule. Override only the properties that need to change.
  3. Preview several pages. A selector may match more elements than expected.
  4. Test responsive states. Check mobile navigation, buttons, forms, and content cards.
  5. Publish the change. Keep a backup of the CSS outside the database.

Customizer CSS is associated with the theme. If the site switches themes, that CSS is not normally active under the new theme, although it may remain stored for the previous theme.

Method 3: Add CSS through a child theme

A child theme extends a parent theme and keeps custom files separate from the parent. This is appropriate when the CSS is part of a larger set of template, pattern, PHP, JavaScript, or asset changes that should be portable and version-controlled.

Start with the dedicated guide: How to Create a WordPress Child Theme.

Minimal child-theme header

/*
Theme Name: TDWP Child
Template: parent-theme-folder
Version: 1.0.0
*/

The Template value must exactly match the parent theme’s directory name. Add CSS below the header only after confirming that the child stylesheet is loaded.

Load the child stylesheet when necessary

<?php
function tdwp_child_enqueue_styles() {
    wp_enqueue_style(
        'tdwp-child-style',
        get_stylesheet_uri(),
        array(),
        wp_get_theme()->get( 'Version' )
    );
}
add_action( 'wp_enqueue_scripts', 'tdwp_child_enqueue_styles' );

Theme behavior varies. Some parent themes load both parent and child styles automatically, some load only the active theme stylesheet, and some block themes rely primarily on theme.json rather than a conventional stylesheet. Inspect the parent theme’s asset-loading code before adding duplicate requests.

Preserved example: override one button property

The original article correctly demonstrated that an override does not need to repeat every declaration. The later rule can change only the background while the remaining properties continue to come from the original stylesheet.

Original theme button

Original button

Customized button

Customized button

Original theme CSS

.button {
  background: #ed463d;
  color: #fff;
  font-size: 16px;
  font-weight: bold;
  line-height: 1.2;
  border-radius: 4px;
}

Custom override

.button {
  background: #3dc4ed;
}

The result depends on the cascade. If the theme uses a more specific selector, an inline style, a later stylesheet, or !important, the simple override may not win.

Method 4: Enqueue a dedicated stylesheet

For a custom theme or plugin, place CSS in a separate file and load it with WordPress’s stylesheet functions instead of hard-coding a <link> element into a template.

<?php
function tdwp_enqueue_custom_styles() {
    $relative_path = 'assets/css/custom.css';
    $file_path     = get_theme_file_path( $relative_path );

    wp_enqueue_style(
        'tdwp-custom',
        get_theme_file_uri( $relative_path ),
        array(),
        file_exists( $file_path ) ? filemtime( $file_path ) : null
    );
}
add_action( 'wp_enqueue_scripts', 'tdwp_enqueue_custom_styles' );

The file modification time in the example changes the stylesheet version when the file changes, helping browsers receive the new CSS during development. Production asset pipelines may use a release version or generated manifest instead.

Load CSS only where it is needed

<?php
function tdwp_enqueue_contact_styles() {
    if ( ! is_page( 'contact' ) ) {
        return;
    }

    wp_enqueue_style(
        'tdwp-contact',
        get_theme_file_uri( 'assets/css/contact.css' ),
        array(),
        '1.0.0'
    );
}
add_action( 'wp_enqueue_scripts', 'tdwp_enqueue_contact_styles' );

Conditional loading can reduce unused CSS, but avoid fragmenting a small stylesheet into many requests without measuring the result.

Method 5: Add dynamic CSS with wp_add_inline_style()

When a small CSS value is generated from validated settings, add it to a registered and enqueued stylesheet handle. The function prints the CSS after the target stylesheet, helping the dynamic rule participate predictably in the cascade.

<?php
function tdwp_add_brand_color() {
    $color = sanitize_hex_color(
        get_theme_mod( 'tdwp_button_color', '#3157d5' )
    );

    if ( ! $color ) {
        return;
    }

    $css = sprintf(
        '.button-primary { background-color: %s; }',
        $color
    );

    wp_add_inline_style( 'tdwp-custom', $css );
}
add_action( 'wp_enqueue_scripts', 'tdwp_add_brand_color', 20 );

The handle tdwp-custom must already be registered and queued. Validate every dynamic value before placing it into CSS, and prefer controlled property values over accepting an arbitrary block of user-provided code.

Find and target the correct element

  1. Inspect the page. Use browser developer tools to identify the element, classes, computed styles, and rule currently winning.
  2. Choose the narrowest stable selector. Prefer a meaningful custom class over generated or deeply nested selectors.
  3. Add a class when possible. In the block editor, use the Advanced panel’s Additional CSS class field for a reusable component class.
  4. Override only necessary properties. Avoid copying the whole original rule.
  5. Test every state. Review hover, focus, active, disabled, validation, mobile, dark backgrounds, and increased zoom.

Example with a custom block class

Add featured-callout in the block’s Additional CSS class field, then target it through the site-wide CSS editor or stylesheet:

.featured-callout {
  padding: clamp(1rem, 3vw, 2rem);
  border: 1px solid #dfe5ef;
  border-radius: 0.75rem;
  background: #f4f7fb;
}

.featured-callout a:focus-visible {
  outline: 3px solid #3157d5;
  outline-offset: 3px;
}

Understand why a CSS rule does not apply

CSS is resolved through origin, importance, cascade layers, specificity, scoping, and source order. When a rule appears crossed out in developer tools, another declaration has won.

  • Selector mismatch: the selector does not match the rendered HTML.
  • Specificity: the theme rule is more specific.
  • Source order: another matching rule loads later.
  • Inline styles: the element has a style attribute or generated block styles.
  • !important: an important declaration changes the normal priority.
  • Media query: the rule applies only at another width or media type.
  • Syntax error: a missing brace, invalid comment, or malformed property interrupts parsing.
  • Cache: a browser, plugin, host, or CDN is serving an older stylesheet.

Do not reach for !important automatically. First inspect the winning rule and correct selector scope, load order, or architecture. Use !important deliberately when overriding an unavoidable important declaration or implementing a controlled utility system.

Avoid editing theme files in the dashboard on a live site

The Theme File Editor can change PHP and CSS directly from the dashboard, but it provides a weak development workflow. Changes are not inherently version-controlled, a syntax mistake can break the site, and parent-theme files remain vulnerable to updates.

  • Create a backup before changing files.
  • Work in a local or staging environment.
  • Use version control and a deployment process.
  • Keep a tested rollback path.
  • Restrict production file-editing capability when it is not required.

Historical custom CSS plugin recommendations

The original article mentioned Simple Custom CSS, Jetpack Custom CSS, Custom CSS Manager, and My Custom CSS. Those names are preserved as historical context, but their current maintenance, security, compatibility, ownership, and availability have not been verified for this page.

Simple Custom CSS Originally highlighted as the author’s preferred dashboard CSS editor.
Jetpack Custom CSS Originally referenced as another method for managing CSS outside theme files.
Custom CSS Manager and My Custom CSS Listed as alternatives in the 2014 article.

Current WordPress includes built-in site-wide CSS editors, so a plugin may be unnecessary for basic overrides. Before installing any CSS plugin, confirm that it is actively maintained, compatible with the current WordPress version, limited to the required capability, and removable without losing the only copy of critical code.

Accessibility checks for CSS changes

  • Maintain readable text and control contrast in every state.
  • Do not remove focus outlines without providing an equally visible replacement.
  • Do not hide important content only visually when it must remain available to assistive technology.
  • Confirm layouts reflow without horizontal scrolling at narrow widths and increased zoom.
  • Respect prefers-reduced-motion for nonessential animation.
  • Keep touch targets large enough and separated from neighboring controls.
  • Do not communicate errors, status, or required fields through color alone.

CSS performance and maintenance

  • Remove obsolete rules after redesigns and theme changes.
  • Avoid selectors tied to fragile generated markup.
  • Group related component styles and add comments explaining unusual decisions.
  • Do not load a large framework to change one button.
  • Minify production files through a tested build or optimization process.
  • Keep source files readable even when deployed assets are compressed.
  • Measure unused CSS and rendering behavior on real pages before restructuring assets.

Test and publish safely

  1. Save a copy of the current CSS. Record the working state before changing it.
  2. Test in staging. Use representative pages, posts, archives, forms, and templates.
  3. Check logged-in and logged-out views. Admin bars and cached pages can change layouts.
  4. Review several widths and zoom levels. Include keyboard-only navigation.
  5. Clear only necessary caches. Verify the new stylesheet URL and response.
  6. Publish during a controlled window. Monitor major pages and keep the rollback ready.

What changed from the original 2014 guide

The original article advised using a child theme, adding CSS to the bottom of its stylesheet, overriding only the needed button property, and considering dashboard CSS plugins. This revision preserves those concepts while adding current block-theme Styles, classic-theme Additional CSS, block classes, proper stylesheet enqueueing, dynamic inline CSS, cascade troubleshooting, accessibility, performance, staging, and rollback guidance.

Official WordPress references

Article status

Archived discussion

The original page included an inactive reply form but no preserved comments. The form has been removed so visitors are not asked to submit personal information to an endpoint that may no longer work.

Questions, corrections, and feedback about this tutorial can be sent through the redesigned TDWP contact page.