CSS Styling
Styling Zermatt modules / Build a custom theme.
Zermatt comes with a powerful way to style modules and themes. Whether with Zermatt-native SASS support, or with TailwindCSS, or any other implementation.
Architecture
When running npm run dev
or npm run build
:
- Zermatt scans for all
.scss
files ofweb/zermatt/**/
folders invendor
,app/code
and the current theme. - Those files are processed in order to deal with hierarchy (see below).
- A
zermatt-lock.scss
file is generated and contains one@use
per matching.scss
file. - ViteJS processes this all-in-one file with the
scss
preprocessor fromvite.config.js
. - This creates a
dist/zermatt.css
file that is used inMaddlen_Zermatt::view/frontend/layout/default_head_blocks.xml
Zermatt exposes a zermattLock()
function that can be used to generate a custom zermatt-lock.scss
.
Hierarchy
In short: theme > app/code > vendor
Location | File | Content |
---|---|---|
vendor | A.scss | .class_A { color: red; } |
vendor | B.scss | .class_B { color: black; } |
app/code | A.scss | .class_C { color: blue; } |
app/code | C.scss | .class_D { color: green; } .class_E { color: yellow; } |
theme | A.scss | .class_F { color: purple; } |
theme | D.scss | .class_E { color: lime; } .class_G { color: olive; } |
Result:
.class_B { color: black; }
.class_D { color: green; }
.class_E { color: lime; }
.class_F { color: purple; }
.class_G { color: olive; }
In other words:
- Hard rewrite: use a file named the same as one lower in the hierarchy.
- Soft rewrite: use a file named any custom way and update the SCSS as usual.
- Custom: use a file named anything you like, and write SCSS as usual.
Writing SCSS
Zermatt reads and compiles all .scss
files that are in the web/zermatt/**/
folders in vendor
, app/code
and the current theme.
So it is possible to write SCSS in any location in those folders, for example:
.
βββ app/
β βββ code/
β β βββ Vendor/
β β βββ Module/
β β βββ view/
β β βββ frontend/
β β βββ web/
β β βββ zermatt/
β β βββ modules/
β β βββ vendor-module.scss
β βββ design/
β βββ frontend/
β βββ Vendor/
β βββ theme/
β βββ web/
β βββ zermatt/
β βββ ui/
β β βββ typography.scss
β β βββ forms.scss
β βββ modules/
β β βββ // Rewrites vendor-module.scss from Vendor_Module
β β βββ vendor-module.scss
β β βββ // Rewrites from /vendor
β β βββ some-scss-file-somewhere.scss
β βββ layout.scss
βββ vendor/
βββ */*/
βββ some-scss-file-somewhere.scss
@use or not?
@use
(the deprecated @import
) is not required in your SCSS files as long as the imported file is in a web/zermatt
folder.
If, for some reason, your SCSS files are not in a web/zermatt
folder, then you can use @use
to import them.
You may also want to completely bypass Zermatt SASS layer (see "Full custom theme") and use your own implementation.
You will then need to create a .scss
entry point file which will contain your imports.
Full custom theme
It is possible to completely bypass all existing .scss
files and use a custom implementation in a theme.
Zermatt provides several options.
Option 1: with SASS
The fastest option is to create a .scss
entry file in the web/zermatt
folder of the theme.
Then build around that file.
Implementation:
- Create a
custom-name.scss
entry file in theweb/zermatt
folder of the theme - In
vite.config.js
file:
// replace
await zermattLock()
// with
await zermattLock([path.join(path.dirname(fileURLToPath(import.meta.url)),
'/custom-name.scss')])
- Write SCSS the usual way
Option 2: without SASS
In vite.config.js
file:
// replace
await zermattLock()
// with
await zermattLock([])
And do your thing.
Note: the dist/zermatt.css
output file is still generated (with a fake harmless content)
in order to avoid network errors as the layout is still calling it. See "Architecture".
Using TailwindCSS
Considerations about using TailwindCSS
The nature of TailwindCSS is so that it would need to watch too many .phtml
(or worse PHP) files to work which is bad for performance.
This is why, except if you know what you are doing, it is highly recommended to scope TailwindCSS to the current theme only.
This implies building a theme from scratch (which is a totally fine option) or deal with conflicts between TailwindCSS and Magento CSS.
That being said, adding TailwindCSS to Zermatt is straightforward.
- Init TailwindCSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
- Create input.css
@tailwind base;
@tailwind components;
@tailwind utilities;
- Update tailwind.config.js to scan the correct files
export default {
content: ["../../**/*.phtml"], // .phtml files in the current theme
}
- Update index.html
<script type="module" src="/zermatt.js"></script>
<link rel="stylesheet" href="/input.css">
- Update vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';
export default defineConfig({
css: {
postcss: {
plugins: [
tailwindcss(),
autoprefixer(),
],
},
},
build: {
manifest: true,
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
if (assetInfo.name && assetInfo.name.endsWith('.css')) {
return 'assets/zermatt.css'
}
return 'assets/[name].[hash][extname]'
}
}
}
}
})
Tip: in order to restyle non-tailwind phtml files even outside of the theme, use TailwindCSS @apply
directive to reconstruct css classes.
This is very useful in the context of Zermatt to be able to easily style phtml files from vendor
or app/code
Zermatt modules.
Conventions and best practices
Namespace files
Ex: vendor-module.scss
. To be enforced especially if file lives in app/code
or is meant to be distributed.
Scope CSS within their matching Zermatt module
Ex:
<div class="vendor-module" x-data="Zermatt.Module('Vendor_Module')">...</div>
with
.vendor-module {...}