CSS: Foundation — Selectors

CSS Selectors

Learning outcomes:

  • What are selectors in CSS
  • Different kinds of selectors — type, class, universal, ID, and attribute.
  • Simple and compound selectors
  • Grouping selectors together (using ,)

What are selectors?

Before we can style elements on an HTML document, we have to first select them. Whether it's to style all the paragraphs, or just a tiny anchor element in the footer, we have to perform selection.

And to select elements in CSS, we have what we call selectors.

Selectors are used to select a given set of HTML elements.

The elements selected all meet a given criteria established by the selector, for e.g. all elements having a particular type, or having a particular class, or a particular attribute, etc.

Before we move any further, I urge you to think about the various traits of HTML elements that we know which can help us in selecting them. To give you a headstart, we know about the type of different elements, e.g. <h1> or <p> or <a>, and so on.

What stuff do we know about HTML elements that can help us in selecting them?

Well, we know quite a lot of stuff regarding HTML elements. To name a few, we know their types; their classes; their IDs; their attributes, plus given values of these attributes; and so on.

And with so much knowledge about HTML elements, it isn't surprising at all to know that we have a lot to CSS selectors!

There are different kinds of selectors in CSS. Some will be discovered in this chapter while the rest in the next one.

The ones we'll be covering in this chapter are:

  • Universal selector, *
  • Type selector, type
  • Class selector, .class
  • ID selector, #id
  • Attribute selector, [name="value"]

Let's explore each of these one-by-one...

Different kinds of selectors

Type selector

Perhaps, the simplest of all kinds of CSS selectors is a type selector.

A type selector selects elements based on their type.

The type here is basically just the name of the element. For example, the type selector p selects all <p> elements in the HTML document.

To denote a type selector, we don't need to do anything special — just enter the name of the desired element to select, and voila!

Thus far in this course, all the selectors that we've dealt with were type selectors.

Let's consider another example to review a type selector. In the following HTML document, we wish to give a blue color to all paragraphs.

HTML
<p>This is a paragraph</p>
<p>This is another paragraph</p>

Alright. This is really easy — just select all <p> elements using the type selector p and apply the color property:

CSS
p {
   color: blue;
}

This is a paragraph

This is another paragraph

Ain't that simple?

Write CSS to color all links in an HTML document as blueviolet and all <span> elements as gold.

To select all links, which is basically all <a> elements, we use the selector a. To select all <span>s, we trivially use the selector span.

With this decided, the styling is just a matter of seconds, using the color property and the given color values:

CSS
a {
   color: blueviolet;
}

span {
   color: gold;
}

Class selector

Multiple elements in an HTML document can fall under the same class, given by the class attribute. CSS can then be used to select these groups of elements using a class selector.

The class selector selects elements based on a given class.

The general form of a class selector is .class, where class represents the class name of the elements to select.

Let's take an example to better understand the class selector.

In the following HTML, we have a paragraph with multiple <span> elements falling under the class highlight:

HTML
<p>
    I am <span class="highlight">highlighted</span>.
    I am not highlighted.
    I am <span class="highlight">highlighted</span>.
    I am <span class="highlight">highlighted</span> too.
</p>

Just by reading the name of the class, we can reason about its purpose, i.e. to highlight the underlying element. In particular, we want all .highlight elements to have a yellow background (to give that typical highlighted look).

Alright. Let's do this using the class selector:

CSS
.highlight {
   background-color: yellow;
}

I am highlighted. I am not highlighted. I am highlighted. I am highlighted too.

And there we have it!

You are working with a team of developers and designers making the next award-winning website. The group of developers coding the markup has set up the HTML with different classes.

Three of these classes are given below together with the purpose they serve:

  • disabled: gives a grey color
  • large: gives a 30px font-size
  • stroked: gives a 1px solid black border.

Your task is to write the CSS code to implement these given class specifications.

The question is pretty straightforward. We just need to use the aforementioned classes and declare the desired rules for each of them.

CSS
.disabled {
   color: grey;
}

.large {
   font-size: 30px;
}

.stroked {
   border: 1px solid black;
}

Universal selector

Ever thought of selecting all elements in an HTML document?

Well, the creators of CSS did so and, consequently, provided us with the universal selector.

The universal selector selects all elements in the underlying HTML document or within elements matched by a previous selector.

The latter case here, that is, selecting all elements within elements matched by a previous selector, requires us to first learn about combinators in CSS. We shall do so in the next chapter.

The universal selector is denoted using an * (asterisk).

Time for an example:

HTML
<div>
   <p>This is a paragraph</p>
   <div>This a div with a <span>span</span></div>
   <p>This is another paragraph with <b>bold</b> text.</p>
