Spoooooky CSS Selectors

Avatar of Chris Coyier
Chris Coyier on

Let’s get into the spirit a little bit this year with some Halloween themed posts! I’ll kick it off with some CSS selectors FROM BEYOND THE GRAVE. Er. CSS selectors that will CHILL YOU TO THE BONE. OK maybe not, but they will be at least kinda weird.

The Lobotomized Owl Selector

Heydon Pickering made this one famous two years ago. I looks like this:

* + * {
  margin-top: 1.5em;

Lobotomized owl? Get it?!

Illustration by Ping Zhu, kiped from A List Apart

The idea is that only elements that have a previous sibling get margin on top. So that you don’t have to do stuff like:

.the-last-one-so-don't-put-margin-on-me {
  margin-bottom: 0;

Instead, you get even spacing kinda for free:

See the Pen Lobotomized Owl by Chris Coyier (@chriscoyier) on CodePen.

You can see other people playing around with it.

The Mr. Ghost Selector

This little guy is such weird characters that my WordPress site won’t even save them, so let’s do this in a Pen (the embed might look weird too, try looking on CodePen itself):

See the Pen Ghost Selectors by Chris Coyier (@chriscoyier) on CodePen.

Speaking of unusual characters, remember that emoji are valid too!

<div class="&#x1f47b;">
  Mrs. Ghost
.&#x1f47b; {


Monster Selectors

Speaking of unusual characters, how about some of these dongers:

Those could be selectors too! But in this case, some of those characters need to be escaped in CSS. ESCAPE FROM MONSTER ISLAND. Or something. Fortunately Mathias Bynens has a tool for that.

Which means we can do like:

See the Pen jrRBqB by Chris Coyier (@chriscoyier) on CodePen.

Or how about some FANGS:

<div ^^=^^>
[\^\^^=\^\^] {

Another Lobotomy Selector

How about one like this:

the-brain:empty {
  color: green;

What kind of selector is the-brain? It’s an element we CREATED OURSELVES through MAD SCIENCE like FRANKENSTEIN’S MONSTER. Or just create a custom element or whatever.

  The brain!
var tmpl = document.querySelector('template');

var brainProto = Object.create(HTMLElement.prototype);

brainProto.createdCallback = function() {
  var root = this.createShadowRoot();
  root.appendChild(document.importNode(tmpl.content, true));

var brain = document.registerElement('the-brain', {
  prototype: brainProto

(Maybe this is supposed to use customElements.define() these days? I dunno.)

So now our original selector will match if we do:


But as the selector suggests, it will not match if we do:

  Fallback content inside.

It won’t even match:

<the-brain> </the-brain>

Otherwise we could do the-brain:blank {}, but :blank isn’t really supported yet.

The Insensitive Selector

What’s scarier than insensitivity? Other than MOST ANYTHING. Yah well this is still a really weird looking selector, right?

a[href$=".zip" i] {


The ” i” at the end there is telling the attribute value that “.zip” can match upper or lower case characters.

This one is from Wes Bos:

The Only The Righteous Shall Stand Selector

ZOMBIE Zebra striping is easy right?

tr:nth-child(odd) {
  background: WhiteSmoke;

But what if we BANISH some rows from visibility with our MAGIC SPELL OF JAVASCRIPT by applying a class name to certain rows:

<tr class="BANISHED"><td></tr></tr>
  display: none;

Now our zebra striping is all messed up, like too many newts fell into the cauldron during spellcasting (ug, sorry).

Selectors Level 4 has a fix:

tr:nth-child(odd of li:not(.BANISHED)) {
  background: WhiteSmoke;

This would mean that “odd” is only calculated on the rows that are still visible, and the zebra striping will remain intact.

It’s not supported anywhere yet though, so let’s SCREAM LIKE A BANSHEE until it is.

The Knife Through The Guts Selector

Remember that custom element we created? <the-brain>? Let’s say the template for that element was like this instead, having some actual HTML in there:

  <div class="braaaain">The brain!</div>

As we already saw, you can apply CSS to that element and it will cascade into there as you might expect. But you can’t get your BLOODY HANDS on elements inside directly.

/* works fine */
the-brain {
  color: pink;
/* But you can't reach inside like this */
.braaaain {
  color: red;

That’s encapsulation. It’s kind of the point of web components. You can stick a knife through that SPOOKY OL’ SHADOW DOM though, like this:

html /deep/ .braaaain {
  color: red;

That only works in Blink though and I have no idea if it’s standard or what. Ahhh the TERRORS of CROSS-BROWSER COMPATIBILITY.

The ID selector

#container {


Too specific. #lol