ATOMIT - Optimizing CSS architecture
Introduction
In the world of web development, creating efficient and scalable user interfaces is crucial to the success of any project. To achieve this, a well-structured CSS architecture that facilitates code organization and maintenance is essential.
In this article, we'll look at a modern CSS structure that combines popular methodologies in web development: Atomic Design, ITCSS, and BEM. Atomic Design divides web interfaces into smaller parts, ITCSS helps organize CSS in a scalable way, and BEM provides a clear naming system for CSS classes.
Through this combination, named ATOMIT, we achieve a robust and easy-to-maintain CSS architecture that addresses both the modular structure of the design and the scalable organization of CSS code.
?? The code presented in this article was written using SvelteKit. Its ease of understanding allows it to be applied to any other programming language.
Scaffolding: The final structure
|--src/
| |--components/
| | |--01-atoms/
| | | |--Button/
| | | | |--Button.svelte
| | | | |--button.scss
| | | |
| | |--02-molecules/
| | | |--Card/
| | | | |--Card.svelte
| | | | |--card.scss
| | | |
| | |--03-organisms/
| | | |--Header/
| | | | |--Header.svelte
| | | | |--header.scss
| | | |--Footer/
| | | | |--Footer.svelte
| | | | |--footer.scss
| | | |
| | |--objects/
| | | |--o-col/
| | | | |--o-col.svelte
| | | | |--o-col.scss
| | | |--o-container/
| | | | |--o-container.svelte
| | | | |--o-container.scss
| | |
| |--routes/
| | |--+layout.svelte
| | |--+page.svelte
| | |
| |--styles/
| | | |--01-settings/
| | | | |--_s-borders.scss
| | | | |--_s-breakpoints.scss
| | | | |--_s-colors.scss
| | | | |--_s-fonts.scss
| | | | |--_s-layout.scss
| | | | |--_s-root.scss
| | | | |--_s-transitions.scss
| | | | |--_s-z-index.scss
| | | | |
| | | |--02-tools/
| | | | |--_t-functions.scss
| | | | |--_t-media-query.scss
| | | | |
| | | |--03-external/
| | | |--04-generic/
| | | | |--_g-generic.scss
| | | | |--_g-normalize.scss
| | | | |
| | | |--05-elements/
| | | | |--_e-anchors.scss
| | | | |--_e-images.scss
| | | | |--_e-lists.scss
| | | | |--_e-quote.scss
| | | | |
| | | |--06-typography/
| | | | |--_t-subtitle.scss
| | | | |--_t-title.scss
| | | | |
| | | |--07-keyframes/
| | | |--08-utilities/
| | | | |--_u-display.scss
| | | | |--_u-error.scss
| | | | |--_u-text-transformation.scss
| | | | |
| | | |--main.scss
|--index.js
Atomic Design: Basics and Principles
Atomic Design is a method for creating design systems invented by Brad Frost. Although it is design-oriented, we can pick up ideas that will facilitate the architecture of our CSS.
Atomic Design consists of several elements:
These are the smallest components of our design system. They are identifiable but indivisible elements and always require additional context to be meaningful within our application. Examples include buttons, labels, titles...
When we put two or more atoms together we create a molecule. They are elements that already have a meaning by themselves, although they are not totally independent: cards, a label with an input...
An organism is a composition of various molecules and atoms. Here, we're dealing with independent elements that make sense even when taken from one page and placed on another: a header, the course grid with its filters...
?? Atomic Design also mentions templates and pages, but this doesn't affect our style development since we rarely need to define classes at the page level. We define them by combining several organisms in our HTML.
With Atomic Design, we achieve a common language between the design team and front-end development. This greatly facilitates communication between them, although as a design-oriented system, it falls short when we need to define where to put styles like reset, normalize, box-sizing, or add functional or structural classes.
ITCSS: Organization and Scalability
ITCSS is a CSS architecture system developed by Harry Roberts. It's known as Inverted Triangle, representing how we visualize and organize our styles: starting from the least specific to the most specific selectors.
We'll organize our CSS into 7, 8, or as many layers as needed:
With ITCSS, we know where each type of style goes, even though the components folder can get really big. It's flexible, so we can organize the components however we want.
This type of organization gives us 3 characteristics (or benefits):
MAGNITUDE: Impact of one layer on the others.
CLARITY: Location of the selector.
SPECIFICITY: Strength level of the selector.
BEM: Clarity in CSS Naming
BEM (Block, Element, Modifier) is a class naming system that solves the main problems of choosing class names: it minimizes the risk of collisions, reduces the need for nested selectors, and clearly expresses the relationship between classes.
<!-- BLOCK -->
<div class="form">
<!-- ELEMENT WITH A MODIFIER -->
<input class="form__input form__input--border" type="text">
<!-- ELEMENT -->
<input class="form__input" type="text">
<!-- ELEMENT -->
<textarea class="form__input"></textarea>
<!-- ELEMENT WITH TWO MODIFIERS -->
<button class="form__submit form__submit--big form__submit--black"></button>
</div>
Improving What We Don't Like About BEM with Utility Classes
If we strictly follow BEM, each time we need to adjust a block or element, we'd need to create a new modifier. However, for tasks like centering text or applying specific colors, we often repeat the same process across different parts of our application. Creating multiple modifiers for these tasks can become tedious and challenging to manage, as any change requires modifying several areas of our application.
For a more effective way to handle these situations, it makes sense to combine BEM with utility classes:
// Card.svelte
<article class="card">
<img class="card__img" src="/architecture-css.png" alt="" />
<h3 class="card__title is-centered">CSS Architecture</h3>
<strong class="card__meta **is-centered**">Modular and Scalable</strong>
</article>
<styles>
.card {
&__img { }
&__title { }
&__meta { }
}
</styles>
// styles/utilities/u-text.scss
.is-centered {
text-align: center !important;
}
It's essential to clearly express the intention of the utility class. By using a prefix like is-, it's evident that this class is a utility and will modify the element it's applied to. These classes should be extremely specific, generally not containing more than one property. Additionally, when adding a utility class, we usually want that property to be applied, so it might be appropriate to add !important.
?? Use !important with caution, as it may conflict with linting rules.
领英推荐
BEM in Components
Using BEM in JS components might seem excessive and redundant because we don't experience class collision issues, and we can view a component as a block itself. However, it still offers several benefits:
ATOMIT: The Fusion of Atomic Design, ITCSS, and BEM
We can improve both systems by combining them. By adopting the Atomic Design structure, which includes atoms, molecules, and organisms, we can enhance the organization of the "components" folder in ITCSS, providing clearer guidance on how to organize components. Also, by recognizing that objects don't have decorative styles, we place them before atoms.
Decision Making
Detailed Explanation
styles/
The first two levels are aimed at preprocessors like Sass: defining variables for colors, typography, etc., as well as mixins and functions. These two levels do not produce any output in our CSS.
This layer will be used to style anything external to our HTML code. For example, when you've added a library (plugin) and want to modify its styles.
This layer is where we put generic styles like reset or normalize, define box-sizing... Here we start generating output in our CSS.
// CSS3 Variables
:root {
--vars(...);
};
// Asterisk selectors
*{};
// Selections
:selections{};
We define the styles of HTML elements like h1, img, a... It's where we start applying our own styles that will change the appearance of our application.
?? Things that cannot go before normalize, because otherwise styles are lost.
It will contain text properties, including responsive ones. These texts can be; headings, titles, subtitle...
This layer is intended to collect all the keyframes we need (animations).
@keyframes fadeOutDown {
0% {
opacity: 1:
transform: translateY(8);
}
100% {
opacity: 0;
transform: translateY(20px);
}
}
Utility classes like is-error, is-centered, etc., which will always override previous styles when applied. Only here is it allowed to use !important without making our CSS less maintainable.
?? Last option to use, don't overuse this layer.
components/
These are the smallest pieces of our design system. Here you'll find the most basic elements of our interface, like button, input, label, etc.
This layer groups atoms, such as cards, form-group, etc.
This layer groups all the components of our interface, such as header, footer, form, etc.
Conclusions
Using ATOMIT not only helps us organize our styles clearly but also ensures they can grow and be maintained over time. By breaking our code into atoms, molecules, organisms, and more, and using clear and consistent names, our CSS stays neat and easy to understand.
So, go ahead, join the community of developers adopting ATOMIT, and take your front-end projects to the next level. With a solid and well-organized CSS architecture, you're equipped to face web development challenges with confidence and achieve success.
Youtube canal AnimatiCSS - Web Developer - Front End Freelance
11 个月Hola! Me parece muy interesante ese enfoque, justo yo también he estado indagando sobre esto y he estado testeando previamente su utilidad, cuando pueda publicaré mi visión, para quien pueda serle útil. Gracias por la mención!
Desarrollador sénior en Sopra Steria
11 个月Excelente labor, estoy fascinado con esta perspectiva y la amplia gama de problemas que optimiza o resuelve de manera directa.