CSS Quirks with :after and :before Pseudo Elements

May 11th, 2013

My colleague came across some quirks with the less commonly used :after and :before pseudo elements. Take a look at the following examples:

div:after {
    width: 100px;
    height: 100px;
    background: #000;
    content: "";
    display: block;
}

img:after {
    width: 100px;
    height: 100px;
    background: #000;
    content: "";
    display: block;
}

It should show a black empty block after the element selected. One of these works, one of them doesn’t. Can you guess which one and why? I couldn’t, until I did a little more digging.

According to the CSS2 Specification:

Note. This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.

Except, it never was, and no browsers really followed up or decided to make replaced elements work with :after and :before.

So what’s a “replaced element”? It’s any element that has an appearance defined by an external resource. The following are replaced elements: <img>, <object>, <button>, <textarea>, <input> and <select> (to name a few). The form elements are a little weird to classify under this same distinction, although I suppose their appearance is defined by the browser and/or operating system. This line gets even more blurry with the new appearance property (commonly used with it’s prefixed forms, -webkit-appearance and -moz-appearance) which removes browser/os styling from these elements.

Although, funnily enough, button:after does indeed work in Chrome and Firefox (possibly others?). But it places the :after element INSIDE the button element. Wat?

Upon testing, there’s other layout elements that also do not function with :after and :before, including: <br>, <embed>, <col> and more void elements (as they areĀ referredĀ to in HTML5). Void elements are elements that never have contents under any circumstances; however, hr:after works just fine, even though the horizontal rule is in fact a void element as well. There goes that theory!

So in conclusion, :after and :before are broken and there’s no proper specification listed for what they do across all elements. It also seems completely inconsistent across all browsers for which elements they do work with, and with the case of the button? I have no idea what to say about that one. Check it out here:

http://jsfiddle.net/Drath/SYpSD/

This entry was posted in Blog and tagged .

Leave a Reply

*

*

TOP