77

I need to get :after and assign it to variable. It is possible?

querySelectorAll doesn't work.

alert(some_div_with_pseudo.querySelectorAll('::after')[0]) // undefined
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
A. Petrov
  • 902
  • 1
  • 6
  • 6
  • 1
    You _cannot_, as the name 'pseudo' implies. These are not part of the actual DOM, they are, to javascript, style rules applied to an actual element. – somethinghere Aug 10 '16 at 13:50
  • 1
    JavaScript *absolutely* can read/write CSS pseudo `content`; see my answer below for a *write-mode* example. – John May 23 '19 at 15:15
  • 1
    This question is not a duplicate of the other question. You will note that the other question involves jQuery, and the selected answer doesn’t answer this one. – Manngo Nov 10 '20 at 19:35

6 Answers6

59

The short answer is that you can’t. It’s not there yet.

JavaScript has access to the DOM, which is built when the page is loaded from HTML, and modified further when JavaScript manipulates it.

A pseudo element is generated by CSS, rather than HTML or JavaScript. It is there purely to give CSS something to hang on to, but it all happens without JavaScript having any idea.

This is how it should be. In the overall scheme of things, the pages starts off as HTML. JavaScript can be used to modify its behaviour and to manipulate the content on one hand, and CSS can be used to control the presentation of the result:

HTML [→ JavaScript] → CSS → Result

You’ll see that CSS, complete with pseudo elements, comes at the end, so JavaScript doesn’t get a look in.

See also:

Edit

It seems that in modern JavaScript there is a workaround using window.getComputedStyle(element,pseudoElement):

var element = document.querySelector(' … ');
var styles = window.getComputedStyle(element,':after')
var content = styles['content'];
Manngo
  • 14,066
  • 10
  • 88
  • 110
  • 1
    The problem with getComputedStyle is that if you put the wrong literal, you will get the same result as if you didn't put the 2nd variable at all, e.g. getComputedStyle(element,':afterrrr')==getComputedStyle(element) so the function behaves wierdly. – Nathan B Jul 21 '21 at 10:55
  • Does anyone know how to get updated styles when the pseudo element is `:hover`ed or `:active`. It seems `getComputedStyle` only returns the original style of the pseudo element. `getComputedStyle` does, however, return the updated the style of ***regular*** elements when they're `:hover`ed or `:active` – Levi Uzodike Apr 28 '22 at 20:06
  • I don't know that the edit is the proper solution to the question but it certainly is a correct answer the problem I had! – Staghouse Jun 15 '22 at 15:31
39

You can do this:

window.getComputedStyle(
    document.querySelector('somedivId'), ':after'
);

Sample here: https://jsfiddle.net/cfwmqbvn/

vsync
  • 118,978
  • 58
  • 307
  • 400
Didier Aupest
  • 3,227
  • 2
  • 23
  • 35
  • 2
    It return style. I need element – A. Petrov Aug 10 '16 at 11:45
  • 27
    ":after" is a pseudo element, not an element. You can not return a dom node, it isn't one - all you can do it get the styles :) – MrBizle Aug 10 '16 at 13:37
  • @MrBizle Its a shadow dom element. – John Libes Mar 02 '20 at 17:58
  • @MrBizle how can I check if the pseudo element exist? – Kick Buttowski Aug 16 '21 at 02:02
  • 1
    Does anyone know how to get updated styles when the pseudo element is `:hover`ed or `:active`. It seems `getComputedStyle` only returns the original style of the pseudo element. `getComputedStyle` does, however, return the updated the style of regular elements when they're `:hover`ed or `:active` – Levi Uzodike Apr 28 '22 at 20:41
5

I use an arrow pointing in the direction that the content and sidebar will toggle to/from via a CSS pseudo-element. The code below is effectively a write mode however it is entirely possible to read CSS pseudo-element content as well.

Since there is a bit involved I'll also post the prerequisites (source: JAB Creations web platform JavaScript documentation, if anything missing look it up there) so those who wish to try it out can fairly quickly do so.

