This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
How to update placeholder color using Javascript?
(5 answers)
Closed 2 years ago.
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.
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/
To edit an existing one which you don't have a direct reference to requires iterating all style sheets on the page and then iterating all rules in each and then string matching the selector.
Here's a reference to a method I posted for adding new CSS for pseudo-elements, the easy version where you're setting from js
Javascript set CSS :after styles
var addRule = (function (style) {
var sheet = document.head.appendChild(style).sheet;
return function (selector, css) {
var propText = typeof css === "string" ? css : Object.keys(css).map(function (p) {
return p + ":" + (p === "content" ? "'" + css[p] + "'" : css[p]);
}).join(";");
sheet.insertRule(selector + "{" + propText + "}", sheet.cssRules.length);
};
})(document.createElement("style"));
addRule("p:before", {
display: "block",
width: "100px",
height: "100px",
background: "red",
"border-radius": "50%",
content: "''"
});
sheet.insertRule returns the index of the new rule which you can use to get a reference to it for it which can be used later to edit it.
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');
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");
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.
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.
An old question, but one I came across when try to dynamically change the colour of the content of an element's :before selector.
The simplest solution I can think of is to use CSS variables, a solution not applicable when the question was asked:
"#editor::-webkit-scrollbar-thumb:vertical {
background: --editorScrollbarClr
}
Change the value in JavaScript:
document.body.style.setProperty(
'--editorScrollbarClr',
localStorage.getItem("Color")
);
The same can be done for other properties.
Looks like querySelector won't work with pseudo-classes/pseudo-elements, at least not those. The only thing I can think of is to dynamically add a stylesheet (or change an existing one) to do what you need.
Lots of good examples here:
How do I load css rules dynamically in Webkit (Safari/Chrome)?
Related
This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
Closed 8 years ago.
My CSS looks like:
/* works */
.badger-left:after {
left: 0;
border-radius: 6px 0 6px 0;
background: #428bca;
}
jQuery to change it on the fly:
$('.badger-left:after').css('background-color', "red"); // doesnt work
$('.badger-left').attr({ 'data-badger': "USA" }); // works
HTML:
<div class="col-sm-12 badger-left" data-badger="">
</div>
Why isn't the jQuery selector working and what should I do to make it work?
http://screencast.com/t/onWs4KDJVD -- where it says "USA" (USA is set from the attr. data-badger in jquery), that background needs to change to red (or whatever color specified) via jQuery.
Thanks
The CSS selectors :after and :before is not supported in javascript, most pseudo-classes are not.
jQuery adds the css inline. Since :before, and :after do not really exist there is no style attribute to place the css into anyway.
Run this test to see:
$("*:after") // returns []
$("*") // returns a huge array ;)
You could use either a jQuery .append() or .add() to achieve a similar effect.
The CSS ::after selector just adds an "imaginary" div to the inside of the element it's applied to just before the closing tag.
.append()
https://api.jquery.com/append/
.add()
https://api.jquery.com/add/
jQuery:
$('.badger-left').append('div');
CSS:
.badger-left div{
/* ".badger-left::after" styling would go here */
}
This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
Closed 8 years ago.
Why does this snippet not work on a button? How can I do it correctly?
$('div.button:after').css({
display:'none'
})
You cannot select pseudo elements using inline CSS, think like the the way you cannot write :hover styles inline.
What jQuery does with .css() is it injects the styles inline so you cannot change a pseudo element using $('div.button:after').css().
The simple way to achieve that is by using say .addClass() method..
HTML
<div class="button">Hello</div>
CSS
.button:after {
content: " Hide this using jQuery";
color: red;
}
.hide_btn_pseudo:after {
display: none;
}
jQuery
$('div.button').addClass('hide_btn_pseudo');
Demo
Inorder to show the element, you can remove the class back, using .removeClass()
Actually you can't. Because it is a pseudo-element.
Setting CSS pseudo-class rules from JavaScript
But you can do this instead:
document.styleSheets[0].insertRule("div.button:after { display:'none'; }", 0);
document.styleSheets[0].cssRules[0].style.display= 'none';
Check the link for special IE notes.
This question already has answers here:
Get a CSS value from external style sheet with Javascript/jQuery
(5 answers)
Closed 9 years ago.
I am trying to access css property like this:
.box {
position: absolute;
background-color: red;
height: 10px;
width: 10px;
}
JS:
var height = $('.box').css('height');
I know, the above code is wrong and this actually doesn't work as .box is not available in the DOM.
Another thing that i tried:
var height = $("<span class='box'></span>").css('height');
My question is: how can I get the height of .box without having any element in the DOM with class box ?
On a modern browser you could use document.stylesheets, and the stylesheet would need to be in the original HTML and the source needs to match the Same Origin Policy, i.e. you can't inject the stylesheet from say a Chrome extension as it does not show in document.stylesheets
CSS
.box {
position:absolute;
background-color:red;
height:10px;
width:10px;
}
Javascript
function propertyFromStylesheet(selector, attribute) {
var value;
[].some.call(document.styleSheets, function (sheet) {
return [].some.call(sheet.rules, function (rule) {
if (selector === rule.selectorText) {
return [].some.call(rule.style, function (style) {
if (attribute === style) {
value = rule.style.getPropertyValue(attribute);
return true;
}
return false;
});
}
return false;
});
});
return value;
}
console.log(propertyFromStylesheet(".box", "height"));
Output
10px
On jsfiddle
The only way you can get then without using a DOM element is by downloading the stylesheet and parsing the contents. You can also access the compiled stylesheet by going to document.stylesheets and finding the rule. You can also use window.getComputedStyle(element) and create an element such as document.createElement('div') and attach the '.box' className to it.
Keep in mind that doing any of this implies that the stylesheet is on the same domain and port of where your html file is.
To get the computed height of an element as set in a stylesheet, it has to exists in the DOM. You solve this by creating an element, positioning it way off the visible screen, and appending it to the body (or anywhere really).
To get the height you can use .height(), or .innerHeight() to get the height without margins and borders, but including padding :
var elem = $('<span />', {'class':'box',
style:'position:fixed;top:-9999px'}).appendTo('body');
var height = elem.innerHeight();
elem.remove();
FIDDLE
There's usually no need to access and parse the stylesheet for this, except in really special cases, where you're not looking for something like an elements height, but for instance trying to check if some special style is set in a specific stylesheet etc.
Let's say you want to change the width of many elements, to simulate a table, for example. I realize you could do this:
$(".class").css('width', '421px');
This alters the inline style='width: 421px;' attribute for each element. Now, what I'd LIKE to do: is change the actual CSS rule definition:
.class {
width: 375px; ==[change to]==> 421px;
}
When it comes to 100's if not 1000's of nested <ul> and <li> that need to be changed, it seems like this would be better for performance than trying to let jQuery do the work through the .css() method.
I've found this example - this IS what I'm trying to do:
var style = $('<style>.class { width: 421px; }</style>')
$('html > head').append(style);
I'm NOT trying to swap classes ($el.removeClass().addClass()), because I can't have a class for EVERY optimal width (379px, 387px, 402px..).
I could create a <style> element and dynamically set the width, however I'm thinking there's a better way.
document.styleSheets[0].addRule works in Chrome, 'not a function' in FF
What works for me is to include an empty style block in the header:
<style id="custom-styles"></style>
And then manipulate that with something like this:
$('#custom-styles').text('h1 { background: red }')
I've tested this appears to work in current version of Chrome (well, Chromium - 63.0) and Firefox (57.0.4).
Lately I wondered about editing elements styles not by switching their classes on dom, but by changing the actual ruleset for the css class or selector.
So instead of something like
$('.some').hide()
or
$('.some').addClass('hidden')
Why not alter a rule directly with document.styleSheets and stuff?
Wouldn't this approach be generally more performant, at least with many elements, as we'd let the browser handle the ruleset changes natively?
You could for example add an style to .some, like display: none; and all .some elements would be immedeatly be hidden. There is no need to iterate over all those elements in js and hide them manually(like the example above).
Changing rulesets directly would more likely encourage classes that are context aware(or however you would call this..), as you'd hide all #persons > .item or something.
I still don't know best practices regarding classes that are named with context in mind, like for example control names like .calendar .ticket .item, versus single functionality classes like .hidden .left .green, as I usually need both types of conventions.
I am just asking what you think about this and what are benefits and drawbacks of the modifiying stylesheet approach versus how libraries like jquery handle changing styles?
Also, what do you think is good practice, what do you regard more as a hack?
cough javascript and hacking cough
Manipulating document.styleSheets is tricky due to differing implementations and the lack of a rule selector API. Currently if you want to manipulate a rule in a stylesheet you have to go through this process:
iterate over document.styleSheets
iterate over rules within current styleSheet object
if rule matches our class, edit the rule styles
Then there's the cascading issue. How do you know that a particular style on the rule you've matched won't be overridden by a different rule somewhere in the pages stylesheets? If you just bail out after changing the first matching rule you find, you can't be sure that the styles you set will actually be applied to the element, unless you stick an !important on each one, which will leave you with a whole different set of problems.
Even when you've manipulated the style sheet rules, the browser still has the same job to do — it has to recalculate all the styles by applying the cascade.
So, manipulating styleSheets doesn't look too appealing now, does it? Stick to class switching, trust me. Using jQuery and modern APIs like querySelectorAll make it plenty fast and the browser still does all the hard work like recomputing the style values.
Such a tricky question :(
But if you take boilerplate for instance, it has a some standard classes to use like:
/* Hide from both screenreaders and browsers: h5bp.com/u */
.hidden { display: none !important; visibility: hidden; }
/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: ; position: absolute; width: 1px; }
/* Hide visually and from screenreaders, but maintain layout */
.invisible { visibility: hidden; }
Where it gets tricky is, IF it is something you need to hide because of JS, then you should ONLY hide it with JS. Then it will function if JS is disabled.
If it is something that is not JS dependent, then you hide it in the HTML.
So JS function = hide with JS (either by using JS or adding hide classes)
Basic HTML hide = hide with HTML class
Styleswitching vs JS switching
Basicly JS switching gives you the oppertunity to add effect etc, just using predefined classes limits that somewhat. But would love to see some ressource comparisons :)