</div>

Here we have a purposefully complex markup, with elements nested inside of elements. The reason for this complexity is so that we can clearly visualize the effect of the universal selector.

Let's now style this markup using the selector:

CSS
* {
   border: 1px solid red;
}

This is a paragraph

This a div with a span

This is another paragraph with bold text.

Notice how each single element here has the border around it, courtesy of the universal selector.

ID selector

As you may already know, HTML elements can be assigned unique IDs in a document using the id attribute. This allows the elements to be used as destination anchors of given hyperlinks.

But another utility of IDs is to allow us to conveniently select a specific element in CSS for styling. This is precisely where the ID selector comes in.

The ID selector selects the element with a given ID.

The general form of an ID selector is #id where id is the ID of the element to select.

Consider the HTML below containing a <p> element with ID p1, which we'll now refer to compactly as #p1 (following the CSS selector syntax).

HTML
<p id="p1">A paragraph with ID 'p1'</p>
<p>Another paragraph</p>

We want to color this paragraph blue. Of course, one option is to go right in the HTML markup and use the style attribute on the paragraph to specifically style it. But we're here to explore the ID selector so let's leverage the ID already assigned to this paragraph in order to style it:

CSS
#p1 {
   color: blue;
}

A paragraph with ID 'p1'

Another paragraph

Perfect!

ID selector matches multiple elements!

As per the standard rules of HTML, IDs must be unique in a document. This means that ID selectors in CSS should match one and only one element in the underlying document.

However, probably for backwards compatibility, this is NOT the case. That is, an ID selector would match multiple elements if they all have that ID set on them.

Here's a concrete illustration:

HTML
<p>Paragraph with ID 'p1'</p>
<p>Another paragraph with ID 'p1'</p>

We have two paragraphs with the exact same ID. Let's see what happens after applying the following rule:

CSS
#p1 {
   color: green;
}

Paragraph with ID 'p1'

Another paragraph with ID 'p1'

And there you have it. Both the paragraphs get styled, which means that #p1 selects both the paragraphs.

So is this a quirk in CSS? Well, I personally don't think so.

It's rather a quirk in our document's markup. As stated earlier, it's non-conforming to the standard to have an HTML document with non-unique IDs.

In case we don't abide by this rule of HTML, CSS doesn't care either.

Here's a quick task for you to quickly exercise what you've learnt about the ID selector.

Consider the HTML below:

HTML
<p id="p1">A sandybrown background</p>
<p id="p2">A seagreen color</p>
<p id="p3">A sandybrown background and 20px font-size</p>

Write CSS code to style this HTML such that it looks as follows:

A sandybrown background

A seagreen color

A sandybrown background and 20px font-size

(The desired styles for each element are given in its content.)

We ought to select and style the three elements individually using their respective IDs, i.e. using the selectors #p1, #p2 and #p3:

CSS
#p1 {
   background-color: sandybrown;
}

#p2 {
   color: seagreen;
}

#p3 {
   background-color: sandybrown;
   font-size: 20px;
}

Attribute selector

To base the criterion of selection of elements upon their attributes, we can leverage attribute selectors.

The attribute selector selects elements with a given attribute.

There are numerous variations of attribute selectors following from the numerous ways in which we might want to select elements containing given attributes.

For example, we might want to select elements that only have a particular attribute set on them, regardless of the value of that attribute. Or we might want to select elements that have an exact attribute-value pair.

In this section, we'll only concern ourselves with these two kinds, i.e. attribute's existence and attribute-value pair. We'll explore other variations in the upcoming chapters.

The general format of the first variation, where we check for an attribute's existence, is [name] where name is the name of the attribute.

The general format of the second variation, where we check for an exact attribute-value pair, is [name="value"], where name is the attribute's name and value is its value.

Let's consider examples for each variant.

Here's the HTML markup:

HTML
<button data-key="1">Button 1</button>
<button data-key="2">Button 2</button>
<button>Button 3</button>

First, let's select only the first button based on the value of its data-key attribute and style it:

CSS
[data-key="1"] {
   background-color: pink;
}

Perfect!

Now, let's select both the buttons with the attribute (irrespective of their individual values):

CSS
[data-key] {
   background-color: pink;
}

Compound selectors

So now, by this point, we can easily select all HTML elements of a given type, belonging to a given class, having a given attribute, or having that attribute with a specific value, and so on.

These are all individual conditions that we can apply to select different elements.

But what if we wish to combine them together and further restrict the matching criteria?

For example, what if we want to select all <p> elements that have the class intro? Or what if we want to select all <a> elements with the title attribute set?

This is where compound selectors enter the game.

