As we know today, the CSS language is an essential part of the web. It gives us the ability to draw the way elements are presented on a screen, web page or other media.
It is simple, powerful, and declarative. We can easily implement complex things like dark/light patterns. However, there are many misconceptions and misuses of it. These can turn CSS markup into complex unreadable and unscalable code.
How can we prevent this from happening? By following best practices and avoiding the most common mistakes. In this article, we will summarize the 5 most common mistakes and how to avoid them.
1. Not designing in advance
Doing something immediately without thinking about it may get the job done faster, and it gives us a sense of speed and accomplishment. But, in the long run, this will have the opposite effect.
Before writing code, it is important to think it through. What approach will we take to designing the component? Do we want to build our components in an atomic way? Do we want to create a composable utility system? Do we want a UI library that is already built in? Do we want our CSS to be globally scoped or per-component scoped?
Having a clear goal will help us choose the best tool for the job. This will save us from redundancy and DRY violations . There are many valid ways to design an application. The most common ineffective one is improvisation.
Our code must be predictable, easy to extend and maintain.
Look at an example.
In the example above, we can see how everything becomes readable and clear when using CSS variables for the theme design. The first .card definition looks completely random and this component is not easily extendable.
2. CSS Code Smells
Code Smell is a hint that there is a bug somewhere in the code, and developers can use this smell to track down the problem in the code.
Code smells are not bugs, and they do not prevent the system from working properly. They are just bad practices that can make our code harder to read and maintain.
Here is a list of some of the most common ones and how to overcome them.
It is common to use the :: notation in pseudo elements and pseudo classes. It is part of the old CSS specification and browsers continue to support it as a fallback. However, we should use :: in pseudo elements such as ::before, ::after, ::frist-line… We should use :: in pseudo-classes such as :link, :visited, :first-child…
Using String Concatenation Classes
It is very popular to use the Sass preprocessor to help with our CSS codebase. Sometimes when trying to DRY, we create classes by concatenating & operators.
There seems to be no problem until developers try to search for the .card-selected class in the code base. Developers will have a hard time finding this class.
Incorrect use of abbreviations
CSS abbreviations are great and allow us to avoid overly lengthy code. However, sometimes we don’t use them intentionally. Most of the time, background abbreviations are used by accident.
Incorrect use of !important
The !important rule is used to override specificity rules. Its use is mainly focused on overriding a style that cannot be overridden in any other way.
It is usually used in scenarios where more specific selectors can do the job.
Forced use of attribute values
It is quite common for a magic number to appear in the CSS codebase. They create quite a bit of confusion. Sometimes we may find long numbers in the code because the developer is trying to override a property he is not sure about.
3. No scoping of CSS class names
Due to the nature of the CSS language, it is easy for elements to be inadvertently stereotyped by a bad class name. This problem is very frequent, so there are quite a few solutions to this problem.
In my opinion, the two best ones are.
- using naming conventions
- CSS Modules
The most popular naming convention is BEM 101. It stands for Block, Element, and Modifier methods.
Its purpose is to create unique names by allowing developers to understand the relationship between HTML and CSS.
My biggest concern with the BEM method is that it is time consuming and relies on the developer to implement it. CSS modules happen on the preprocessor side, which makes it error free. It generates random prefixes/names for our CSS module class names.
4. Using px units
Pixels are used quite often because it seems easy and intuitive to use at first. The truth is quite the opposite. For a long time now, pixels are no longer based on hardware. They are simply based on an optical reference unit.
The px is an absolute unit. What does this mean? That we can’t scale properly to meet more of them.
What should we use instead? Relative units are the way to go. We can rely on these to better express our dynamic layout. For example, we can use ch to express the width of a div based on the number of characters.
Typically, the most common replacements for px are rem and em. They represent the relative size of a font in a box-to-text relative fashion.
- rem indicates the size relative to the root font-size.
- em indicates the size relative to the element size.
By using rem, we will be able to express the layout according to the user’s preferred font size.
In the screenshot above, we can see how the rem unit-based layout can scale and adapt to different default font sizes.
5. Ignore browser support
When starting to develop a website, it is crucial to define our target audience. It is common to skip this step and go straight to coding.
Why is it crucial? It helps us to understand on which devices our application will be used. After that, we can define which browsers and which versions we will support.
We can still work towards accepting later features like subgrid, as long as we can provide the proper fallbacks. It is always a good idea to define an incremental feature experience. As a feature gains more support, we can gradually discard its fallback.
Tools like caniuse.com or browserslist.dev are helpful in this regard. The autoprefixer feature that comes with tools like postcss will help us get broader support for CSS.