CSS Selectors That Rock

Styling websites can get a little mundane if the site you are working on is not so aesthetically pleasing or challenging. If I find myself just going through the motions, I tend to step back and try to improve my skills. Doing this not only increases motivation for the project, it also puts are few more tricks up my sleeve for future projects.

Below are 10 CSS selectors. Some of them you probably use on every project and some possibly never. Next time you’re finding yourself going through the motions, maybe it’s a good time to sneak in some new selectors that you wouldn’t normally use.


E + F


h2 + p {
   margin-top: 10px;
}

The adjacent sibling combinator. It will select the element that is immediately preceded by the former element. In the example above, only the first paragraph will have a top margin of 10px.

A little more specific:


h2.article + p { margin-top: 0;}

Similar to the previous example, except that it adds a class selector. This rule will only triggers when H2 has class="article".


E > F


nav > ul {
  border: 1px solid black;
}

Child selectors. A child selector matches when an element is the child of some element. A child selector is made up of two or more selectors separated by >.

The above example will only target the uls which are direct children of the nav element. It will not target the ul that is a child of the first li.


<nav>
   <ul>
      <li>List Item</li>
      <li>List Item</li>
      <li>List Item
        <ul> <!-- this ul will not be targeted  -->
           <li>Child</li>
        </ul>
      </li>
      <li>List Item</li>
   </ul>
</nav>

A little more specific:


nav ul > li a { color: red;}

Descendant selectors and child selectors. The above example matches an a element that is a descendant of a li. The li element must be the child of a ul. The ul element must be a descendant of a nav element.


E ~ F


h1 ~ p {
   color: red;
}

General sibling combinator. The general sibling combinator is made of the “tilde” ~. The sibling combinator is quite similar to the adjacent sibling combinator (not as strict). The difference is that the element doesn’t need to immediately follow the first element, but can be anywhere after it.

With the above example, it will select any p elements as long as it follows a h1.


E:before & E:after
The before and after pseudo elements are super handy. If you have a keen eye, you might have noticed that the comment bubbles on this site are constructed with just CSS thanks to these handy selectors.

The :before and :after pseudo-elements can be used to describe generated content before or after an element’s content.


 <div class="boom_box">
   <p>css arrow boom!</p>
</div>

.boom_box {
	position: relative;
	background: #88b7d5;
	border: 4px solid #c2e1f5;
}
.boom_box:after, .boom_box:before {
	bottom: 100%;
	border: solid transparent;
	content: " ";
	height: 0;
	width: 0;
	position: absolute;
	pointer-events: none;
}

.boom_box:after {
	border-bottom-color: #88b7d5;
	border-width: 30px;
	left: 50%;
	margin-left: -30px;
}
.boom_box:before {
	border-bottom-color: #c2e1f5;
	border-width: 36px;
	left: 50%;
	margin-left: -36px;
}

css arrow boom!


E:link & E:active & E:hover & E:focus


div:hover {
  background: #e3e3e3;
}

The dynamic pseudo-classes. These are also super handy and if you are not using them to give your users feedback on their actions, I would highly recommend using these in your next project (or add them to your existing sites) to give it a little more perzaz.

The :link pseudo-class is used to select unvisited links.

The :hover pseudo-class applies while the user hovers over an element, but does not activate it. For example, when the cursor hovers over a link, the colour changes.

The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it.

The :focus pseudo-class applies while an element has the focus (accepts keyboard events or other forms of text input).

You might have seen these basic rules declared in a reset stylesheet like so:


 a:link    { color: blue }    /* unvisited links */
 a:visited { color: black }   /* visited links   */
 a:hover   { color: red }     /* user hovers     */
 a:active  { color: orange }  /* active links    */

Note that the a:hover must be placed after the a:link and a:visited rules, otherwise the cascading rules will override the a:hover rule. Same goes with the a:active being placed after a:hover. The active state will apply when the user both activates and hovers over the element.

The above example is pretty boring. If you think outside the box you can do some pretty rad stuff like transform: rotate(70deg);, transform: scale(0.5); or transition: all 0.3s ease-out;.


E:nth-child(n)


li:nth-child(6) {
   color: bold;
}

The :nth-child() pseudo-class accepts an integer as a parameter and is not zero-based (not like arrays). If you wish to target the sixth list item, use li:nth-child(6).

This selector can even be used to select a variable set of children. For example, you could do tr:nth-child(2n+1) to select every odd row of a HTML table.

You can get pretty crafty with these guys and it is worth reading up on the spec if you are into that kind of jazz.


E:nth-last-child(n)


li:nth-last-child(4) {
   color: green;
}

