Customizing Volto Light Theme with @@custom.css

see also: 5. Extend VLT – Customizing Volto Light Theme — Plone Training 2025 documentation

  • in project project-title
    • add new directory theme with files:

      frontend/packages/volto-project-title/src/theme/
      - _main.scss
      - _variables.scss
      
    • Content of _main.scss

      @import 'variables';
      
      /* import ClassicUI based Theming custom styles */
      @import url('https://project-title.com/++api++/@@custom.css');
      
    • Content of _variables.scss = empty for now

    • Edit the custom.css at https://project-title.com/ClassicUI/@@theming-controlpanel#autotoc-item-autotoc-2
      example custom.css

      body h1.documentFirstHeading {
          color: #e40166 !important;
      }
      

TODO:

  1. In Production mode the import is in the client.xxxx.css in the start of first line:
@charset "UTF-8";@import url(https://kwk.dev3.acsr.de/++api++/@@custom.css); …
  1. Currently in development mode the additional css is imported as additional line

as a consequence the css is imported before the other css rules einstead of after all existing rules. Only adding !important can override some of the rules, but is helpful anyway for Q&D changes.

Relative urls

It is seems not possible to use generic relative urls in the SCSS code. You need to enter one of your working absolute domains in the url to make it work.

TBAL:_links to resources describing this SCSS limitation.

Workarounds for the relative url and order of css issues welcome.

2 Likes

Off topic, but @import is Deprecated, better to use '@use' if possible, then you 'keep track of variableas'

I assume this will not help with your problem.

1 Like

There used to be a 'hack' if it was not possible to 'boost its specifity':

body .all-classes #iall-ds .myclass  =>  body .all-classes #all-ids .myclass.myclass 

Not sure if this still works, but could be worth a try

1 Like

@acsr I guess that any @import that is not a SCSS file (in this case a URL) is treated as a CSS import, so it's pushed to the top by the preprocessor. Just make sure that the code is in the right place (_main.scss).

You don't need to import again @import 'variables in _main.scss. That's done automatically by the build process. Maybe the docs are not clear enough about this point. _main.scss gets injected after all the VLT and Volto default CSS. _variables.scss gets injected at the top (to be able to override any other variable).

I get the "convenience" of using @@custom.css from Classic, I guess because you want the ability to change it TTW. However, you could also leverage the flexibility of Volto: you could inject it using a slot, like the last implementation of the Theming component in latest VLT:

The slot definition:

The slot renderer:

The component is injecting custom CSS code, you can inject a plain <link> tag pointing to your custom CSS file in Classic.

I hope this helps.

1 Like

@espenmn I know that it is deprecated, but @use has some (well intended) limitations / differences (e.g. any rule is always imported only once, better traceback etc.) So I stuck with @import for now to avoid lighting the candle at two ends. As you said: if possible… So this needs further investigation.

@sneridagh THX, but actually the @import is there in _main.scss, but not the actual CSS rule. The intention is to pull that TTW editable (you got the point).

You are right, I simply followed the docs/training first literally.

Much better move. So I avoid the limitation of SCSS with relative urls and rewriting them or create compile failures.

Having the plain link in the header is OK, since it is only intended for temporary quick TTW fixes until a redeployment is possible.

I need to try it out.

Never saw that, nice to know. I put it in my "Kleines Besteckköfferchen" -> “small cutlery set suitcase” that is only by accident abbreviated as scss. :grimacing: