Skip to content

Sass For Symfony!

Edit this page

This bundle makes it easy to use Sass with Symfony's AssetMapper Component (no Node required!).

  • Automatically detects the Sass binary installed in the system
  • Automatically downloads the correct Sass binary if it's not detected in the system
  • Adds a sass:build command to build and watch your Sass changes

Tip

While this bundle is great, you may not need to use Sass! Native CSS now supports variables and nesting. See Is it time to drop Sass? article for some more details.

Installation

Install the bundle:

1
$ composer require symfonycasts/sass-bundle

Usage

Start by writing your first Sass file assets/styles/app.scss, and let's add some basic style:

1
2
3
4
5
6
7
/* assets/styles/app.scss */

$red: #fc030b;

body {
  background: $red;
}

Note

Both syntaxes are supported: this guide uses .scss throughout, and .sass files work the same way.

Then point your styles in your template:

1
2
3
4
5
{# templates/base.html.twig #}

{% block stylesheets %}
    <link rel="stylesheet" href="{{ asset('styles/app.scss') }}">
{% endblock %}

That's right! You point directly to the .scss file. But don't worry, the final built .css file will be returned!

Then run the command:

1
$ php bin/console sass:build --watch

And that's it!

Symfony CLI

If using the Symfony CLI, you can add the build command as a worker to be started whenever you run symfony server:start:

1
2
3
4
5
# .symfony.local.yaml
workers:
    # ...
    sass:
        cmd: ['symfony', 'console', 'sass:build', '--watch']

Tip

If running symfony server:start as a daemon, you can run symfony server:log to tail the output of the worker.

How Does it Work?

The first time you run one of the Sass commands, the bundle will automatically try to detect the correct Sass binary installed in the system and use it. If the binary is not found, the bundle will automatically download the correct one for your system and put it into the bin/dart-sass directory.

When you run sass:build, that binary is used to compile Sass files into a var/sass/app.built.css file. Finally, when the contents of assets/styles/app.scss are requested, the bundle swaps the contents of that file with the contents of var/sass/app.built.css. Nice!

Excluding Sass Files from AssetMapper

Because you have .scss files in your assets/ directory, when you deploy, these source files will be copied into the public/assets/ directory. To prevent that, you can exclude them from AssetMapper:

1
2
3
4
5
6
7
# config/packages/asset_mapper.yaml
framework:
    asset_mapper:
        paths:
            - assets/
        excluded_patterns:
            - '**/assets/styles/**/_*.scss'

Note

Be sure not to exclude your main SCSS file (e.g. assets/styles/app.scss): this is used in AssetMapper and its contents are swapped for the final, built CSS.

How to Get Source Sass Files for 3rd-Party Libraries

The easiest way to get 3rd-party Sass files is via Composer. For example, see the section below to know how to get the source Sass files for Bootstrap.

But if you're using a library that isn't available via Composer, you’ll need to either download it to your app manually or grab it via NPM.

Using Bootstrap Sass

Bootstrap is available as Sass, allowing you to customize the look and feel of your app.

Note

The @use directive will be supported in Bootstrap version 6. Until then, use the deprecated @import directive to ensure overrides are applied.

An easy way to get the source Sass files is via a Composer package:

1
$ composer require twbs/bootstrap

Now, import the core bootstrap.scss from your app.scss file:

1
2
3
4
/* Override some Bootstrap variables */
$red: #FB4040;

@import '../../vendor/twbs/bootstrap/scss/bootstrap';

Tip

Importing through a relative path like this works, but Sass then considers Bootstrap to be part of your code rather than a dependency. As a result, the quiet_deps option will not silence the deprecation warnings Bootstrap emits. To get rid of them, import Bootstrap through a load path instead - see Register Additional Load Paths.

Using Bootswatch Sass

Bootswatch is also available as Sass and provides free themes for Bootstrap. An easy way to get the source Bootswatch Sass files is via a Composer package:

1
$ composer require thomaspark/bootswatch

Now, import the core Sass theme files along with bootstrap.scss from your app.scss file:

1
2
3
@import '../../vendor/thomaspark/bootswatch/dist/[theme]/variables';
@import '../../vendor/twbs/bootstrap/scss/bootstrap';
@import '../../vendor/thomaspark/bootswatch/dist/[theme]/bootswatch';

Don't forget to install the twbs/bootstrap main package as well because Bootswatch needed it. See the previous section for more details.

Deploying

When you deploy, run sass:build command before the asset-map:compile command so the built file is available:

1
2
$ php bin/console sass:build
$ php bin/console asset-map:compile

Limitation: url() Relative Paths

When using url() inside a Sass file, currently, the path must be relative to the root .scss file. For example, suppose the root .scss file is:

1
2
/* assets/styles/app.scss */
import 'tools/base';

Assume there is an assets/images/login-bg.png file that you want to refer to from base.css:

1
2
3
4
5
6
7
8
/* assets/styles/tools/base.scss */
.splash {
    /* This SHOULD work, but doesn't */
    background-image: url('../../images/login-bg.png');

    /* This DOES work: it's relative to app.scss */
    background-image: url('../images/login-bg.png');
}

It should be possible to use url() with a path relative to the current file. However, that is not currently possible. See this issue for more details.

Configuration

To see the full config from this bundle, run:

1
$ php bin/console config:dump symfonycasts_sass

Source Sass file

The main option is the root_sass option, which defaults to assets/styles/app.scss. This represents the source Sass file:

1
2
3
# config/packages/symfonycasts_sass.yaml
symfonycasts_sass:
    root_sass: 'assets/styles/app.scss'

Note

The root_sass option also supports an array of paths that represents different source Sass files:

1
2
3
symfonycasts_sass:
    root_sass:
        - '%kernel.project_dir%/assets/scss/app.scss'

Note

The root_sass option also supports glob patterns for source Sass files:

1
2
3
4
5
symfonycasts_sass:
    root_sass:
        - '%kernel.project_dir%/assets/scss/app.scss'
        - '%kernel.project_dir%/assets/lib/*.scss'
        - '%kernel.project_dir%/assets/admin/**/*.scss'

Sass CLI Options

You can configure most of the Dart Sass CLI options:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# config/packages/symfonycasts_sass.yaml
symfonycasts_sass:
    sass_options:
        # The output style for the compiled CSS files: expanded or compressed. Defaults to expanded.
        # style: expanded

        # Emit a @charset or BOM for CSS with non-ASCII characters. Defaults to true in Dart Sass.
        # charset: true

        # Register additional load paths. Defaults to empty array.
        # load_path: []

        # Whether to generate source maps. Defaults to true when "kernel.debug" is true.
        # source_map: true

        # Embed source file contents in source maps. Defaults to false.
        # embed_sources:

        # Embed source map contents in CSS. Defaults to false.
        # embed_source_map:

        # Don't print warnings. Defaults to false.
        # quiet:

        # Don't print deprecated warnings for dependencies. Defaults to false.
        # quiet_deps:

        # Print all deprecation warnings even when they're repetitive. Defaults to false.
        # verbose:

        # Deprecations to treat as errors. You may also pass a Sass version to include
        # any behavior deprecated in or before it. Defaults to empty array.
        # fatal_deprecation: []

        # Opt in to a deprecation early. Defaults to empty array.
        # future_deprecation: []

        # Deprecations to ignore. Requires the Sass binary to be at least 1.74.0. Defaults to empty array.
        # silence_deprecation: []

        # Don't compile more files once an error is encountered. Defaults to false.
        # stop_on_error:

        # Print full Dart stack traces for exceptions. Defaults to false.
        # trace:

Using a different binary

This bundle has already detected or installed for you the right binary. However, if you already have a binary installed on your machine and somehow the bundle has not been able to find it automatically - you can instruct the bundle to use that binary, set the binary option:

1
2
symfonycasts_sass:
    binary: 'node_modules/.bin/sass'

Tip

If a path in the binary option is explicitly specified - the bundle will just use it which means it will not try to search a binary itself or download it automatically for your system. To let the bundle take care of it automatically - do not specify the binary option.

Register Additional Load Paths

You can provide additional load paths to resolve modules with the load_path option.

For example, an alternative way to use Bootstrap would be to register the vendor path:

1
2
3
4
5
# config/packages/symfonycasts_sass.yaml
symfonycasts_sass:
    sass_options:
        load_path:
            - '%kernel.project_dir%/vendor/twbs/bootstrap/scss'

And then import bootstrap from app.scss with:

1
@import 'bootstrap';

Besides being shorter, this is also what makes the quiet_deps option useful: Sass only recognizes a file as belonging to a dependency when it is loaded through a load path. Third-party libraries tend to emit deprecation warnings you have no control over, and you can now silence them - while still seeing the ones coming from your own Sass files:

1
2
3
4
5
6
# config/packages/symfonycasts_sass.yaml
symfonycasts_sass:
    sass_options:
        load_path:
            - '%kernel.project_dir%/vendor/twbs/bootstrap/scss'
        quiet_deps: true

Handling Deprecations

Sass announces breaking changes through deprecations. Each one has an ID (such as import or color-functions) that you can act on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# config/packages/symfonycasts_sass.yaml
symfonycasts_sass:
    sass_options:
        # turn these deprecation warnings into errors, so they can't be ignored
        fatal_deprecation:
            - 'import'

        # opt in to a deprecation before it is active, to prepare for it
        future_deprecation:
            - 'import'

        # hide these deprecation warnings entirely
        silence_deprecation:
            - 'color-functions'

Each of these options also accepts a single ID instead of a list (e.g. silence_deprecation: 'color-functions'), and fatal_deprecation accepts a Sass version too (e.g. '1.33.0'), to treat every deprecation introduced in or before that version as an error. That version must not be newer than the Sass binary in use, otherwise the build fails with an "Invalid version" error.

Silencing the warnings coming from your dependencies - instead of a specific deprecation - is done with quiet_deps.

Note

silence_deprecation requires Dart Sass 1.74.0 or higher, which is more recent than the binary this bundle downloads by default. See Using a different binary.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version