The Best Way To Learn CSS Selectors: A step-by-step guide with examples on CSS Selectors!
Table of contents
A CSS selector is a pattern to match the elements on a web page. The style rules associated with that selector will be applied to the elements that match the selector pattern.
Selectors are one of the most important aspects of CSS as they allow you to target specific elements on your web page in various ways so that they can be styled.
What are selectors?
Selectors are the CSS rules that define how HTML elements are styled. Selectors are used to styling all kinds of HTML elements and can be used to target specific HTML elements, such as <p>
and <div>
. They also can target classes, IDs, attribute values, etc.
Several types of selectors are available in CSS, let's take a closer look at them:
Universal Selector
The universal selector works like a wild card character, selecting all elements on a page. Every HTML page is built on content placed within HTML tags. Each set of tags represents an element on the page. Look at the following CSS example, which uses the universal selector:
* {
color: green;
font-size: 20px;
line-height: 25px;
}
The three lines of code inside the curly braces (color, font-size, and line-height) will apply to all elements on the HTML page. As seen here, the universal selector is declared using an asterisk. You can also use the universal selector in combination with other selectors.
Element Type Selector
Also referred to simply as a “type selector,” this selector must match one or more HTML elements of the same name. Thus, a selector of nav would match all HTML nav elements, and a selector of <ul>
would match all HTML unordered lists, or <ul>
elements.
The following example uses an element type selector to match all <ul>
elements:
ul {
list-style: none;
border: solid 1px #ccc;
}
To put this in some context, here’s a section of HTML to which we’ll apply the above CSS:
<ul>
<li>Fish</li>
<li>Apples</li>
<li>Cheese</li>
</ul>
<div class="example">
<p>Example paragraph text.</p>
</div>
<ul>
<li>Water</li>
<li>Juice</li>
<li>Maple Syrup</li>
</ul>
Three main elements are making up this part of the page: Two <ul>
elements and a <div>
. The CSS will apply only to the two <ul>
elements, and not to the <div>
. Were we to change the element type selector to use <div>
instead of <ul>
, then the styles would apply to the <div>
and not to the two <ul>
elements.
Also, note that the styles will not apply to the elements inside the <ul>
or <div>
elements. That being said, some of the styles may be inherited by those inner elements.
ID Selector
An ID selector is declared using a hash, or pound symbol (#) preceding a string of characters. The string of characters is defined by the developer. This selector matches any HTML element that has an ID attribute with the same value as that of the selector, but minus the hash symbol. Here’s an example:
#container {
width: 960px;
margin: 0 auto;
}
This CSS uses an ID selector to match an HTML element such as:
<div id="container"></div>
In this case, the fact that this is a <div>
element doesn’t matter—it could be any kind of HTML element. As long as it has an ID attribute with a value of container, the styles will apply.
An ID element on a web page should be unique. That is, there should only be a single element on any given page with an ID of the container. This makes the ID selector quite inflexible because the styles used in the ID selector rule set can be used only once per page.
If there happens to be more than one element on the page with the same ID, the styles will still apply, but the HTML on such a page would be invalid from a technical standpoint, so you’ll want to avoid doing this.
In addition to the problems of inflexibility, ID selectors also have the problem of very high specificity.
Class Selector
The class selector is the most useful of all CSS selectors. It’s declared with a dot preceding a string of one or more characters. Just as is the case with an ID selector, this string of characters is defined by the developer. The class selector also matches all elements on the page that have their class attribute set to the same value as the class, minus the dot.
Take the following ruleset:
.box {
padding: 20px;
margin: 10px;
width: 240px;
}
These styles will apply to the following HTML element:
<div class="box"></div>
The same styles will also apply to any other HTML elements that have a class attribute with a value of a box. Having multiple elements on a single page with the same class attribute is beneficial because it allows you to reuse styles, and avoid needless repetition. In addition to this, class selectors have very low specificity—again, more on this later. Another reason the class selector is a valuable ally is that HTML allows multiple classes to be added to a single element. This is done by separating the classes in the HTML class attribute using spaces. Here’s an example:
<div class=”box box-more box-extended”></div>
Descendant Combinator
The descendant selector or, more accurately, the descendant combinator lets you combine two or more selectors so you can be more specific in your selection method. For example:
#container .box {
float: left;
padding-bottom: 15px;
}
This declaration block will apply to all elements that have a class of box that is inside an element with an ID of the container. It’s worth noting that the .box element doesn’t have to be an immediate child: there could be another element wrapping .box, and the styles would still apply. Look at the following HTML:
<div id="container">
<div class="box"></div>
<div class="box-2"></div>
</div>
<div class="box"></div>
If we apply the CSS in the previous example to this section of HTML, the only element that’ll be affected by those styles is the first <div>
element that has a class of box. The <div>
element that has a class of box-2 won’t be affected by the styles. Similarly, the second <div>
element with a class of box won’t be affected because it’s not inside an element with an ID of the container.
You should be careful when using the descendant combinator in your CSS. This kind of selector, while making your CSS a little easier to read, can unnecessarily restrict your styles to a specific context—in this case, the styles are restricted to boxes inside of #container—which can make your code inflexible.
Child Combinator
A selector that uses the child combinator is similar to a selector that uses a descendant combinator, except it only targets immediate child elements:
#container > .box {
float: left;
padding-bottom: 15px;
}
This is the same code from the descendant combinator example, but instead of a space character, we’re using the greater-than symbol (or right angle bracket.) In this example, the selector will match all elements that have a class of box and that are immediate children of the #containerelement. That means, unlike the descendant combinator, there can’t be another element wrapping .box—it has to be a direct child element.
Here’s an HTML example:
<div id="container">
<div class="box"></div>
<div>
<div class="box"></div>
</div>
</div>
In this example, the CSS from the previous code example will apply only to the first <div>
element that has a class of box. As you can see, the second <div>
element with a class of box is inside another <div>
element. As a result, the styles will not apply to that element, even though it too has a class of box.
Again, selectors that use this combinator can be somewhat restricting, but they can come in handy—for example, when styling nested lists.
General Sibling Combinator
A selector that uses a general sibling combinator matches elements based on sibling relationships. That is to say, the selected elements are beside each other in the HTML.
h2 ~ p {
margin-bottom: 20px;
}
This type of selector is declared using the tilde character (~). In this example, all paragraph elements (<p>
) will be styled with the specified rules, but only if they are siblings of <h2>
elements. There could be other elements in between the <h2>
and <p>
, and the styles would still apply.
Let’s apply the CSS from above to the following HTML:
<h2>Title</h2>
<p>Paragraph example.</p>
<p>Paragraph example.</p>
<p>Paragraph example.</p>
<div class="box">
<p>Paragraph example.</p>
</div>
In this example, the styles will apply only to the first three paragraph elements. The last paragraph element is not a sibling of the <h2>
element because it sits inside the <div>
element.
Adjacent Sibling Combinator
A selector that uses the adjacent sibling combinator uses the plus symbol (+) and is almost the same as the general sibling selector. The difference is that the targeted element must be an immediate sibling, not just a general sibling. Let’s see what the CSS code for this looks like:
p + p {
text-indent: 1.5em;
margin-bottom: 0;
}
This example will apply the specified styles only to paragraph elements that immediately follow other paragraph elements. This means the first paragraph element on a page would not receive these styles. Also, if another element appeared between two paragraphs, the second paragraph of the two wouldn’t have the styles applied.
So, if we apply this selector to the following HTML:
<h2>Title</h2>
<p>Paragraph example.</p>
<p>Paragraph example.</p>
<p>Paragraph example.</p>
<div class="box">
<p>Paragraph example.</p>
<p>Paragraph example.</p>
</div>
…the styles will apply only to the second, third, and fifth paragraphs in this section of HTML.
Attribute Selector
The attribute selector targets elements based on the presence and/or value of HTML attributes, and is declared using square brackets:
input[type="text"] {
background-color: #444;
width: 200px;
}
There should not be a space before the opening square bracket unless you intend to use it along with a descendant combinator. The above CSS would match the following element:
<input type="text">
But it wouldn’t match this one:
<input type="submit">
The attribute selector can also be declared using just the attribute itself, with no value, like this:
input[type] {
background-color: #444;
width: 200px;
}
This will match all input elements with an attribute of type, regardless of the value.
You can also use attribute selectors without specifying anything outside the square brackets (thus targeting based on the attribute alone, irrespective of the element). It’s also worth noting that, when using values, you have the option to include quotes (single or double,) or not.
Pseudo-class
A pseudo-class uses a colon character to identify a pseudo-state that an element might be in—for example, the state of being hovered, or the state of being activated. Let’s look at a common example:
a:hover {
color: red;
}
In this case, the pseudo-class portion of the selector is the:hover part. Here we’ve attached this pseudo-class to all anchor elements (elements). This means that when the user hovers their mouse over an element, the color property for that element will change to red. This type of pseudo-class is a dynamic pseudo-class, because it occurs only in response to user interaction—in this case, the mouse moving over the targeted element. It’s important to recognize that these types of selectors do not just select elements; they select elements that are in a particular state. For this example, the state is the “hover” state.
Pseudo-element
Finally, CSS has a selector referred to as a pseudo-element, and, used appropriately, it can be very useful. The only caveat is that this selector is quite different from the other examples we’ve considered. Let’s see a pseudo-element in context:
.container:before {
content: "";
display: block;
width: 50px;
height: 50px;
background-color: #141414;
}
This example uses one kind of pseudo-element, the:before pseudo-element. As the name suggests, this selector inserts an imaginary element into the page, inside the targeted element, before its contents.