Changing CSS pseudo-element styles via JavaScript

116,336

Solution 1

EDIT: There is technically a way of directly changing CSS pseudo-element styles via JavaScript, as this answer describes, but the method provided here is preferable.

The closest to changing the style of a pseudo-element in JavaScript is adding and removing classes, then using the pseudo-element with those classes. An example to hide the scrollbar:

CSS

.hidden-scrollbar::-webkit-scrollbar {
   visibility: hidden;
}

JavaScript

document.getElementById("editor").classList.add('hidden-scrollbar');

To later remove the same class, you could use:

document.getElementById("editor").classList.remove('hidden-scrollbar');

Solution 2

If you're comfortable with some graceful degradation in older browsers you can use CSS Vars. Definitely the easiest of the methods I've seen here and elsewhere.

So in your CSS you can write:

#editor {
  --scrollbar-background: #ccc;
}

#editor::-webkit-scrollbar-thumb:vertical {
  /* Fallback */
  background-color: #ccc;
  /* Dynamic value */
  background-color: var(--scrollbar-background);
}

Then in your JS you can manipulate that value on the #editor element:

document.getElementById("#editor").style.setProperty('--scrollbar-background', localStorage.getItem("Color"));

Lots of other examples of manipulating CSS vars with JS here: https://eager.io/blog/communicating-between-javascript-and-css-with-css-variables/

Solution 3

I changed the background of the ::selection pseudo-element by using CSS custom properties doing the following:

/*CSS Part*/
:root {
    --selection-background: #000000;
}
#editor::selection {
    background: var(--selection-background);
}

//JavaScript Part
document.documentElement.style.setProperty("--selection-background", "#A4CDFF");

Solution 4

You can't apply styles to psuedo-elements in JavaScript.

You can, however, append a <style> tag to the head of your document (or have a placeholding <style id='mystyles'> and change its content), which adjusts the styles. (This would work better than loading in another stylesheet, because embedded <style> tags have higher precedence than <link>'d ones, making sure you don't get cascading problems.

Alternatively, you could use different class names and have them defined with different psuedo-element styles in the original stylesheet.

Solution 5

I posted a question similar to, but not completely like, this question.

I found a way to retrieve and change styles for pseudo elements and asked what people thought of the method.

My question is at Retrieving or changing css rules for pseudo elements

Basically, you can get a style via a statement such as:

document.styleSheets[0].cssRules[0].style.backgroundColor

And change one with:

document.styleSheets[0].cssRules[0].style.backgroundColor = newColor;

You, of course, have to change the stylesheet and cssRules index. Read my question and the comments it drew.

I've found this works for pseudo elements as well as "regular" element/styles.

Share:
116,336
木川 炎星
Author by

木川 炎星

Updated on July 23, 2021

Comments

  • 木川 炎星
    木川 炎星 almost 3 years

    Is it possible to change a CSS pseudo-element style via JavaScript?

    For example, I want to dynamically set the color of the scrollbar like so:

    document.querySelector("#editor::-webkit-scrollbar-thumb:vertical").style.background = localStorage.getItem("Color");
    

    and I also want to be able to tell the scrollbar to hide like so:

    document.querySelector("#editor::-webkit-scrollbar").style.visibility = "hidden";
    

    Both of these scripts, however, return:

    Uncaught TypeError: Cannot read property 'style' of null

    Is there some other way of going about this?
    Cross-browser interoperability is not important, I just need it to work in webkit browsers.

  • Admin
    Admin over 9 years
    querySelector will not work with any pseudo-elements, because they're pseudo-elements, not actual elements that exist in the DOM.
  • Wes Ruvalcaba
    Wes Ruvalcaba over 5 years
    Right, it won't work in older browsers (caniuse.com/#search=css%20variables), but it will go to the fallback.
  • Fabian von Ellerts
    Fabian von Ellerts about 5 years
    This is the best answer if you need to target a specific element. For IE compatibility, include css-vars-ponyfill and run cssVars({ variables: { 'scrollbar-background': '#color' } }) when updating.
  • Ben Racicot
    Ben Racicot almost 5 years
    This is not an answer to the question.
  • kmsheng
    kmsheng almost 5 years
    This is not even relevant.
  • Armin
    Armin over 4 years
    Actually this is a great and simple workaround.
  • snarf
    snarf over 4 years
    It's not a workaround at all. This is standard operating procedure when your styling can be defined statically. If you don't know what the style will be until runtime, this doesn't help you it all.
  • Kathrine Hanson
    Kathrine Hanson about 4 years
    saved my time. thanks.
  • Muhammad Ashhar Hasan
    Muhammad Ashhar Hasan about 4 years
    I was already using css variables to change colors of scrollbar, but it was just updating all the internal scrollbars but not the main one (which is on whole page). So I did this by inserting new css rule, using insertRule() method. Hence, when the user selects a new theme it does two things delete the rule(if any) and insert the rule with new colors.
  • Rounin - Standing with Ukraine
    Rounin - Standing with Ukraine about 4 years
    That's really clever. Excellent solution.
  • Rafael
    Rafael almost 4 years
    This should be the accepted answer. Works like a charm :)
  • Nodira
    Nodira over 3 years
    The only normal answer I found for adding styles to pseudo-elements since yesterday! I'm setting --nav-opacity-level: 0; in scss and changing it's value to 1 in js. When the button is clicked, the js function sets the value to 1. But, the opacity is not getting set 0 as I'm initially setting it, but it's getting 1. Would really appreciate help :)
  • 3gwebtrain
    3gwebtrain over 3 years
    Adding removing class name is not directly alter the value of element. how about moving to center point for some reason? you need to calculation right?