Architecture & exitCSS
Concept from ITCSS
ITCSS is a project architecture designed by Harry Roberts. The goal is to ensure a good maintenance and scalability of the codebase, by following some conventions and rules.
ITCSS means Inverted Triangle CSS, and represent the complexity graph how your code must be organized.
The triangle represents the CSS selectors order : from generic to explicit, from low-complexity to hight-specifity, or from global zones to localized ones.
Glsass and exitCSS
In Glsass, the ITCSS is slightly modified, to allow more flexibility and take advantage of Sass Modules. It's why we used the exitCSS (for EXtended ITCSS) term to differntiate it.
Since we don't have to import all files at the root file (thanks @use
and
@forward
rules), there may no need for you to import tools
inside your
index.scss
.
This is the layer structure:
- Root (Settings + Tools)
- Graphics
- Generic
- Elements
- Objects
- Layouts
- Components
- Scopes
- Themes
- Utilities
Root
The Root
layer is a combination of the Settings
and Tools
folders. The
settings contains main variables and definitions used in the framework. The
tools is about Sass mixins and functions.
Even if there is not root
folder inside Glsass, it's a term to reference all
part of the framework which doesn't "produce" CSS code, and are only about
configurations.
Graphics
Similar to the settings layer, Graphics
also contains many variables. But all
of them are only about interfaces and graphics : border
(width and radius),
font
styles, etc.
If this variables aren't initilize inside the settings folder, it's to take
advantage of global functions (like cv
).
Generic
This is the layer which will generate CSS code. It contains reset and normalize
styles, box-sizing
definitions and some shared styles (like default
margin-bottom
on some elements).
Elements
Also called Base, there is rules for styling basic HTML elements (headings, links, lists, etc.) to adjust some default browser behaviors/feelings.
Objects - .o-*
The first class-based selectors start here, it defines undecorated (or at
least, as much as possible) design patters. Some objects like o-media
are
known from OOCSS and are present is this layer.
Layouts - .l-*
Glsass doesn't provide layout classes because it will depend of your HTML structure. You can add your own folder and files if you use this layer logic (header, main, hero, footer).
To avoid adding more complexity in your files organization, layouts can be considered like "big" components, so you don't have to use this layer. The goal remains to keep an understandable block architecture.
Components - .c-*
In this layer, you have specific UI "components" (or UI blocks), so the majority of your work will go here. A component is a well-designed piece of UI that can be reused in differents needs and areas. Glsass provide basic and customizable components (alert, button, card, etc.), that you can use or not, modify theme from the Sass parameters or build your own.
But if a component is create to be reusable anywhere, is it still legetimate to
use this layer for built a UI block for a unique need? In some cases, you can
choice to create a "Modules" folder (.m-*
).
By convention, a component
can be use a lot of time, in different areas of contexts. For a module, the goal
is to create a chunk of UI for a specific use. The goal is just to organize your
UI folders and indicate to the others developers, which ones is reusable and
which are not.
Since this layer is specific of the design to build, Glsass
doesn't foward any module. But it can be use to add a new behavior to an
existing (external) component (like a m-button
for example).
Scopes - .s-*
Scoped context in CSS should be used sparingly. The goal is to solve very
specific and local problem. The perfect example is when you use a CMS with a
WYSIWYG editor. You may add a class like .s-cms-content
around the generated
content, and then target HTML elements (ul
/li
, a
, hn
).
Before use it, be sure that you cannot achieve the expected result otherwise, to avoid additional complexity of your codebase. And be careful about the weight/priorities of the new classes.
In some cases, you can also have a pages
folder to manage some page behavior.
Generally, it will use the .page-*
prefix (.page-home
, .page-about
, etc.)
and it can help you to manage bigger "scope" from your app.
To finish, given that behavior of the pages
layer, you may want to move it
before (before Layouts -> a page is a "large" layout), or after (after Themes ->
CSS rules have a huge specificity). It's for you to see, depending of your
organization and needs, the goal is just to keep some logic in the code
distribution.
Themes - .t-*
This layer is similar to the previous one, because it lust be used only for
specific case, especially if you work with
Stateful Themes.
But since with Sass syntax you can use the parent selector &
, theming can be
applied in components directly.
The theming can also be set from the
settings variables, so this layer can be used (or not) depending of your code
organization.
Helpers - .h-*
Helpers are special classes to create special behaviors on an elements.
This layer can find it very similar to the utilities
layer, there is one
difference which make it different: if an utility class add (mostly) one CSS
rule, a helper class add several ones.
Despite the similarities, it's a good pratice to separate them to better distinguish.
Utilities - .u-*
This is (normally) the last layer of your stack. Glsass already contains a lot of utilities classes, mainly inherit from Bootstrap, Tachyon, Tailwind or other CSS frameworks.
Namespace prefixes
Starting from the objects layer, all classes must start with a namespace prefix to easily identify the scope of the class.
For example, if you use a block
, without the prefix it's difficult to
determinate what is the purpose. But if it was a o-block
, it may be about to
create a simple flow layout, instead of a c-block
, a component which can
define border, background-color or whatever aesthetic rule.
This naming principe is called BEMIT (for BEM + ITCSS), and following the work of Chris Pearce (CSS Guidelines), we can use other prefixes like:
is-*
andhas-*
for temporary states_-*
for hacksjs-*
for classes need to be "accessible" for JavaScript (not for styling!)qa-*
for QA testing and simplify automated UI tests
Of course, you can also use any other prefix if it make sense and is documented to ensure other members of your team will understand the behavior and logic behind.
What's about vendors?
Vendors isn't a real layer for Glsass, because it will contain others librairies. But is some cases (slider/carousel, datepicker), you may need to include another (S)CSS files in your codebase.
Because of the specificity or rules, it should be after the components layer. But since you may not have the control of the CSS code, the simply way is to add it at the end.
Each case are specific, it also to you to move it at the good place depending of the generated code.
Alternative setups
In some case, you can also find other derivatives of this organization, for example:
- Core (settings + tools + graphics)
- Basics (generic + elements)
- Patterns (objects + layouts + components)
- Contexts (scopes + themes)
- Overrides (helpers + utilities)