~/ Practical Applications of Pseudo Elements and Classes

A note about browser support:

There's some pretty crazy stuff going on in this post. The support for pseudo classes and elements is quite good, and you can start using them in production now. The code examples in this post show properties without vendor prefixes for readability purposes. If you're not using Compass or Autoprefixer to deal with vendor prefixes, you can always reference Can I Use to see which vendor prefixes, if any, are required.

Understanding what pseudo classes and pseudo elements are used for can be a bit confusing at first. What are they? Why are they pseudo?! You're probably already familiar with a few of them. In any introductory CSS class, the :hover state for anchor links is a popular example.

Hover Me At nclud, we totally dig open source. All of the examples in this post are on GitHub. Click the icon below to view the Sass used.

Github

Here are some practical use cases for these pseudo web things:

Pseudo Classes

:active

The :active pseudo class is useful for representing skeuomorphic behavior in web interfaces.

I've used a button in this example and transformed the translateY() to offset the box shadow. It has the visual effect of the button being pressed or clicked.


button{
transition:all .2s ease;
position:relative;
box-shadow:0 10px 0 #8DC63F;
}

button:active{
transform:translateY(9px);
box-shadow:0 1px 0 #8DC63F;
}

:checked

One cool use of the :checked pseudo-class is custom radio buttons or checkboxes. Given the following markup:

<label>
<input class='ps-checked' type='radio' name='radio'>
<div>
Custom Radio Content
</div>
</label>

We can pull off totally semantic custom radio buttons without having to use JavaScript. Notice how the label wraps both the input and the custom radio content? Doing this allows us to use the adjacent sibling selector. Anytime the label is clicked, the input takes on the checked property. Then, we apply the styles to an div that's adjacent to the checked input.



label input{
visibility:hidden;
}

label div{
box-shadow:8px 8px #8DC63F;
position:relative;
transition:all .2s ease;
}

label input:checked + div {
transform:translate(7px, 7px);
box-shadow:1px 1px 0px #8DC63F;
color:#fff;
}

If we hide the radio button input with visibility:hidden, we are free to style the contents of the <label> container as we please.

This is an elegant solution for toggle states in web applications. Instead of toggling a class, or worse, changing the CSS via JavaScript (jQuery included), we can maintain styles that reflect state changes in the DOM all in one place.

:first-child and :last-child

A popular use case for the first and last children of a container is the widget. Here's some markup:

<div class='widget'>
  <h1>The Widget Title</h1>
  <p>A brief summary of the what The Widget Title is all about.
     Maybe it's even the opening paragraph.</p>
  <p>Often there will be more than one paragraph in a widget</p>
</div>

In our widget, we want to have equal padding for the widget container, but ignore the margin-top of the <h1> and the margin-bottom of the <p>. This is a common design pattern, where the container has equal spacing all around the elements. If the h1 or p were to retain its margin when directly next to the widget's container, it would look a bit funky.

See the Pen qzhfI by Jesse Shawl (@jshawl) on CodePen

.widget{
  padding:1em;
}
.widget :first-child{
  margin-top:0
}
.widget :last-child{
  margin-bottom:0
}

:nth-child

Alternating colors! It's an effective technique that takes a very small amount of code:

li:nth-child(2n){
  background:#8DC63F;
}

Before :nth-child was available, you'd have to either hardcode classes into the alternating rows or use a JavaScript solution to color the odd-numbered rows. Using a CSS solution allows us to keep styles together, which ultimately decouples our front end code.

:target

The :target pseudo class is useful for highlighting hash-linked sections on web pages. This is a great usability technique. Normally the page will jump to the anchor on click and position the element with the corresponding ID at the top of the page. If the linked-to element is towards the bottom of the page, and there isn't enough room at the bottom for the element to be all the way at the top of the page, the only way to identify what was linked to will be to use the :target pseudo class to highlight the important info.

:target{
  animation:target 2s ease;
}

@keyframes target{
  0%{
    background:#B4D88B;
  }
  100%{
    background:#fff;;
  }
}

Here are some other examples of using the :target pseudo selector:

  1. A List Apart
  2. Stack Overflow

The difference between pseudo-classes and pseudo-elements

When both use the : syntax to denote pseudo-ness, it's difficult to remember the difference between a class and an element. The CSS3 spec provides a syntax for distinguishing between pseudo classes and pseudo elements: :class and ::element.

Pseudo classes are used to select elements which cannot be selected using a class or id. I like to think of pseudo elements as being able to add content to a node in the DOM without adding more markup, like all the cool things on one-div.com.

Most of the examples in this post reference pseudo classes, but Chris Coyier has a great round up of all the cool things you can do with pseudo elements over at CSS Tricks.

:before and :after

My most frequent use of the :before pseudo element is the micro clearfix. In Sass, you can extend a clearfix place holder:

Micro Clearfix adapted from Nicholas Gallagher.

%clearfix{
  :after{
    content: ' ';
    display: table;
    clear: both;
  }
}

:first-letter

There's no need to use images or hard code div's with a class if you want to pull off the drop cap technique:

Jesse Shawl is a Front End Developer at nclud - whose focus intersects web performance and cutting edge browser interactivity. He's an open source advocate who enjoys building tools for the web with third party API's and mesmerizing CSS animations.

p:first-letter{
  font-size: 5em;
  height: .75em;
  display: block;
  float: left;
  padding-right:.125em;
  line-height: 1;
  font-weight:bold;
  color:#B4D88B;
  text-shadow:4px 4px 0 #8DC63F;
}

~/ Posted by Jesse Shawl on 2013-12-12