Manipulating CSS pseudo-elements using jQuery (e.g. :before and :after)

(original source from Stackoverflow, answer written by Blazemonger )

My situation:
I’ve a CSS file and I need to dynamically change the values of .is-selected:after and .is-selected:before from Javascript based on the user selection.

Here is my code

.is-selected {
    position: relative;
}
.is-selected:after, .topUp .is-selected:before {
    top: 85px;
    left: 0;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}
.is-selected:after {
    border-color: rgba(136, 183, 213, 0);
    border-top-color: #9C2AA0;
    border-width: 31px;

    width: 1px;
    overflow: hidden;
}
.is-selected:before {
    border-color: rgba(194, 225, 245, 0);
    border-top-color: #ffffff;
    border-width: 38px;
    margin-left: -6px;
}

After few tries I’ve realised I can’t manipulate them because it’s not technically part of the DOM and therefore is inaccessible by any JavaScript.
However, I’ve found and here reported from an answer in Stackoverflow, written by Blazemonger, few alternatives to do it.


I’m going to start with what’s widely considered the “best” approach:

1) Add/remove a predetermined class

In this approach, you’ve already created a class in your CSS with a different :after or :before style. Place this “new” class later in your stylesheet to make sure it overrides:

p:before {
    content: "foo";
}
p.special:before {
    content: "bar";
}

Then you can easily add or remove this class using jQuery (or vanilla JavaScript):

$('p').on('click', function() {
    $(this).toggleClass('special');
});

http://jsfiddle.net/mblase75/fa5Wn/

Pros: Easy to implement with jQuery; quickly alters multiple styles at once; enforces separation of concerns (isolating your CSS and JS from your HTML)
Cons: CSS must be pre-written, so the content of :before or :after isn’t completely dynamic

2) Add new styles directly to the document’s stylesheet

It’s possible to use JavaScript to add styles directly to the document stylesheet, including :after and :before styles. jQuery doesn’t provide a convenient shortcut, but fortunately the JS isn’t that complicated:

var str = "bar";
document.styleSheets[0].addRule('p.special:before','content: "'+str+'";');

http://jsfiddle.net/mblase75/n8tVX/

.addRule() and the related .insertRule() methods are fairly well-supported today.

As a variation, you can also use jQuery to add an entirely new stylesheet to the document, but the necessary code isn’t any cleaner:

var str = "bar";
$('<style>p.special:before{content:"'+str+'"}</style>').appendTo('head');

http://jsfiddle.net/mblase75/3qc4k/

If we’re talking about “manipulating” the values, not just adding to them, we can also read the existing :after or :before styles using a different approach:

var str = window.getComputedStyle(document.querySelector('p'), ':before') 
           .getPropertyValue('content');

http://jsfiddle.net/mblase75/nHCM6/

We can replace document.querySelector(‘p’) with $(‘p’)[0] when using jQuery, for slightly shorter code.

Pros: any string can be dynamically inserted into the style
Cons: original styles aren’t altered, just overridden; repeated (ab)use can make the DOM grow arbitrarily large

3) Alter a different DOM attribute

Most browsers allow you to use attr() in your CSS to read a particular DOM attribute. By combining this with content: in some carefully-prepared CSS, we can change the content (but not other properties, like margin or color) of :before and :after dynamically:

p:before {
    content: attr(data-before);
    color: red;
    cursor: pointer;
}

JS:

$('p').on('click', function () {
    $(this).attr('data-before','bar');
});

http://jsfiddle.net/mblase75/Tfc9j/

This can be combined with the second technique if the CSS can’t be prepared ahead of time:

var str = "bar";

document.styleSheets[0].addRule('p:before', 'content: attr(data-before);');

$('p').on('click', function () {
    $(this).attr('data-before', str);
});

http://jsfiddle.net/mblase75/Lfba2/

Pros: Doesn’t create endless extra styles
Cons: attr in CSS can only apply to content strings, not URLs or RGB colors

Advertisements