Learn CSS Selectors

When it comes to learning CSS Selectors, there are oftentimes many ways to skin the cat. You can use a number of different techniques to reach the same end. However, it’s important to know which techniques are applicable in which circumstance. In this article, we are going to learn CSS Selectors and I will be covering the main techniques you can use to target your HTML elements.

What are CSS Selectors?

You can’t learn CSS Selectors without a proper definition.

In CSS, selectors are used to target the HTML elements on our web pages that we want to style. 

Mozilla Web Development Tutorial

// index.html

<h1> Hello World! </h1>

Above we have an HTML heading tag with text in it. Let’s say we want to make the text blue and the background white. So if we aren’t using inline styling (you shouldn’t be) then we need a way to hit the heading tag from our stylesheet.

// styles.css

h1 {
  background-color: white;
  color: blue;

As you can see, we have targeted the heading tag in our CSS file using a CSS Selector.

Hello World!

This is a basic example of how to use a selector, but you’re here to learn CSS Selectors, not look at basic examples. In the following paragraphs, I will cover the different techniques you can use to target your HTML elements.

ID Selectors

Selecting an element by its ID is good for situations where you only need to apply a style to that element, or that element and its descendants. An ID should only ever occur once in the document, as they are unique attributes.

Below is an example of selecting an element called title and styling it.


<h1 id="title"> </h1>

// CSS

#target {
  color: yellow;

Class Selectors

Selecting an element by its Class is probably the most popular way of selecting HTML elements. Unlike its counterpart, the ID Attribute, the Class Attribute does not have to be unique to one element. Therefore, the Class Selector does not have to be repeated if the developer wants to use it on multiple different elements. The code below will make all of those elements have red text!



  <p class="info"></p>
  <h1 class="info"></h1>
  <sub class="info"></sub>


// CSS

.info {
  color: red;

Attribute Selectors

Attribute Selectors are the most varied and complicated selectors, simply because there are so many different attributes an element can have. You can go down a real rabbit hole here, and if you’re so inclined you can here. However, for the sake of brevity, I am only going to mention a couple use cases. If I wanted to select a text input in a form, I would do the following.


  <input type="text" placeholder

// CSS

input[type="text"] {
  border: red;

Thanks to HTML5, we can now also create custom HTML attributes and target them with CSS. Remember, any custom attribute must be prefixed with “data”.


<div data-anything-i-want></div>

// CSS

div[data-anything-i-want] {
  background: red;

Universal Selector

The Universal Selector is the easiest one to grasp, as it selects every element in the document. For instance, if I want all text on a site to be the color orange, I would simply use a Universal Selector, the CSS below does just that.

* {
  color: orange;

This technique becomes much more useful when you pair it with a combinator which we will cover next!

CSS Combinators

locks all connected to each other
Combinators, Combinations. Eh, I thought it was clever.

This stuff has all been pretty vanilla so far, but now the real fun begins. In order to really learn CSS Selectors, one must have a strong grasp of CSS Combinators. Using CSS Combinators allows you to chain together multiple selectors and truly give you the freedom to select any element efficiently.

Child Combinator

A Child Combinator is signified by the > symbol. Sometimes you may need to target the child of an element. For instance, the child of the following <div> is an <h1>

<div id="parent">
  <h1 id="child"></h1>

Here the two main ways we would target the child element are using either an ID selector or a child combinator. I will show you what those look like and explain them.

// Child combinator

div > h1 {
  // some CSS

Imagine we had a list of items that we wanted to style, but the items should all have the same styling. Using the ID selector would be very inefficient in comparison to the child combinator. We would need to write out the ID selector x amount of times, whereas we only need to write the direct descendant selector once.

I mentioned before that there are always multiple ways to do things when using CSS Selectors. For instance, in the above scenario, I could target the child element by referencing the parent’s ID AND hitting their direct descendants.

As mentioned in the previous section, this would be a great technique to use the Universal Selector with. Most HTML documents are separated into sections, so it is often useful to only style elements within a certain section. For instance, if all the text on my site was black, but I had one section that had a purple background-color I couldn’t leave black text there. Primarily because it’s not accessible to people with color-blindness, which is mandatory according to the Web Content Accessibility Guidelines (WCAG).


<div id="pricing">
  <h1>Some text</h1>
  <p>Some additional text</p>
  <span>Tiny text</span

// CSS

#pricing {
  background-color: purple;

#pricing * {
  color: white;

Descendant Combinators

<ul id="main-navigation">





I want to change the font color of all of the <a> in my main navigation. The most simple way to do so is to simply use a descendant combinator as follows:

#main-navigation a {
  color: red;

The above code will make all of those <a> have a font color of red. This one is very straightforward and I try and use it as often as possible.

One thing you may have not noticed is that the space between the “#main-navigation” selector and the “a” is actually a meaningful space. Just like the right caret ( > ) that we saw above, the space signifies we should be looking for any descendant that matches.

Sibling Combinators

There is a lot of family talk when it comes to CSS Selectors, and it won’t stop now. In HTML you call two adjacent elements, siblings. So naturally, in CSS there is a way to target an elements siblings.

Direct Sibling Combinator

If I want to target a sibling of an HTML element that immediately follows said element, but no other siblings I would use the direct sibling combinator. For instance, say I want to target the <p> with “Cool Photo”, but not the one that is depressing.


<img src="https://zacbanas.com/handsome-guy">
<p>Cool Photo</p>
<p>My mom says I'm handsome</p>

// CSS

img + p {
  background: red;

General Sibling Combinator

This sibling combinator is the more useful one, just like my older brother.

Sorry – I’ll keep jokes to a minimum.

The General Sibling Combinator is used for any element that follows the main element and is a child of the same parent. For instance, the title and caption in the code below both belong to sibling elements. However, they are not direct siblings because one does not immediately follow the other. I want all <p> that are siblings with <h1> to have a yellow border.

// HTML 

<div class="container">
  <img src="https://google.com">

// CSS 

h1 ~ p {
  border: yellow;


CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For instance, the most popular pseudo-class :hover allows your style to take effect only when your element is hovered over. Let’s say I want to make an elements box-shadow bigger when it is hovered over by the cursor.


<div class="card">
  <h1>Card Title</h1>

// CSS 

.card:hover {
  box-shadow: 2px 4px 4px 2px black;

There are 49 other pseudo-classes available for your use that I am not going to go over here. However, I will list them out for you – and the above usage is the same for all of these. I have linked each to an article written about them that you can check out if you want to dive deeper in your quest to learn CSS Selectors.

  1. :active
  2. :any-link
  3. :checked
  4. :blank
  5. :default
  6. :defined
  7. :dir()
  8. :disabled
  9. :empty
  10. :enabled
  11. :first
  12. :first-child
  13. :first-of-type
  14. :fullscreen
  15. :focus
  16. :focus-visible
  17. :focus-within
  18. :has()
  19. :host()
  20. :host-context()
  21. :hover
  22. :indeterminate
  23. :in-range
  24. :invalid
  25. :is() (:matches(), :any())
  26. :lang()
  27. :last-child
  28. :last-of-type
  29. :left
  30. :link
  31. :not()
  32. :nth-child()
  33. :nth-last-child()
  34. :nth-last-of-type()
  35. :nth-of-type()
  36. :only-child
  37. :only-of-type
  38. :optional
  39. :out-of-range
  40. :placeholder-shown
  41. :read-only
  42. :read-write
  43. :required
  44. :right
  45. :root
  46. :scope
  47. :target
  48. :valid
  49. :visited
  50. :where()


Alas, I would be remiss if I did not include Pseudo-Elements. There are three main uses for Pseudo-Elements that I will go over. First are the ::before and ::after Pseudo-Elements. These Pseudo-Elements are generally used to insert content before and after your targeted element.


  <a href="#"> por ejemplo </a>

// CSS

div a::before {
  content: "♥";
  color: red;

div a ::after {
  content: "∆";
  color: blue;

The above CSS adds a red heart before the <a> and a blue triangle after it. These are some of the more simple concepts to grasp.

One of the handiest CSS Selectors I’ve ever come across is the ::placeholder Pseudo-Element. This allows you to style the placeholder content of <input>. For example, if I wanted to make the following placeholder text purple, I would do this.


  <input type="text" placeholder="First Name">

// CSS

form > input[type="text"]::placeholder {
  color: purple;

There we have it, your first dive into CSS Selectors and all the glory that comes along with them. If you found this article helpful please share it on any social media platform you can or leave a comment. Thanks so much for reading!