A compound selector is a selector made up of individual simple selectors joined with one another without a space in between.

But what's a simple selector?

Well, it's the exact opposite of a compound selector:

A simple selector is a selector which can NOT be broken further down into individual selectors.

All the selectors that we saw above are instances of simple selectors because they can't be broken further down.

For example, p is a simple selector. There is no opportunity for further division in it. So is .intro. So is [data-tooltip]. And so on and so forth.

Coming back to the topic, a compound selector is what we get when we join together these simple selectors. Essentially, a compound selector is a means of applying multiple selection conditions for selecting given elements (each simple selector imposing a given condition).

Let's consider an example following from a question asked earlier.

Suppose we wish to select all <p> elements with the class intro in the following HTML:

HTML
<p>A paragraph</p>
<p class="intro">An intro paragraph</p>
<p class="intro">Another intro paragraph</p>
<div class="intro">An intro div</div>

Certainly the selector p won't work because it selects all <p> elements, some of which might not have the intro class.

Similarly, the selector .intro won't help here because it selects all elements with the class intro, some of which might not be <p> elements.

What we really need is to combine both these selectors together. The selector desired here is p.intro:

CSS
p.intro {
   background-color: yellow;
}

Notice how .intro is joined with p without any space in between. It means that we're imposing an additional condition before selecting <p> elements, i.e. the <p> elements must have the intro class as well.

A paragraph

An intro paragraph

Another intro paragraph

An intro div

The rules for writing compound selectors are pretty simple:

  • If we need to include a type or universal selector, it must be at the very beginning.
  • Type and universal selectors can appear at most once.
  • There must be no space in between the selectors.

Let's take a bunch of examples to understand how to pair up multiple simple selectors together.

Suppose we wish to select all <a> elements with the attribute data-tooltip set (irrespective of its value). The following selector does this: a[data-tooltip]. Notice the individual selectors a and [data-tooltip].

Now, suppose we wish to select all <a> elements with the class intro and with the data-tooltip attribute. The compound selector would therefore be: a.intro[data-tooltip].

If the attribute must be data-tooltip with the exact value "-", then the selector would be: a.intro[data-tooltip="-"].

Restating it, a compound selector can't have more than one type selector in it. If you think about it for a second or two, it doesn't even make any sense!

Try experimenting around with different compound selectors and creating different kinds of HTML documents to entertain them.

Universal selectors are mostly redundant in compound selectors!

While it's possible to combine the universal selector with other selectors to produce a compound selector, it often isn't required.

For example, the selector *[data-tooltip] is precisely the same thing as [data-tooltip]. Similarly, *.intro is the same thing as .intro.

In this respect, it won't be wrong to say that in most cases — in fact, almost always — using the universal selector in a compound selector is redundant.

Grouping selectors

Suppose we have to apply the exact same styles to all <h1>, <h2>, <h3>, <h4>, <h5>, and <h6> elements.

As a more concrete example, here's the rule for <h1>:

CSS
h1 {
   background-color: blue;
   color: white;
   padding: 10px;
}

Now should we repeat this same style for each of the six heading elements?

The good news is: NO!

Using the idea of grouping selectors, we can get the same declaration block to apply to multiple selectors, without having to redefine that declaration block multiple times.

The , (comma) character is used to group multiple selectors together.

For example, h1, h2 matches all <h1> and <h2> elements. Similarly, p, .intro matches all <p> elements and all .intro elements.

A group of selectors, for e.g. h1, h2, is sometimes also referred to as a selector list in CSS.

Here's the problem stated above solved:

CSS
h1, h2, h3, h4, h5, h6 {
   background-color: blue;
   color: white;
   padding: 10px;
}

The long selector h1, h2, h3, h4, h5, h6 matches all heading elements and keeps us from having to repeat the declaration block for each heading element.

Invalid selectors in selector lists

An important thing to note while working with selector lists is that even if one of the selectors in a selector list is invalid, CSS would skip the entire rule.

This is undoubtedly something to watch out for!

Consider the following example:

HTML
<p>This is a paragraph</p>
<p>This is another paragraph</p>
<div>This is a div</div>
CSS
p, div, 67 {
   background-color: yellow;
}

We deliberately have an invalid selector in the group of selectors, p, div, 67 — that is, 67 is the culprit here. As a consequence, the entire ruleset is skipped by CSS.

This is a paragraph

This is another paragraph

This is a div

Removing the 67 resolves the issue:

CSS
p, div {
   background-color: yellow;
}

This is a paragraph

This is another paragraph

This is a div

Spread the word

Think that the content was awesome? Share it with your friends!

Join the community

Can't understand something related to the content? Get help from the community.

Open Discord

 Go to home Explore more courses