« Back to Index

better CSS pseudo-element selector detector

View original Gist on GitHub

Tags: #js

detect.css

body {
    font: normal small Helvetica, Arial, Verdana, sans-serif;
}

h1 {
    border-bottom: 1px solid #C00;
    color: #666;
    font-weight: bold;
    margin-bottom: 10px;
}

div {
    border: 1px dashed #333;
    padding: 10px;
}

div,
div p {
    margin-bottom: 10px;    
}

code {
    color: blue;
}

ul {
    list-style: disc;
    margin-left: 10px;
    padding-left: 10px;
}

.before #apply:before {
    color: red;
    content: "before";
    display: inline-block;
    margin: 0 5px 5px 0;
}

.after #apply:after {
    color: green;
    content: "after";
    display: inline-block;
    margin: 0 0 0 55px;
}

detect.html

<h1>Detection script for CSS :before and :after support</h1>
<div>
    <p>This script detects support of the CSS selectors <code>:before</code> and <code>:after</code> by:</p>
    <ul>
        <li>Adding two empty paragraph elements to the page (effectively their height each is zero).</li>
        <li>Adding a style element to the page (+inserting the relevant <code>:before</code>/<code>:after</code> code).</li>
        <li>Checking the height of the element using offsetHeight.</li>
        <li>If the height is greater or equal to 1 then we know the content was added so support is detected.</li>
        <li>Much like <a href="http://www.modernizr.com/">Modernizr</a> we add relevant class names to the main <code>html</code> element</li>
    </ul>
</div>
<p id="apply">Paragraph 1</p>
<p>Paragraph 2</p>

detect.js

window.onload = function() {
    var doc = document,
        html = doc.documentElement,
        body = doc.body,
        paraBefore = doc.createElement('p'),
        paraAfter = doc.createElement('p'),
        styleBefore = doc.createElement('style'),
        styleAfter = doc.createElement('style'),
        heightBefore, 
        heightAfter, 
        selectorsBefore = '#testbefore:before { content: "before"; }',
        selectorsAfter = '#testafter:after { content: "after"; }';

    // Internet Explorer seems to need a type attribute to recognise a stylesheet?
    styleBefore.type = 'text\/css';
    styleAfter.type = 'text\/css';

    paraBefore.id = 'testbefore';
    paraAfter.id = 'testafter';

    // For Internet Explorer...
    if (styleBefore.styleSheet) {
        styleBefore.styleSheet.cssText = selectorsBefore;
        styleAfter.styleSheet.cssText = selectorsAfter;
    } else {
        styleBefore.appendChild(doc.createTextNode(selectorsBefore));
        styleAfter.appendChild(doc.createTextNode(selectorsAfter));
    }

    body.appendChild(styleBefore);
    body.appendChild(styleAfter);
    body.appendChild(paraBefore);
    body.appendChild(paraAfter);

    heightBefore = doc.getElementById('testbefore').offsetHeight;
    heightAfter = doc.getElementById('testafter').offsetHeight;
    
    console.log(heightBefore, heightAfter);

    if (heightBefore >= 1) {
        html.className += ' before';
        body.removeChild(styleBefore);
        body.removeChild(paraBefore);
    }

    if (heightAfter >= 1) {
        html.className += ' after';
        body.removeChild(styleAfter);
        body.removeChild(paraAfter);
    }
};