How change content value of pseudo :before element by Javascript [duplicate]
Asked Answered
R

8

68

I have the grap constructured by CSS, which is dynamically changes by JS. I show graph max value by pseudo element as:

.graph:before {
    content:""; //value that want set by JS
    position:absolute;
    top:0;
    left:0;
}

That's why I need to set this value by JS. I tried $(".graph:before").css("content", hh); but it didn't help. How to get that value?

Retrospect answered 8/5, 2012 at 8:35 Comment(3)
see this similar question #5041994Predetermine
It is doable as in 2016 using jQuery.Koetke
content is a String; in 2019 it is: .style.setProperty('--varname',"${value}");Experimentalize
H
37

Update (2018): as has been noted in the comments, you now can do this.

You can't modify pseudo elements through JavaScript since they are not part of the DOM. Your best bet is to define another class in your CSS with the styles you require and then add that to the element. Since that doesn't seem to be possible from your question, perhaps you need to look at using a real DOM element instead of a pseudo one.

Hyrup answered 8/5, 2012 at 8:37 Comment(6)
-@JamesAllardice this seems like a confusion-inducing decision by either the CSS or JS camps, do you know of any more context for this?Brittani
@timpeterson - The pseudo elements are there to provide a way to access otherwise inaccessible information about a document. They were never intended to be accessible from within the document. See the section on generated content in the CSS spec.Hyrup
A little late to this party, but for future readers, this isn't entirely correct. You can't directly modify pseudo elements with JS, but you can use javascript to modify element attributes which pseudo elements can "read". See the question linked above: #5041994Crap
You can't modify pseudo elements through JavaScript since they are not part of the DOM. really?Forcemeat
Maybe you should read this first! @james-allardice https://mcmap.net/q/282024/-how-to-get-a-dom-element-39-s-before-content-with-javascriptForcemeat
this is no longer true. the below answers proved that you CAN.Breslau
B
118

I hope the below snippet might help, you can specify the content value you want via JS using the CSS attr() function. Below you have two options: to use JavaScript or jQuery:

jQuery:

$('.graph').on('click', function () {
    //do something with the callback
    $(this).attr('data-before','anything'); //anything is the 'content' value
});

JavaScript:

var graphElem = document.querySelector('.graph');
graphElem.addEventListener('click', function (event) {
    event.target.setAttribute('data-before', 'anything');
});

CSS:

.graph:before {
    content: attr(data-before); /* value that that refers to CSS 'content' */
    position:absolute;
    top: 0;
    left: 0;
}
Britzka answered 2/2, 2017 at 10:44 Comment(7)
@RhysvanderWaerden The referenced site refers to lack of support of the attr() function for properties other than content. Otherwise, the support for this solution seems pretty broad.Malpractice
My mistake. Thanks for pointing it out. I'll delete my original comment since I cannot edit it.Mudslinger
do you know how to send unicode through this approach?Midsection
the problam with this is that it's not "anything" that you can set, html for eexample isn't interpreted.Breslau
@godblessstrawberry, I had the same question and found the answer on how to use unicode, here Example provided there was: <p><a href="#" data-fa-icon="&#xf206;"> Unicode example</a></p>Include
This solution is really clever (in my opinion) and solved my issue well, thank you @santosh-d!Bjork
Very helpful solutionFenrir
H
37

Update (2018): as has been noted in the comments, you now can do this.

You can't modify pseudo elements through JavaScript since they are not part of the DOM. Your best bet is to define another class in your CSS with the styles you require and then add that to the element. Since that doesn't seem to be possible from your question, perhaps you need to look at using a real DOM element instead of a pseudo one.

Hyrup answered 8/5, 2012 at 8:37 Comment(6)
-@JamesAllardice this seems like a confusion-inducing decision by either the CSS or JS camps, do you know of any more context for this?Brittani
@timpeterson - The pseudo elements are there to provide a way to access otherwise inaccessible information about a document. They were never intended to be accessible from within the document. See the section on generated content in the CSS spec.Hyrup
A little late to this party, but for future readers, this isn't entirely correct. You can't directly modify pseudo elements with JS, but you can use javascript to modify element attributes which pseudo elements can "read". See the question linked above: #5041994Crap
You can't modify pseudo elements through JavaScript since they are not part of the DOM. really?Forcemeat
Maybe you should read this first! @james-allardice https://mcmap.net/q/282024/-how-to-get-a-dom-element-39-s-before-content-with-javascriptForcemeat
this is no longer true. the below answers proved that you CAN.Breslau
S
31

You can use CSS variable

:root {
  --h: 100px;
}

.elem:after {
  top: var(--h);
}

let y = 10;

document.documentElement.style.setProperty('--h', y + 'px')

https://codepen.io/Gorbulin/pen/odVQVL

Starr answered 22/5, 2018 at 13:34 Comment(2)
Good solution, but this doesn't seem to work for setting the content property. If someone knows how to do this, please post an example.Jughead
@Jughead I made it work like so: const myContent = "content"; myElement.style.setProperty("--content", `'${myContent}'` ); and on CSS: .my-element::after { content: var(--content); }. The trick is wrapping the 'content' string between quotes, when you set the css property.Otherwhere
D
12

I believe there is a simple solution using the attr() function to specify the content of the pseudo element. Here is a working example using the 'title' attribute, but it should work also with custom attributes.:

