Improve your CSS with these 5 principles.





Writing CSS is a fairly simple and straightforward process, then why does it require some more principles and best-practices?



As the scale of the project and the number of people working on it increase, more and more clearly new difficulties begin to appear that can cause serious problems in the future. Code duplication, complex property redefinition chains, using! Important, remaining and unused CSS properties from remote HTML elements, and so on. Such code is more difficult to read and fix.



Writing CSS in a professional way will make the code more maintainable, extensible, understandable, and clean. Let's take a look at 5 simple and very effective principles that take your CSS to the next level.






Naming principle



“In computer science, there are only two complex things: cache invalidation and naming” - Phil Carleton


Properly naming and structuring your CSS selectors is the first step to making your CSS more readable, structured, and clean. Defining rules and restrictions in a naming convention makes your code standardized, reliable, and easy to understand.



That is why concepts such as BEM (Block-Element-Modifier) , SMACSS (Scalable and Modular Architecture for CSS) and OOCSS (Object Oriented CSS) are popular among many frontend developers.



Low specificity principle



Overriding CSS properties is very useful, but in more complex projects, things can get out of hand fairly quickly. Overriding chains can become very long and complex, which will force you to use !important



to solve specificity problems, which can be easily lost when debugging code or adding new functions



 /*     */ .card {} /*     */ .card .title {} .blog-list .card img {} .blog-list .card.featured .title {} #js-blog-list .blog-list .card img {}
      
      





Browser and specificity



One of the benefits of following the principle of low specificity is performance. Browsers parse CSS from right to left .



Let's take a look at the following example:



 .blog-list .card img {}
      
      





Browsers will “read” the selector as follows:



  1. Find all <img> tags on a page
  2. From them, select elements that are descendants of the class .card
  3. From them, select elements that are descendants of the .blog-list class


You can see how selectors with high specificity affect performance, especially when we need to globally select a common element like div , img , li , etc.



Using the same level of specificity



Using CSS selectors with low specificity combined with the BEM methodology or one of the other naming principles mentioned in the previous section, we can create powerful, flexible, and easy-to-understand code.



Why use CSS classes? We want to adhere to the same level of specificity, while remaining flexible and able to select multiple elements. Element selectors and id selectors do not provide the flexibility we need.



Let's rewrite the previous example using BEM and sticking to low specificity.



 /*     */ .card {} /*      */ .card__title {} .blogList__image {} .blogList__title--featured {} .blogList__img--special {}
      
      





You can see how these selectors are simpler, clearer, and can be easily redefined and extended if necessary. And keeping their specificity low (single class), we guarantee optimal performance and flexibility.



DRY principle



The DRY principle (Don`t repeat yourself, do not repeat yourself) can also be applied to CSS. Duplication in CSS can lead to code bloat, unnecessary overrides, poor support, etc. This problem can be fixed with proper code structure and quality documentation.



Storybook is a great free tool that lets you create an overview of the available web interface components and write quality documentation.



 /*    DRY */ .warningStatus { padding: 0.5rem; font-weight: bold; color: #eba834; } .errorStatus { padding: 0.5rem; font-weight: bold; color: #eb3d34; } .form-errorStatus { padding: 0.5rem 0 0 0; font-weight: bold; color: #eb3d34; }
      
      





Let's refactor the code following the DRY principle



 /*    DRY */ .status { padding: 0.5rem; font-weight: bold; } .status--warning { color: #eba834; } .status--error { color: #eb3d34; } .form__status { padding: 0.5rem 0 0 0; }
      
      





Principle of sole responsibility



Using the sole responsibility principle in CSS, you can be sure that CSS classes are easily extensible and redefined. Let's look at the following example



 .button { padding: 1rem 2rem; font-size: 2rem; border-radius: 0.2rem; background-color: #eb4934; color: #fff; font-weight: bold; } .button--secondary { border-radius: 0; font-size: 1rem; background-color: #888; }
      
      





It can be seen that if you need to expand the .button class with the .button - secondary modifier, you will have to perform many overrides, although we only want to change the background color, keeping the styles default.



The problem is that our .button class has several roles:





This complicates the extension of the CSS class and its integration with other classes. With that in mind, let's improve our CSS with BEM and OOCSS.



 /*   */ .button { padding: 1rem 2rem; font-weight: bold; color: #fff; } /*   */ .button--radialBorder { border-radius: 0.2rem; } .button--large { font-size: 2rem; } .button--primary { background-color: #eb4934; } .button--secondary { background-color: #888; }
      
      





We have broken the styles of our button into several classes that can be used to extend the base class. If necessary, we can apply modifiers and add new ones as the design changes or new elements are added



The principle of openness / closeness



Software entities (classes, modules, functions, etc.) must be open for extension, but closed for change ”



We have already used the open / closed principle in the previous examples. All new features and options should be added by extension. Let's look at this example.



 .card { padding: 1rem; } .blog-list .card { padding: 0.5em 1rem; }
      
      





The .blog-list .card selector has several potential problems:





Let's rewrite the previous example:



 .card { padding: 1rem; } .blogList__card { padding: 0.5em 1rem; }
      
      





We fix the problem if we use a single class selector. With this selector, we can avoid unexpected effects and do not use conditionally nested styles.



Finally



We looked at examples of how applying these few simple principles can significantly improve the approach to writing CSS:





Thank you for taking the time to read this article. If you find it useful, you can share it or leave a comment.



All Articles