Why IDs Can be Problematic in CSS
- How to choose the correct CSS selector?
- CSS Parsing
- Conclusion / Tips
IDs are unique, and classes are reusable. By this point, we all already know this. But, telling someone to do not use IDs, because they are not reusable. Could lead to confusion and leave some knowledge gaps. I remember many colleagues, myself included, asking questions like:
Why using IDs is considered bad practice? Are they not a tool as part of the CSS standard? If we have unique elements on a page and their appearance is a function of that particular element, why not use them as style selectors?
This rule comes from the Object-Oriented CSS
method by Nicole Sullivan. Made to simplify the process of scaling CSS for thousands of pages. And, as the creator said in the Wiki:
"It is an approach for writing CSS that is fast, maintainable, and standards-based. It adds much-needed predictability to CSS. So that even beginners can participate in writing beautiful websites."
This approach has to main principles:
- Separate structure and skin. Define repeating visual features as different skins that can you can mix-and-match with objects. In consequence, achieve a large amount of variety without writing unnecessary code.
- Separate container and content. Don't use location-dependent styles. Based on the idea that an object should look the same no matter where you put it.
This rule is not there without a purpose. A unique element on a given page will rarely need a unique style. And there is also the concern that IDs are highly specific and very powerful. Because they will prevail to any other mix of selectors, the only way to override one is using more of them. And, this can become an issue in an environment where many independent developers work on the same site. In this context, sticking to the rule of avoiding IDs makes perfect sense and is a wise decision.
It is true that as a website
grows, it develops a language of a consistent style. And consistent design makes use of reusable classes rather than specific IDs. But, this rule may have encouraged the idea that using ID selectors can cause issues. And some developers
only repeat this rule, without asking why or encouraging their colleagues to find out more. This situation fed from fear and lack of understanding of how they work and how to use them.
Before HTML5 we didn't have semantic elements like footer, head, article, nav, main, etc. And, if we wanted to give structural meaning to the content. We used things like:
But, if we can’t use any of these HTML5 elements, there is nothing wrong with using IDs to reference unique design elements. It makes perfect sense, as they contribute to the organization and maintainability of the stylesheet. Produce a more concise and easy to understand selector structure. And, they allow overriding styles added from frameworks and plugins without recurring to a long string of class names or !important declarations.
We should not perceive them as evil. It is fine to use IDs as long as you establish some guidelines to use them. Be aware that this always includes asking yourself if that is what you need.
When websites and apps evolved and started using more components. It was more practical to rely more on classes than IDs to avoid issues and duplications.
This post tries to highlight the importance of considering our necessities and the context of our project. And not to tell you to apply a rule to all your CSS
code. As well as bring some light into the different factors involved to decide on our approach.
Sometimes some questions do not have a strict right or wrong and often depend on our priorities. And, to know what our priorities are, we must also be aware of our needs and goals. You understand your project code and the context of it more than anyone. And if you think it makes sense to write CSS with IDs, then use them, since they are a valid part of the CSS standard.
The development world is changing every day, what is relevant now, might not be so in the future. And neither should we do what someone wrote on the internet without developing our judgment.
Why is this important? Because we should strive to do professional web development, and writing quality CSS is an essential part of doing it. We should also try our best to make our work understandable. Not only on environments with many colleagues but also in your projects. And, that means to write code with consistency. And if we want high-speed websites, we need to optimize them, and consistency is the foundation for optimization. Because, without it, further steps trough optimization could be even harder.
Keep in mind that, as humans, we do not always write perfect code. Useful, efficient, consistent, maintainable, and understandable. But, that is what we should strive for as professional web developers.
In the end, we should understand the rules, practices, and guidelines. And adopt them or not, understanding the benefits and costs that they imply.
We can opt for a different approach depending on the size and characteristics of our projects. But always keep in mind the big picture. We are not good developers if we do not recognize the consequences of our work.
How to choose the correct CSS selector?
It is not harmful, dangerous, or unmaintainable about using !important, IDs or classes. As a part of CSS, they are tools. And as with every tool one can use them wrong. So, we should learn to identify when it is best to use each one of these tools.
There are various factors involved in choosing the best approach for you. The main ones are maintainability, performance, specificity, and CSS parsing.
Avoid unnecessary work by avoiding repetition of declarations. And make sure that you create code as easy to maintain as possible. Always try to ask yourself:
- How much time a new developer needs to be familiar with the project?
- How much time does it take to introduce a new feature?
- How much time and effort it takes to change something?
- Does change on one thing often break something else in the code?
- Can many people work on the same codebase without conflicts?
Performance is one of the most important goals to aim for when optimizing a website. The faster, the better. We already know that the user experience improves when they get what they want faster. And with this, conversion rates also increase.
But, keep in mind that improving rendering performance is not as consequential and useful as loading performance. With this I mean to not omit specific tags, because it is not as helpful as compressing images. These types of calculations get done so fast that it doesn't matter in practice.
Selector performance is irrelevant because the price for it is terrible. We micromanage our work for gains that aren’t noticeable. In the broad perspective of things, CSS optimization should be one of the last priorities when trying to speed up web applications.
Other optimizations come with less cost and more noticeable gains.
That doesn't mean that some selectors are not slower than others, and thanks to how they work, it is possible that this will always be like that. But, it is best to let the rendering engine handle the selector optimization.
A large CSS file takes longer to transfer (Network is the biggest bottleneck in a website performance), they also take longer to parse, and it takes longer to construct the DOM for the HTML.
A bigger problem is to have a lot of expensive selectors, known as style bloat. It happens a lot when importing an entire CSS framework like Bootstrap or Foundation while using less than 10% of those styles. Another example is when a developer appends classes to the end of the stylesheet as the project changes and grows.
The Specificity on CSS decides which styles get applied to HTML elements and which ones don’t. The more specific the CSS selector is, the more level it has, and this defines the style to apply.
If there are two or more conflicting CSS rules to style the same element, then the web browser will follow specific rules to define which one is most specific, and as a result, will win.
5 levels define the specificity of a CSS selector:
How to calculate the specificity?
The specificity value starts at 0. Add a 1 for each element or pseudo-element selector. 10 for each attribute, class, or pseudo-class. 100 for IDs, 1000 for inline styles. And !important beats them all.
By understanding CSS specificity and how the styles get applied, you make sure that the design that you want gets displayed on your project. And, that you have an organized code and without conflicts between selectors.
Don’t forget there are extra points to remember:
- Equal specificity: The latest rule gets applied. The lower the position in the style sheet. It is closer to the element to style, hence this rule will win. Example:
background-color: red; // WINS
- Inline styles override any external style sheet (except !important selectors): Using them is not a good practice. Because it violates the principle of maintaining styles and structure separate. But they are useful when debugging problems.
- Universal selector and inherited values have a specificity of 0
It’s always a good practice to maintain the specificity levels low. Thus, you will avoid conflicts between selectors. And, when they appear, you can solve them with less effort.
This is a crucial part of building the CSS Object Model. The browser needs to transform the text into something it can use for style layouts. This transformed structure created by the browser's name is CSSOM (CSS Object Model).
This process assigns a place to the CSS selectors inside a tree. CSS selectors inside others will be underneath the tree attached to their parents. The CSS parser read the nested selectors from right to left (the rightmost element in a compound selector is the key selector).
To summarize this in our context, the shorter the selector, the better.
ADVANTAGES & DISADVANTAGES
- You can share and reuse classes between elements, and use many of them on the same HTML element.
- In an environment with many developers working on the same codebase. It may be simpler to know that CSS uses classes and reserve IDs for other purposes. As a result, and depending on your approach, it may be easier to use only classes to define styles instead of a combination of classes and IDs.
- Removing all the IDs reduce the possibilities of ending in a specificity war induced by ourselves.
- When you only use class selectors, you can have more confidence when introducing new features and that your code will work as expected. Considering that each selector has equal specificity.
- You can use IDs as fragment identifiers for referring to a point in your website. Because they have HASH value in the URL: http://mydomain.com#footer, which will scroll the page to show that element when you click that link.
- They can help you to create a structure on your styles, which is very useful once your CSS file grows.
- IDs have a much higher specificity than classes. A class on its own can’t overwrite styles belonging to an ID. And this makes them very useful to override styles expressed elsewhere (from frameworks like Bootstrap or Foundation).
Conclusion and tips
- Styles should be easy to override and extend, so it is maintainable and easy to work with them.
- Always try to avoid classes and ids
- Be cautious around OOCSS, BEM, Atomic CSS, and similar conventions. Look at how they help and how they hinder you. They try to address some of the issues of complex web development, but they also limit your freedom and possibilities.
- Don’t stop using IDs without considering the advantages and disadvantages that apply to your context. Be aware of where they can cause conflicts. And how to avoid them. Someone telling you not to use them at all is not wrong, but they are not right either.
- It’s all about context, and you know yours better than anyone else. If you want to keep and ID for completeness or fragment identifiers, then do it. It’s your decision.
- We can’t build a successful web project without a proper system or method. CONSISTENCY is key.
- We should worry about doing what matters and keeping the big picture in mind.
Subscribe to get your daily round-up of top tech stories!