2026年11月13日

2026年11月13日

Using SCSS in a WordPress Theme: Compile with Dart Sass and Enqueue

This article is a localized edition of the Japanese original. Read the Japanese original

SCSS lets you write CSS with variables, nesting, mixins and more. Browsers cannot read SCSS directly, so you compile it to CSS with Sass and load the resulting CSS file in WordPress.

This article uses Dart Sass, the official Sass implementation (npm package sass). You need Node.js.

Overview

  1. Create scss/ in your theme folder and write your SCSS
  2. Compile with sass to assets/css/main.css
  3. Load assets/css/main.css from functions.php

WordPress reads the comment at the top of your theme's style.css (Theme Name: and so on) as the theme's information. If you overwrite it with compiled output, the comment can disappear depending on the compression settings, and WordPress no longer recognizes the theme. It is easier to compile to a separate file and keep style.css for the theme header only.

Install Sass

# Run in your theme folder
cd wp-content/themes/my-theme
npm init -y
npm install --save-dev sass

# Check the installed version
npx sass --version

Add the compile commands to scripts in package.json.

{
  "scripts": {
    "sass:watch": "sass scss/main.scss assets/css/main.css --watch",
    "sass:build": "sass scss/main.scss assets/css/main.css --style=compressed --no-source-map"
  }
}
# During development: compile every time you save SCSS (stop with Ctrl+C)
npm run sass:watch

# For production: output compressed CSS
npm run sass:build

With --watch, a source map (main.css.map) is also written by default, so your browser's developer tools can show SCSS line numbers. The production command turns it off with --no-source-map.

Split your files (@use)

When a file grows, split it by role. Files whose names start with _ (partials) are not compiled to CSS on their own; they are only loaded from other files.

my-theme/
├── style.css            theme header only
├── functions.php
├── assets/css/main.css  compiled output (generated)
└── scss/
    ├── main.scss        entry file
    ├── _variables.scss
    ├── _mixins.scss
    ├── _base.scss
    └── _card.scss

The entry file main.scss loads each partial with @use. You can omit the extension and the leading _.

// scss/main.scss
@use 'base';
@use 'card';

Define your variables and mixins.

// scss/_variables.scss
$color-primary: #2271b1;
$color-text: #1d2327;
$space-md: 1.5rem;
$radius: 6px;

// Also output SCSS variables as CSS custom properties
:root {
  --color-primary: #{$color-primary};
  --space-md: #{$space-md};
}
// scss/_mixins.scss
@mixin respond-to($breakpoint) {
  @if $breakpoint == sm {
    @media (max-width: 600px) { @content; }
  } @else if $breakpoint == md {
    @media (max-width: 900px) { @content; }
  } @else {
    @error "Unsupported breakpoint: #{$breakpoint}";
  }
}

Variables and mixins loaded with @use are available only in the file that loads them, so add @use to every file that needs them. With as * you can use them without a namespace such as variables.$radius.

// scss/_base.scss
@use 'variables' as *;

body {
  color: $color-text;
}
// scss/_card.scss
@use 'variables' as *;
@use 'mixins';

.card {
  border-radius: $radius;
  overflow: hidden;

  &__body {
    padding: $space-md;
  }

  &:hover {
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  }

  @include mixins.respond-to(sm) {
    border-radius: 0;
  }
}

The :root { … } block in _variables.scss is loaded with @use from both _base.scss and _card.scss, but it appears only once in the CSS, because @use evaluates a file only once no matter how often it is loaded.

&__body compiles to .card__body, and &:hover to .card:hover.

@import is deprecated

Older articles often load files with @import 'variables';, but Sass's @import was deprecated in Dart Sass 1.80.0 and now triggers a warning when you compile. The official Sass documentation says it is planned to be removed in Dart Sass 3.0.0. In new SCSS, use @use (and @forward when you pass a file's members on to other files).

Enqueue the CSS in functions.php

<?php
// functions.php
add_action( 'wp_enqueue_scripts', function () {
	$path = get_theme_file_path( 'assets/css/main.css' );

	wp_enqueue_style(
		'my-theme-main',
		get_theme_file_uri( 'assets/css/main.css' ),
		array(),
		file_exists( $path ) ? (string) filemtime( $path ) : null
	);
} );

Using the file's modification time as the version changes the ?ver= in the URL every time you recompile, so browsers are less likely to keep stale CSS.

In a child theme, get_theme_file_uri() returns the child theme's file if it exists and the parent theme's file otherwise. For more on loading CSS, see How to load JS and CSS with wp_enqueue_scripts in WordPress.

If you want to compile straight to style.css

If you really want to compile to style.css, start the theme header comment with /*!. --style=compressed removes normal comments but keeps comments that start with /*!.

/*!
Theme Name: My Theme
Version: 1.0.0
*/

@use 'base';
@use 'card';

After compiling, check that the theme name shows correctly under Appearance > Themes.

Building with @wordpress/scripts

If you already use @wordpress/scripts (the wp-scripts command), for example for block development, it can build your SCSS too. Note that wp-scripts does not look for SCSS files on their own; it processes SCSS that is imported from JavaScript.

npm install --save-dev @wordpress/scripts
{
  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build"
  }
}

When there is no block.json in src/, the entry point is src/index.js. Import your SCSS there.

// src/index.js
import './style.scss';  // a file named style.scss → build/style-index.css
import './editor.scss'; // files with other names → build/index.css

Running npm run build writes the CSS to the build/ folder. The @wordpress/scripts documentation explains that files named style.scss and similar are combined into style-index.css for both the front end and the editor, and everything else goes to index.css. In a test with @wordpress/scripts 37.1.0, build/ contained style-index.css and index.css, plus index.js, index.asset.php (dependency and version information), and style-index-rtl.css and index-rtl.css for right-to-left languages. Check the file names in build/, then pass them to wp_enqueue_style() in functions.php.

<?php
add_action( 'wp_enqueue_scripts', function () {
	$path = get_theme_file_path( 'build/style-index.css' );

	if ( file_exists( $path ) ) {
		wp_enqueue_style(
			'my-theme-style',
			get_theme_file_uri( 'build/style-index.css' ),
			array(),
			(string) filemtime( $path )
		);
	}
} );

Things to watch out for

  • Do not upload node_modules/ to the server, and leave it out when you zip the theme for distribution or upload.
  • Decide as a team whether compiled CSS is committed to Git. If it is not, you need a build step before deployment (CI, for example).
  • You do not need to compile SCSS on the server. Upload only the CSS you compiled locally.

Summary

  • Install Dart Sass with npm install --save-dev sass and compile with sass input.scss output.css
  • Compile to a separate file such as assets/css/main.css and do not overwrite the theme header in style.css
  • Split files with @use instead of @import, and load variables in each file that uses them
  • Load the CSS with wp_enqueue_style(); using the file's modification time as the version helps avoid stale caches

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