CSS Selectors, Typography, Color Modes, and More

Selectors, units, and capabilities

Although they may not seem like the most exciting of subjects, selectors, units, and capabilities are the “meat and potatoes” of CSS. Master these and your power to solve problems with CSS will increase substantially. So, skip this section at your peril!

Anatomy of a CSS rule

Before exploring some of the recent additions to CSS, to prevent confusion, let’s establish the terminology we use to describe a CSS rule. Consider the following example:


.round {

/* selector */

border-radius: 10px; /* declaration */

}

This rule is made up of the selector (.round) and then the declaration (border-radius: 10px). The declaration is further defined by the property (border-radius) and the value (10px). Happy we’re on the same page? Great, let’s press on.

At the time of writing this, the Selectors Level 4 working draft details a host of new selectors such as is(), has(), and nth-col. Sadly, there is not a single implementation in any of the common browsers available. However, if you want to see how things are shaping up for the future, head to the draft at https://www.w3.org/TR/selectors-4/.

Pseudo-elements and pseudo-classes

There is potential for some confusion when we go on shortly to talk about “pseudo” selectors. The reason being is that, in CSS, there are both pseudo-selectors and pseudo-elements. Let’s therefore take a moment to establish the difference.

The word “pseudo” in this context means something that is like something but not really it. So, a pseudo-element is something that is like an element but not really one, and a pseudo-selector is something that selects something that isn’t really something. Wow, I’m sounding like the Riddler now from Batman! Let’s clarify with some code. Here is how you create a pseudo-element in CSS:


