As a stylesheet language, CSS is easy to understand and hard to master. Many web developers underestimate the complexity of CSS when selectors, properties, precedence, inheritance, and the CSS box model come into play, and so they find it frustratingly difficult.
For something as simple as a declarative language that helps you style HTML documents, CSS can indeed be surprisingly complex. To help you get to grips with CSS, let’s look at where this complexity comes from—and how you can reduce it.
A CSS selector specifies which HTML elements to apply the rules of the expression to. Or, to put it simply, it tells the browser which HTML elements to select and style.
CSS selectors can be basic (that is, they consist of only one query) and combined (they consist of multiple queries combined together).
There are three types of basic CSS selectors: type selectors that search for specific element types, class selectors that search for elements with a specific class name, and id selectors that search for individual elements with a known id attribute.
Combined CSS selectors consist of multiple selectors grouped in some way. This is done using one of the combinators in CSS, which in CSS3 include the adjacent sibling combinator, general sibling combinator, child element combinator, descendant element combinator, and column combinator.
There are also pseudo-classes, which let you specify the state of one or more HTML elements, and pseudo-elements, which lets you specify HTML elements that don’t exist in the document.
If you can master CSS selectors, you can master CSS. Underestimate and ignore them, however, and you will be systematically frustrated that your CSS doesn’t work.
Not everyone who writes CSS style sheets understands CSS precedence, and yet I would argue that everyone should.
CSS precedence determines what happens when two rules in your CSS style sheet target the properties of the same HTML element. Basically, it answers the question: which one should prevail?
It’s common to have overlapping CSS rules, especially in complex projects, which is why it’s so important to understand what CSS precedence is and how exactly it works.
As a general rule of thumb, CSS precedence works in the following way:
- Inline CSS takes precedence over CSS rules in a
<style>tag in the
<head>section or linked to in a CSS file
- A rule that appears later in your CSS style sheet takes precedence over one that appears earlier
- Specific CSS selectors (say,
#nav-item-1) take precedence over generic CSS selectors (say,
- CSS rules with the
!importantproperty always take precedence over those without
If you write CSS code without this knowledge, chances are you will keep making mistakes—and wondering why your CSS isn’t updating.
Another aspect of CSS that causes many web developers to find CSS difficult is inheritance.
CSS inheritance determines what happens to the CSS property of an HTML element when no value is explicitly set in the style sheet. This is so important that all CSS properties in an HTML document can be grouped into one of two types: inherited and non-inherited properties.
When you haven’t specified a value for a given CSS property of an HTML element, that element gets the computed value from its parent (or that of its parent’s parent, or that of the root
Sounds easy, right? Not when you think about all of the CSS properties that an element deep down in the DOM of a big project can inherit from its parents! Also, if you’re using relative units like em, those values can compound and lead to greater size or spacing than they should.
CSS Box Model
Each element in an HTML document is a rectangular box that you can style with CSS. It consists of the content, with its width and height, as well as padding, border, outline, and margin.
Boxes can have an outer display type (
display: block or
display: inline) and an inner display type (regular flow, flex, and grid). Together, these two properties determine how an HTML element is displayed relative to its parents and siblings, as well as how its child elements are displayed.
This is the CSS box model. If you understand how it works, you can easily determine the size and position of HTML elements. If you don’t, you will keep wondering why the actual sizes of HTML elements don’t match the ones you’ve assigned to them in your CSS style sheet.
You can find a really good introduction to the CSS box model at MDN Web Docs.
Cascading Style Sheets (CSS) is a style sheet language, and not a programming language. Because of that, many web developers come into it with the assumption that it’s easy… only to understand that there are many bits and pieces involved.
The good news is that CSS doesn’t have to be hard. If you learn the basics of CSS—namely, selectors, properties, precedence, inheritance, and the CSS box model—then you will be able to master this style sheet language over time.