HTMLElement.pseudoStyle: Setting/Modifying :before and :after in javascript

posted in: Uncategorized | 5

As seen with many stack overflow answers such as this one, it is (technically) not possible to set or modify the :before and :after pseudo elements of an element using javascript, since they exist in the shadow DOM, although very easy to GET the properties as David Walsh (@davidwalshblog) has shown in the past.

Key word there is technically. Using some JavaScript magic, we can simulate it.

The JavaScript

var UID = {
	_current: 0,
	getNew: function(){
		this._current++;
		return this._current;
	}
};

HTMLElement.prototype.pseudoStyle = function(element,prop,value){
	var _this = this;
	var _sheetId = "pseudoStyles";
	var _head = document.head || document.getElementsByTagName('head')[0];
	var _sheet = document.getElementById(_sheetId) || document.createElement('style');
	_sheet.id = _sheetId;
	var className = "pseudoStyle" + UID.getNew();
	
	_this.className +=  " "+className; 
	
	_sheet.innerHTML += " ."+className+":"+element+"{"+prop+":"+value+"}";
	_head.appendChild(_sheet);
	return this;
};

Very simply here, we are extending the HTMLElement prototype to have a new function called pseudoStyle which accepts a pseudo element (:before, :after for example) a property, and a value. We then add a new unique class to the element, which is defined in a new “pseudoStyles” stylesheet that gets injected into the head of the document.

Example 1: Modify

Say we have these styles:

.test:before		{
	content: "testing";
	color: red;
}

And this HTML:

<div id="testDiv" class="test">test2</div>

In this example, we have an element which already has a :before with styles set. Here is how we would modify them:

var div = document.getElementById("testDiv");
div.pseudoStyle("before","color","purple");

See It in Action: http://jsfiddle.net/Tf69a/

Example 2: Set

Say we have an element with NO :before styles currently set:

<div id="testDiv">test2</div>

Here’s how we would set some :before styles:

var div = document.getElementById("testDiv");
div.pseudoStyle("before","content","'test'");
div.pseudoStyle("before","color","purple");

OR we can chain methods:

var div = document.getElementById("testDiv");
div.pseudoStyle("before","content","'test'").pseudoStyle("before","color","purple");

See it in action: http://jsfiddle.net/Tf69a/1/

Conclusion

While it is technically NOT possible to set styles to pseudo elements in JavaScript, we can simulate it using the above snippets.

Bonus: Micro Library

The javascript minified to be pretty tiny, a tiny 393 bytes.

(function(){a={_b:0,c:function(){this._b++;return this.b;}};HTMLElement.prototype.pseudoStyle=function(d,e,f){var g="pseudoStyles";var h=document.head||document.getElementsByTagName('head')[0];var i=document.getElementById(g)||document.createElement('style');i.id=g;var j="pseudoStyle"+a.c();this.className+=" "+j;i.innerHTML+=" ."+j+":"+d+"{"+e+":"+f+"}";h.appendChild(i);return this;};})();
My name is Andrew McGivery. I currently work full time as an application developer at Manulife Financial in Canada. My current passion is building and leading highly engaged teams where employee happiness, learning, and growth is a priority.

5 Responses

  1. Creative approach 🙂

    I’m not sure that extending the HTMLElement is the best approach here. I’d provide this as a regular function. Then, optionally, you could make jQuery/underscore/etc. plugins to get a nicer API, e.g. $elem.setPseudo(‘before’, { color: ‘red’ });

    • Yea, I was a little worried about extending HTMLElement too. I thought about going JQuery style, but for the sake of the simplicity of a blog post, I wanted to keep it vanilla JS. Would be pretty easy to extend to JQuery though.

  2. There is a stray “n” there, I think –
    _sheet.innerHTML += “n.”+className+”:”+element+”{“+prop+”:”+value+”}”;
    Should be –
    _sheet.innerHTML += ” .”+className+”:”+element+”{“+prop+”:”+value+”}”;

  3. Thanks for this.

    I tried to use your plugin but it created a new class every time I updated the attributes…

    Following the advice from Šime I reconstructed this idea as a jQuery plugin. You can find it here:

    https://github.com/makesites/jquery-pseudo

    Cheers

Leave a Reply