Web layout is both complex and fascinating. In fact, it’s often interesting precisely because it’s not simple or predictable. Especially when a project doesn’t rely solely on the tried-and-true set of rules and tools developed over the years, but instead pushes the web developer to discover something new. Of course, you can use the same set of CSS properties and selectors (which we’ll be focusing on here) to create many different designs and projects. But that won’t really move you forward. Your skills in web layout and frontend development will stagnate.

It may sound a bit dramatic, but CSS selectors are essential and valuable. There are so many of them that developers often pick only a few to work with—and that’s enough for them. But we’ve decided to take a closer look at some particularly curious (at least in our opinion) CSS selectors. Some of you may already know about them, some may not. But with such a wide range of options available, it’s always exciting to find something unusual or quirky , something interesting and potentially useful.

It’s worth noting that some selectors are well supported by browsers, while others work only in the latest versions. We’ll break that down as we go.

Attributes and Content

Attribute selectors are handy when you’re targeting elements that have specific values. Let’s look at an example involving fruit selection to better understand the code. In this case, you’ll see elements selected via checkboxes (type="checkbox"), and styles applied to their corresponding labels—such as bold/italic fonts and a blue color. Then we change the style for one checkbox by assigning it the name chk2 and setting its color to red. Importantly, the rest of the list items remain unchanged and stay blue.

In this example, we’re working solely with form elements, but attribute selectors can be used beyond forms. An attribute can be anything—you just need to check for its existence. For example, button[icon] targets all buttons with an "icon" attribute, regardless of its value. Here's an example using different links .

The second and third links are highlighted in orange (yellow) and have attributes—either with or without values. The last pink link has a fluffy attribute. The value doesn’t matter—just the presence of the attribute so the a[fluffy] selector can match it.

How to use it in practice? For example, you could create image sets and highlight, animate, or add borders to images that are missing an alt attribute. This is a key element of good SEO, so it's usually always included. Using this approach, you can select and style only those images that are missing it. Here’s an example using images .

If you want to target just a portion of an attribute's value, there are some really useful selectors:

Here’s another visual example using images, links, and lists. What’s interesting here? The [attr|=val] example uses a hyphen for language-based matching, like <p lang="en-us">. File extension matching uses A[attr$=val]. Additionally, with ::after you can filter for repeated values. The final example shows how to match a domain regardless of protocol or subdomain.

What else should you know? These attributes are case-sensitive. But that’s easy to bypass by adding an i before the closing square bracket. This disables case sensitivity for matched values . All browsers support this—except IE and Edge .

Selectors for User Interfaces

There are selectors for working with UI too. Let’s look at forms and some common pseudo-classes like :checked, :disabled, :enabled . To style a to-do list , we can use :checked as shown below.

This is a very basic example most developers use. But our goal is to find selectors that go further. So let’s explore :default . If you have a group of related elements, this selector picks the default one(s). For instance, it’s used when a reset button is present—it highlights the default behavior.

Pseudo-classes can also be used for input validation—when checking form data before submission (e.g., phone number starts with +7, email contains @, etc.). The common ones are :required, :invalid, :optional, :valid .

Try typing an email. The field turns green when the input is valid. Many forms show a green checkmark for valid fields. The email field is usually required, so it can’t be left empty. This is where the :required:invalid chain comes in.

There are two more interesting pseudo-classes, useful for inputs that can use max/min attributes. These are: :out-of-range and :in-range . In the example , the range is 10–20, but the field has a value of 8, so it’s red. Type in 11 and it turns green. There’s also a Reset button.

Now for placeholder-shown, :read-write and :read-only . The first filters elements that haven’t been interacted with by the user (unchanged content). It’s not well supported. The last two help identify elements available for editing or reading—not just text. Here’s a clear example .

Back to Content

We’ve reviewed interfaces and filters. Let’s return to content—because there are still some cool CSS selector options here. Developers often use ::first-line, ::selection, ::first-letter , as seen in this styling example . First and last are used for text blocks. If you apply ::first-letter to multiple blocks, every paragraph begins with a drop cap. In this case, only the first letter of the first word in the first paragraph is styled.

Experimental and Future CSS

There are also advanced techniques in experimental CSS programming . These selectors aren’t supported by any browser yet, but are documented in Mozilla’s MDN.

::marker – selects list markers like bullets or numbers. ::spelling-error – selects segments marked as misspelled. ::placeholder – targets placeholder text in form fields, such as a sample email address.

Anything else?

There are many more experimental selectors, but we won’t cover them here since they aren’t practical yet. One example is :dir() , which is supported only by Firefox. What does it do? It selects text direction—left to right or right to left ( rtl or ltr ). Here’s an example of text alignment .

Another somewhat supported selector is :matches() or is() ( we’ll revisit this ) . Support is limited but better than for dir(). It shortens long selector lists into a few lines. Great for optimizing CSS code .

Conclusion

We’ve only covered a portion of CSS selectors that are underused for various reasons. Some developers don’t know about them, others don’t see the need. Whether to use them is your choice. However, note that many of the unsupported selectors are new additions from CSS Level 4 specs (as of November 21 this year). Notably, :matches() has been renamed to is() .

Overall, CSS is incredibly useful for both designers and developers. It allows for modern, tech-savvy designs and animations—all without JavaScript. It’s convenient, practical, and often much simpler than coding separate animations or drawing tiny elements that would otherwise bloat file sizes.