CSS

#menu a[href*='sidebar']::after {content: '\2192' !important;}

JavaScript Use

css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');

JavaScript Prerequisites

var sidebar = 20;


function id_(id)
{
 return (document.getElementById(id)) ? document.getElementById(id) : false;
}


function css_rule_set(selector,property,value,important)
{
 try
 {
  for (var i = 0; i<document.styleSheets.length; i++)
  {
   var ss = document.styleSheets[i];
   var r = ss.cssRules ? ss.cssRules : ss.rules;

   for (var j = 0; j<r.length; j++)
   {
    if (r[j].selectorText && r[j].selectorText==selector)
    {
     if (typeof important=='undefined') {r[j].style.setProperty(property,value);}
     else {r[j].style.setProperty(property,value,'important');}
     break;
    }
   }
  }
 }
 catch(e) {if (e.name !== 'SecurityError') {console.log('Developer: '+e);}}
}


function sidebar_toggle()
{
 if (id_('menu_mobile')) {id_('menu_mobile').checked = false;}

 if (getComputedStyle(id_('side')).getPropertyValue('display') == 'none')
 {
  css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');

  if (is_mobile())
  {
   css_rule_set('main','display','none','important');
   css_rule_set('#side','width','100%','important');
   css_rule_set('#side','display','block','important');
  }
  else
  {
   css_rule_set('main','width',(100 - sidebar)+'%');
   css_rule_set('#side','display','block');
  }
 }
 else
 {
  css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2190"','important');

  if (is_mobile())
  {
   css_rule_set('main','display','block','important');
   css_rule_set('main','width','100%','important');
   css_rule_set('#side','display','none','important');
  }
  else
  {
   css_rule_set('main','width','100%','important');
   css_rule_set('#side','display','none');
  }
 }
John
  • 1
  • 13
  • 98
  • 177
  • This is a really interesting solution. If I'm understanding this correctly, you're getting looping through the styleSheet objects, looking within those for selectors that match your target (in the case of the pseudo element `'#menu a[href*="sidebar"]::after'` ) and then updating the individual declaration within that with the new value you provide? It isn't the usecase in this question, but this would only work if there is already an existing style declaration targeting the pseudo element right? – Brice Mar 04 '22 at 17:10
2

There is a way in JavaScript to access value of pseudo elements without any library. To get the value, you need to use the 'getComputedStyle' function. The second parameter is optional.

let elem = window.getComputedStyle(parent, ':before');
alert(elem.getPropertyValue('background'))

This will do alert the value of pseudo element.

SamiunNafis
  • 142
  • 2
  • 10
2

Changing or setting the style of CSS pseudo-element is a tricky one, actually, you can not do this directly or maybe I do not know the way yet, but I will share a technique with you to do this.

-Use CSS variable to design your CSS pseudo-element and change the value of the variable using javascript and this will change the style of your CSS pseudo-element.

CSS:

 #box::after{
 content: 'this is after';
 background-color: var(--boxAfterBackColor,red);
 position: absolute;
 top: -20px;
 right: 0px;
 font-size: var(--boxAfterFontSize,20px);
}

JavaScript:

let box = document.getElementById('box');
box.style.setProperty('--boxAfterBackColor','green');
box.style.setProperty('--boxAfterFontSize','50px');

This works for me, hope it will help you too. Best of Luck!

Zethyst
  • 33
  • 6
  • 2
    This is brilliant! I had an unusual situation where this method was the best alternative. I wanted to style a React forwardRef component. When I used the styled-components library and jest-styled-components, the jest snapshots still had the random className in the forwardRef node. This method allows me to ditch the styled-component so the snapshots work as expected. – Stefan Musarra Jun 09 '23 at 09:21
0

let elem = window.getComputedStyle(document.querySelector('#item'), ':after'); console.log(elem.getPropertyValue('content'))

  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 08 '22 at 04:50