document.getElementById('btn_change1').addEventListener("click", function(){
    document.getElementById('test_div').title='Status 1';
});
   
document.getElementById('btn_change2').addEventListener("click", function(){       
    document.getElementById('test_div').title='Status 2';
});
#test_div {
   margin: 4em;
   padding:2em;
   background: blue;
   color: yellow;
}

#test_div:after {
   content:attr(title);
   background: red;
   padding:1em;
}
<button id='btn_change1'>Change div:after to [Status 1]</button>
<button id='btn_change2'>Change div:after to [Status 2]</button>

<div id='test_div' title='Initial Status'>The element to modify</div>
Drue answered 1/10, 2017 at 2:3 Comment(0)
K
6

People who are still looking some solution of same problem, it is doable as follows using jQuery:

<button id="changeBefore">Change</button>
<script>
    var newValue = '22';//coming from somewhere
    var add = '<style>.graph:before{content:"'+newValue+'"!important;}</style>';
    $('#changeBefore').click(function(){
        $('body').append(add);
    });
</script>

This example illustrate that on clicking button: changeBefore , the value for .graph:before will change as per new dynamic coming value for it.

For more description about changing of :before or :after element style or getting its content:

Lets suppose your HTML is like this:

<div id="something">Test</div>

And then you are setting its :before in CSS and designing it like:

#something:before{
   content:"1st";
   font-size:20px;
   color:red;
}
#something{
  content:'1st';
}

Please notice I also set content attribute in element itself so that you can take it out easily later. Now there is a button clicking on which, you want to change the color of :before to green and its font-size to 30px. You can achieve that as follows:

Define a css with your required style on some class .activeS :

.activeS:before{
   color:green !important;
   font-size:30px !important;
 }

Now you can change :before style by adding the class to your :before element as follows:

<button id="changeBefore">Change</button>
<script>
    $('#changeBefore').click(function(){
        $('#something').addClass('activeS');
    });
</script>

If you just want to get content of :before, it can be done as:

<button id="getContent">Get Content</button>
<script>
    $('#getContent').click(function(){
        console.log($('#something').css('content'));//will print '1st'
    });
</script>

I hope it helps

Koetke answered 14/11, 2016 at 13:42 Comment(2)
best answer here. append (prepend) worked and the rest of the methods (attr, html, ect) did not. I did add the css from the answer above which is the best way to clear out what was already there.Breslau
Thank you, I am glad it helped you!Koetke
L
1

I had a similar problem, but with icons. I needed to switch the play and pause icons for an audio player in html5.

The problem here was that HTML, CSS and jQuery all interpret differently the "content" values to show icons, due to the use of \ symbol.

So the best workaround is to delete and re-create the node. Here's my code:

<ul class="list list--buttons">
    <li><a href="#" class="list__link previuos"><i class="fa fa-step-backward"></i></a></li>

    <li><a href="#" class="list__link playpause"><i class="fa fa-play"></i></a></li>

    <li><a href="#" class="list__link next"><i class="fa fa-step-forward"></i></a></li>
</ul>

And the script

<script type="text/javascript">
            $(
                function(){
                    var aud = $('audio')[0];
                    $('.playpause').on('click', function(e){
                        e.preventDefault();
                    if (aud.paused) {
                        aud.play();
                        /* from play icon to pause icon */
                        $('.playpause .fa-play').remove();
                        $('.playpause').append('<i class="fa fa-pause"></i>');
                    }
                    else {
                        aud.pause();
                        /* from play icon to pause icon */
                        $('.playpause .fa-pause').remove();
                        $('.playpause').append('<i class="fa fa-play"></i>');
                    }

                })
                $('.next').on('click', function(e){
                    e.preventDefault();
                    aud.src = '{$content:audio-file}';
                })
                $('.previuos').on('click', function(e){
                    e.preventDefault();
                    aud.src = '{$content:audio-file}';
                })
                aud.ontimeupdate = function(){
                    $('.progress').css('width', aud.currentTime / aud.duration * 100 + '%')
                }
            })
        </script>

Hope it helps!

Lepidopteran answered 12/4, 2020 at 9:42 Comment(0)
M
1

You can use document.styleSheets to modify pseudo selector cssRules

document.styleSheets[0].cssRules[0].style.content = '"111"';
Massenet answered 13/6, 2020 at 10:30 Comment(1)
This tell us it actually CAN be done, without the content: attr(...) (and I'd almost +1 you for it), but should it be done that way? Only if you wish to change your Twitter bio from "Developer of web applications" to "Maintainer of one project".Tennilletennis
M
-1

If you use something like an onoffswitch and want to translate the css content attribute with i18next then you can use one of the i18next Framework example from github (i18next Jquery Framework) and then you extended the function with this code:

var before = i18next.t('onoffswitch.before');
var after = i18next.t('onoffswitch.after');
$('.onoffswitch-inner')
    .attr('data-before', before )
    .attr('data-after', after );

and the css code must be this:

.onoffswitch-inner:before {
    content:  attr(data-before);
    padding-left: 10px;
    background-color: #65AFF5; color: #FFFFFF;
}
.onoffswitch-inner:after {
    content:  attr(data-after);
    padding-right: 10px;
    background-color: #EEEEEE; color: #999999;
    text-align: right;
}
Melcher answered 20/2, 2019 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.