The :nth-last-child() pseudo-class is a great selector to be aware of. Can’t say I have used it many times to be honest, but when I have, it saved the day. Say you have a huge content heavy site with the biggest list in the world and you have to target the 4th last item. Hello :nth-last-child(4). You could do this with :nth-child(4598792) but it is a little less likely to be bulletproof, especially if the client adds a few menu items to the top of the list.


E:nth-of-type(n)


.article p:nth-of-type(4) {
   color: red;
}

The :nth-of-type() pseudo-class gives you the ability to target the type of element rather than the child.

For example, if you have lots of paragraphs within an article on your site and want to target the 4th one and you don’t have a hook (ID or Class) to target, you can use :nth-of-type(4).


E:first-child & E:last-child


ul li:first-child {
   border-left: none;
}

ul li:last-child {
   border-right: none;
}

This :first-child and last-child structural pseudo classes allow you to target only the first child or last child of the element’s parent. These two selectors are quite handy when dealing with list styling, menus in particular.

The :first-child pseudo-class represents an element that is the first child of some other element. The :last-child pseudo-class represents an element that is the last child of some other element.


X[title]


h2[title] {
  color: red;
}

Attribute selectors. You can go pretty crazy with these guys if you desire (or need too). They allow you to specify rules that match elements which have certain attributes defined in the source. For example, the above selector matches all H2 elements that specify the "title" attribute, whatever its value.

This is only the tip of the iceberg into what attribute selectors can do.

The End

I hope I have given you a little incentive to make that next boring project a little more fun.

One word of warning is that some of the above selectors won’t work in older browsers, and by no means is the above list the best of the best, or the ones you should learn. It was just a few off the top of my head.

Do you have any favourite selectors that you would recommend?

Jake Bresnehan

A Front End Developer based in Sydney and the creator of Web Design Weekly.

Web Design Weekly keeps developers at the forefront of techniques and trends whilst helping them learn and grow to produce top quality code to make the web a better place for all.

14 Comments

  1. Nice post Jake! Glad to see the WDW blog up and running.

    I use a lot of pseudo classes and attribute selectors (especially nth-child), they’re a great time saver, but it’s worth mentioning you’ll need to rock Selectivizr (http://selectivizr.com/), or another polyfill, in your builds to make sure they work in IE :)

    • By the way, love the real time comment previews!

    • >, +, [attr], :first-child all work in IE7 and up.

    • Indeed they do :) I believe :last-child :nth-child, :nth-of-type, etc (anything in the css3 spec?) will need a polyfill to work below IE9.

    • Selectivizr doesn’t add support for :before and :after though right?

    • Apparently not, I actually thought it did!

  2. Very nice.
    Just one note, ::before and ::after are pseudo-elements, not classes.

    • Fixed. Thanks!

  3. Thanks for a nice post. What exactly is the difference between E ~ F and E F though? Seems to me that both would apply to F elements that follow E.

    • Hey Rima,

      The difference between the descendant selector and the general sibling selector is:

      E F is a Descendant Selector

      E ~ F is a General Sibling Selector

      The descendant selector matches all elements that are descendants of a specified element.

      The general sibling selector matches elements that are siblings. The elements don’t have to be adjacent siblings, but they have to have the same parent.

      So if you think about the HTML below:

      <h1>
       <span>I am a descendant because I am nested within the h1</span>
      </h1>
      <span> I am a sibling, because I am at the same nested level as the h1</span>
      <h3>
       <span> I am not a sibiling of the h1, but I am a decedant of the h3</span>
      </h3>
      

      The h1, span and h3, are all siblings.
      The spans within the h1, and h3, and descendants of their parent tags

      You can also see a coded example – http://dabblet.com/gist/2850099

      Hope that helps.

  4. You bet – very clear now! Thanks :)

  5. Great page, well done, except you need one very important element in this page.
    What is needed is a….. “Print.css”!

    The black display boxes do not show well on any print preview. On the Chrome browser, many of the elements are scrambled together and all of your left column link list overlaps the content.

    A print.css would greatly assist anyone, as myself, who wants to print the page to read and review (and use) offline.

    • Thanks for pointing that out Mark!

      As soon as I have time I will make sure this is fixed.

      I have logged the issue on the WDW GitHub repository. If you have anything else you would like to see fixed please don’t hesitate to comment.

      Cheers,
      Jake

This post currently has 14 responses. What do you think?

You can use basic HTML when posting code, please turn all < characters into &lt; or > into &gt;
If the code is multi-line, use <pre><code></code></pre>

Leave a Reply

Your email address will not be published. Required fields are marked *

Current day month ye@r *