Many of the technologies we all use in our day-to-day lives have some very humble beginnings, and web technologies are definitely no exception. They have evolved and transformed over time into the complex, yet powerful tools that we get to use on a daily basis. Cascading Style Sheets, or CSS, is one such tool […]
Many of the technologies we all use in our day-to-day lives have some very humble beginnings, and web technologies are definitely no exception. They have evolved and transformed over time into the complex, yet powerful tools that we get to use on a daily basis.
Cascading Style Sheets, or CSS, is one such tool that has evolved unequivocally since its foundation in the mid-90s. Its job has always remained the same: to “describe the presentation of a document written in HTML or other markup languages [and] how the structured elements in the document are to be rendered”, as Mozilla put it. Essentially, CSS describes how a webpage or app is to be displayed to the user, and was developed in its beginnings as a way to separate the styling of the markup from the markup itself.
Although the purpose of CSS is relatively straight-forward, how it achieves this is definitely not. As a work placement student with Newicon, I will be exploring the ins and outs of CSS, explaining my understanding of how it works in the hope that I can further my own understanding and, perhaps, help others to understand it also.
One of the most important aspects of CSS is, of course, the cascade.
When a browser loads a web page, there are many different sources from which it can infer how to style the elements. The three main sources for styling are the browser’s default stylesheet, styles specified by the user, and finally the styles or stylesheets linked to the document by the author.
Within each source, specific style rules for the elements of the page are defined. For example, in webkit browsers like Chrome and Safari, the body element of an HTML document gets an 8 pixel margin applied by the browser’s own default stylesheet.
With so many different sources all potentially applying conflicting style rules to the same element, there has to be a way to determine which of these styles is ultimately applied to the HTML and displayed to the user. Cascading, within the context of CSS, is the process by which the style of an element is determined from these multiple conflicting sources.
When a document is loaded in a browser, all of its style sources are cascaded/combined together into a “virtual” stylesheet for the specific page. Of course, when this process takes place, conflicts will occur where multiple sources attempt to apply their own rules to the same element. When this happens, the origin of the rule, its source, is taken into consideration.
Styles applied by the browser’s default stylesheet have the lowest precedence, and so are always overwritten by rules from other sources. The next level up from this, user-determined (reader) style rules such as those applied in the browser console or from their own stylesheet take precedence over the browser’s default, while the author stylesheets linked directly within the webpage take precedence over these, and imported stylesheets have the same level of precedence as the stylesheet that imported it.
Consider a scenario where an element has both a class and an ID, and this element has a style rule of “color: red”, the ID has a style rule of “color: green”, and the class has a style rule of “color: blue”. What colour should the browser render the element in?
Under these circumstances, it is the specificity of the css selectors that is compared in order to determine which rule to apply to the element, with more specific selectors taking precedence over more general selectors.
The selector with the lowest specificity, and thus taking the least precedence, is that of the element type, such as “div” or “h2”, with a specificity of 1, while class selectors have a specificity of 1,0 and ID selectors a specificity of 1,0,0. Therefore, a style rule applied to an element by its class will take precedence over a rule applied to the element name, while a rule applied to the ID of the element will take precedence again over the class and element name.
For example;
1 2 3 4 5 |
div { color: blue } // Rule is applied to all elements of type 'div' div.container { color: red } // Rule is applied to all elements of type 'div' with the class 'container' div#banner { color: green } // Rule is applied to an 'div' element with the id 'banner' |
In this case, “div #banner { color: green }” has the higher specificity and so this rule takes precedence and is applied.
Or so you would assume. However, there is one final step at which a rule could come into conflict with another. If two rules have the same importance (i.e. both have “!important” applied), origin, and specificity, then the rule applied to the page last takes precedence over the first, as would be the case with any other similar pair of rules. That is to say, whichever is “lower down” the “virtual style sheet” will always take precedence over all conflicting rules.
As part of CSS’s fundamental core, the cascade is designed in a way to ensure that ultimately users are in control of the page, rather than the author.
Within CSS, there’s a special “!important” tag, which ensures that the style rule that it is included in is always applied to the page, overwriting all other rules regardless of specificity, unless a more specific !important rule exists.
1 2 3 4 5 6 7 8 9 10 11 12 |
div { color: green!important; } div.className { color: red; } div#idName { color: blue; } div.className#idName { color: black; } |
In the above example, even though the first rule has the lowest specificity, it will be applied to all div elements on the page, regardless of class names or IDs.
This rule was first put in place in order to give ultimate control to the user viewing the webpage by giving users the option to give precedence to their own stylesheets. Therefore since CSS2, contrary to other rules, !important rules within user/reader stylesheets always take precedence over rules set in the author stylesheet.
Because of the fact that it takes precedence over every other style rule, it is generally considered bad practice to use the !important rule besides in very specific situations. Using the !important tag outside of these situations is often regarded as intentionally breaking the fundamental core of the cascade, specificity, in order to fix a problem within the design that should have a better solution.
Because the !important rule takes precedence over everything, developers down the line may need to impose a rule that needs to take precedence over the !important rule, but by its very nature this will of course not work unless the !important rule is removed completely, subsequently breaking the parts of the design it was originally governing. The use of the !important rule can ultimately cause more problems than it ‘fixes’, leading the developer down a rabbit hole of messy and difficult to maintain stylesheets.
While there are some cases that it could be argued the !important tag can be used guilt-free, such as as part of user stylesheets (as it is intended), the vast majority of developers would likely advise finding a better solution in every situation.
So that’s how CSS works, but could we do better? Many people seem to think so, with a wide range of tools and methodologies for developers to use now attempting to fix what they feel is wrong with CSS. I plan to go into the caveats and shortcoming of CSS in a future article, but one issue I will raise now is the issue that I’m sure many of us know all too well; CSS sheets get long!
Because of the way the cascade works, each element on the page has to be styled according to its name, class(es), pseudo class(es), and ID, meaning that for every element with a different combination of name, classes, pseudo classes, and ID, you have to define your set of rules. This bloats out stylesheets a lot, and many people consider this a problem, especially when it comes to debugging and maintenance.
One attempt at a solution to large, overly complicated stylesheets is the OOCSS (object-oriented CSS) methodology, coined and developed by developer Nicole Sulliva, a.k.a. Stubbornella. OOCSS’s fundamental principles revolve around reusability of code, as is common with object-oriented methodologies. Firstly, OOCSS encourages the use of universal class selectors that can be used to apply universal styling to all elements of a particular class.
For example;
If you wanted to have three buttons of 500px*50px with a 1px solid black border, but all different colours, you might write it as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#button1 { width: 500px; height: 50px; border: solid 1px #000; background: #F00; } #button2 { width: 500px; height: 50px; border: solid 1px #000; background: #FF0; } #button3 { width: 500px; height: 50px; border: solid 1px #000; background: #00F; } |
But with OOCSS principles applied, you would instead separate out the universal style rules into a class applied to all of the elements, so that you’d be left with the much tidier CSS below which has the same result:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.button { width: 500px; height: 50px; border: 1px solid #000; } #button1 { background: #F00; } #button2 { background: #FF0; } #button3 { background: #00F; } |
This is a small example, but when applied to an entire project this extraction of common styles into class selectors makes a huge difference on the size and complexity of your stylesheet.
This thinking is carried through into the second principle of OOCSS; the separation of content from their containers. This means that for all of our elements, they remain independent to their parents in terms of style. This means that no matter what our element is contained within, our style rules will be applied to it.
This separation and extraction of styles means that almost every style rule being applied to our page under OOCSS principles will have no competing rules, nulling the need for our specificity check in the cascade.
For years now people have been pointing out CSS’s imperfections, suggesting that CSS as a means of styling markup with its cascade and inheritance is fundamentally flawed; that it is overly complex and bloated for what it needs to do; and that it is not fit for purpose.
The fact that steps in the cascade can be unnecessary says to some that a better solution should be found, and OOCSS sure does a good job of backing up this idea. After all, if we can style an element with no competing rules, why would we do it any other way?
With our styles separated into class “objects” and applied globally, we have substantially reduced both the load time and the maintainability of our stylesheet.
To summarise, in order for a style rule to be applied to a document, it must beat any conflicting rules in four criteria;
Origin: If the rule has been applied by a source that takes precedence over all conflicting rules’ sources, then it will be applied. Otherwise, it will be ignored by the browser. The hierarchy of importance has five key layers, which each override the layers below it;
Importance: If the rule has an “!important” flag, then it will take precedence over all other rules lacking the same flag. If, however, two or more competing rules do contain the important tag, then the origin is considered again but in reverse, where reader sources take precedence over author sources to allow the reader more control.
Specificity: If two or more rules match each other in both origin and importance then their specificity is compared. Specificity represents the combined weight of the CSS selector, and the selector with the most weight has the most specificity, and will be applied.
Order: However, if specificity is also equal between two or rules, then the final deciding factor is simply the order at which the rules are applied to the element, with rule being applied last taking precedence and all others being ignored.
However, the cascade and CSS as a whole may not be the best tool for the job, it turns out, that developers today are tasked with, especially with web projects requiring scalability and styles for all screen sizes.
There are definitely questions to be asked about the credibility of CSS as the be-all, end-all solution to styling documents and web pages, but that’s a discussion for a future post. For now, I plan wholeheartedly to take on board the lessons I’ve learnt while writing this article.
References and Credits
Mozilla on CSS – https://developer.mozilla.org/en-US/docs/Web/Guide/CSS
Håkon Wium Lie – http://www.wiumlie.no/
– https://en.wikipedia.org/wiki/H%C3%A5kon_Wium_Lie
Nicole Sullivan (Stubbornella) – http://www.stubbornella.org/content/
– https://twitter.com/stubbornella
Greg Raiz – http://www.raizlabs.com/graiz/2006/09/25/ten-reasons-why-css-sucks/
Subscribe to get our best content. No spam, ever. Unsubscribe at any time.
Send us a message for more information about how we can help you