Write the styles
A CAITS project writes its styles in SCSS files, apart from the HTML. init installs sass, and Vite compiles the SCSS: you have nothing to configure. This page shows where each stylesheet goes, how they share values, and how to name the classes.
Three kinds of stylesheets
| Stylesheet | Where | Who imports it | The pages that load its CSS |
|---|---|---|---|
| The stylesheet of the app | src/routes/_frontend/style/app.scss | The layout | All the pages of the layout |
| The stylesheet of a page | Next to the page: src/routes/_frontend/home-page.scss | The page (+page.marko) | This page only |
| The stylesheet of a component or a view | Next to it: MessageBoard.scss | The component, or the view | Each page that shows it |
src/routes/_frontend/+page.marko
import "./home-page.scss";The build makes one CSS file for the layout, and one for each page: the CSS of its stylesheet, and that of the components and the views that it shows. Each page loads the file of its layout, then its own file. A component that many pages show has its CSS in a file that these pages share.
The stylesheet of the app
The layout imports style/app.scss. This file loads the other files of style/ with @use, and Sass compiles all of them into one CSS.
The stylesheets of the routes
src/routes/_frontend/
+layout.marko import "./style/app.scss";
+page.marko import "./home-page.scss";
home-page.scss @use "values"; then @media (max-width: values.$narrow) { … }
style/
app.scss the fonts, then @use "theme"; @use "elements"; @use "page"; @use "menu";
_values.scss the Sass values: $page, $narrow, $phone, $grain
_theme.scss the colors and the fonts, as CSS variables
_elements.scss the HTML elements
_page.scss the parts of each page: its width, the eyebrow, the lead
_menu.scss @use "values"; then width: values.$page;- A partial is a file whose name starts with
_. Sass does not compile it alone: its CSS goes into the stylesheet that loads it, at the place of its@use. - The order of the
@useinapp.scssis the order of the CSS. Put the general rules first (the theme, the elements), then the parts of the pages. - A partial loads the partials that it needs. Sass puts the CSS of each file once only in a stylesheet, also when many files of this stylesheet load it.
@usetakes the name of the file without_and without.scss. Use@use, not@import: Sass will remove@import.
What the browser gets
The browser gets CSS only, never SCSS:
npm run build: Sass compiles the SCSS, then Vite minifies the CSS: each CSS file is one line, without the comments.npm startsends these files.npm run dev: Sass compiles the SCSS, but Vite does not minify the CSS: you can read it in the browser. When you save a stylesheet, the page changes, and does not reload.
The names of the classes
All the classes of the app are global. Thus each class of a page, a component or a view starts with its name (the BEM convention):
MessageBoard.scss
.message-board { // the block: the view
&__composer { … } // .message-board__composer: a part of the view
&__message { … }
}MessageBoard.marko
<form class="message-board__composer">The classes that all the pages use are in the partials of style/: the example has button, eyebrow and lead. The name of a keyframe is global too: @keyframes message-board-enter.
A file whose name ends with .module.scss also works: import styles from "./MessageBoard.module.scss", then class=styles.composer. Its class names are unique to the file. But TypeScript does not check the names in styles.
Fonts
Install the fonts with npm, for example from Fontsource, and load them in app.scss:
style/app.scss
@use "@fontsource-variable/geist";
@use "@fontsource/instrument-serif/400-italic.css" as instrument-serif-italic;Sass gives a module the name of its file. When this name is not a valid name (400-italic), give the module another name with as. The build puts the files of the fonts in the app: the pages load nothing from another site. Then give the font to the views with a CSS variable (--font-sans).
The architecture rules
The architecture check reads the stylesheets, as it reads the code:
- The routes keep their stylesheets in
src/routes/_frontend/style/, next to a page or a layout, or next to a component incomponent/. A view keeps its stylesheet in its folder. - A stylesheet does not go up a folder (
../): it loads the files of its folder, of the folders below, and ofstyle/by their name. The shortcuts (#context/,#frontend/) do not work in a stylesheet: Sass reads#as the start of a fragment of a URL. - A context does not load a stylesheet of the routes, also by the name of a partial of
style/.
Types and tests
quality/caits/tsconfig.json includes the types of Vite (vite/client): TypeScript accepts import "./MessageBoard.scss".
The unit tests do not compile the styles: a test of a view does not depend on them. The end-to-end tests run on the build, with its CSS.