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
- Create
scss/in your theme folder and write your SCSS - Compile with
sasstoassets/css/main.css - Load
assets/css/main.cssfromfunctions.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 sassand compile withsass input.scss output.css - Compile to a separate file such as
assets/css/main.cssand do not overwrite the theme header instyle.css - Split files with
@useinstead 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)