.thing::before {</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">content: "Spooky";</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

That inserts a ::before pseudo-element into the .thing element with the content “Spooky.” A ::before behaves like a first child of the element and an ::after behaves like a last child.

The following image might help. It’s showing a single element represented in the Firefox developer tools, containing text with both a ::before and an ::after pseudo-element added in CSS:

The key thing to remember with pseudo-elements is that if you don’t provide a value for content, nothing will show on the page. Notice the double colon before before? Officially, that is how you should code pseudo-elements as it helps differentiate them from pseudo-selectors, which only use one. However, a single colon worked with the first implementations of ::before and ::after and so you can still write them that way too.

You can’t do the same with pseudo-selectors; they always have a single colon. For example, :hover, :active, and :focus are all pseudo-selectors and are written with a single colon.

At the risk of oversimplification, it might be useful to think of a pseudo-selector as one that selects a subpart of the original thing it is selecting.

Hopefully, the difference between pseudo-selectors and elements is now clear.

With that distinction made, let’s move on and look at some of the powerful selectors available to us today in CSS.

CSS Level 3 selectors and how to use them

CSS now provides incredible power for selecting elements within a page. You may not think this sounds very glitzy but trust me, it will make your life easier and you’ll love CSS for it! I’d better qualify that bold claim.

CSS attribute selectors

You’ve probably used CSS attribute selectors to create rules. For example, consider the following markup:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><img src="https://placeimg.com/640/480/any" alt="an inquisitive cat"></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">And this CSS:</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">img[alt] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">border: 3px dashed #e15f5f;</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

This would select the img element in the preceding code, and any others on the page provided that they have an alt attribute.

In fact, to make something a little more useful, we could combine this with the :not negation selector (we will look at that in detail later in this chapter) to add a red border around any images that have no alt attribute or an alt attribute with no value:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">img:not([alt]),</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">img[alt=""] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">border: 3px solid red;</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

That would be useful from an accessibility point of view as it would visually highlight any images that didn’t have alternate text included for assistive technology.

As another example, let’s say we wanted to select all elements with a data-sausage attribute:


[data-sausage] {</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

The key thing here is to use square brackets to specify the attribute you want to select.

The data-* type attribute was introduced in HTML5 to provide a place for custom data that can’t be stored sensibly by any other existing mechanism. The specification description for these can be found here: http://www.w3.org/TR/2010/WD-html5-20101019/elements.html#embedding-custom-non-visible-data-with-the-data-attributes.

You can also narrow things down by specifying what the attribute value is. For example, consider the following rule:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">img[alt="Sausages cooking"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* Styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

This would only target images that have an alt attribute of “Sausages cooking”; for example:

<img src=”img/sausages.png” alt=”Sausages cooking” />

So far, so “big deal, we could do that in CSS2.” What do CSS Level 3 selectors bring to the party

CSS substring matching attribute selectors

CSS3 added the ability to select elements based upon the substring of their attribute selector. That sounds complicated. It isn’t! The three options are whether the attribute:

  • Begins with a certain substring
  • Contains an instance of a certain substring
  • Ends with a certain substring

Let’s see what they look like.

The “beginning with” substring matching attribute selector

Consider the following markup:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li data-type="todo-chore">Empty the bins</li></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li data-type="todo-exercise">Play football</li></p>

<pre>

Suppose that markup represents two items in a “todo” list application we are building. Even though they both have different data-type attribute values, we can select them both with the “beginning with” substring matching attribute selector, like this:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">[data-type^="todo"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* Styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

The key character in all this is the ^ symbol. That symbol is called the “caret,” although it is often referred to as the “hat” symbol too. In this instance, it signifies “begins with.” Because both data-type attributes have values that begin with “todo,” our selector selects them.

The “contains an instance of” substring matching attribute selector

The “contains an instance of” substring matching attribute selector has the following syntax:

[attribute*="value"] {</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* Styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

Like all attribute selectors, you can combine them with a type selector (one that references the actual HTML element used) if needed, although I would only do that if I had to—in case you want to change the type of element used.

Let’s try an example. Consider this markup:

<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><p data-ingredients="scones cream jam">Will I get selected?</p></span>

We can select that element like this:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">[data-ingredients*="cream"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">color: red;</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

The key character in all this is the * symbol, which in this context means “contains.”

The “begins with” selector would not have worked in this markup as the string inside the attribute didn’t begin with “cream.” It did, however, contain “cream,” so the “contains an instance of” substring attribute selector finds it.

The “ends with” substring matching attribute selector

The “ends with” substring matching attribute selector has the following syntax:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">[attribute$="value"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* Styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

An example should help. Consider this markup:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><p data-ingredients="scones cream jam">Will I get selected?</p></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><p data-ingredients="toast jam butter">Will I get selected?</p></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><p data-ingredients="jam toast butter">Will I get selected?</p></p>

<pre>

Suppose we only want to select the element with scones, cream, and jam in the data-ingredients attribute (the first element). We can’t use the “contains an instance of” (it will select all three) or “begins with” (it will only select the last one) substring attribute selector. However, we can use the “ends with” substring attribute selector:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">[data-ingredients$="jam"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">color: red;</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

The key character in all this is the $ (dollar) symbol, which means “ends with.”

Right, we have some pretty handy attribute related selectors now. It’s also worth knowing that you can chain attribute selectors, just like you can class selectors.

Chaining attribute selectors

You can have even more possibilities for selecting items by grouping attribute selectors.

Suppose we had this markup:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-todo-type="exercise"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-activity-name="running"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-location="indoor"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">Running</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"></li></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-todo-type="exercise"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-activity-name="swimming"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-location="indoor"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">Swimming</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"></li></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-todo-type="exercise"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-activity-name="cycling"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-location="outdoor"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">Cycling</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"></li></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><li</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-todo-type="exercise"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-activity-name="swimming"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">data-location="outdoor"</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">></p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">Swimming</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"></li></p>

<pre>

Let’s suppose I only wanted to select “indoor swimming.” I can’t use just data-location=”indoor” as that would get the first element too. I can’t use data-activity-name=”swimming” as that would get me the first and the third, but I can do this:

</pre>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">[data-activity-name="swimming"][data-location="indoor"] {</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/* Styles */</p>
<p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p>

<pre>

This selects elements that have “swimming” as the activity name, as long as they also have “indoor” as the location.

Attribute selectors allow you to select IDs and classes that start with numbers. Before HTML5, it wasn’t valid markup to start IDs or class names with a number. HTML5 removes that restriction. When it comes to IDs, there are still some things to remember. There should be no spaces in the ID name, and it must be unique on the page. For more information, visit http://www.w3.org/html/wg/drafts/html/master/dom.html#the-id-attribute. Now, although you can start ID and class values with numbers in HTML5, CSS still restricts you from using ID and class selectors that start with a number (http://www.w3.org/TR/CSS21/syndata.html#characters). Luckily for us, we can easily work around this by using an attribute selector; for example, [id=”10″].

Right, I think our attribute selecting skills are now pretty tight. Let’s move on to how we can deal with selecting elements based upon where they are in the document



This website uses cookies and asks your personal data to enhance your browsing experience. We are committed to protecting your privacy and ensuring your data is handled in compliance with the General Data Protection Regulation (GDPR).