This question already has answers here:
Closed 5 months ago.
I have defined a css like
.slidingTag li:after {
content: '';
z-index: 3;
height: 6px;
}
I want to change the height attribute dynamically from JS. I can get the property using
window.getComputedStyle(document.querySelector('.slidingTag'), 'li:after').getPropertyValue('height')
But I do not know how to change the height attribute. I tried to use setProperty
but it seems there is no such function available for pseudo-classes. Any ideas let me know.
If that style comes from a CSS file, you'll have to search for it in document.styleSheets
, which will be messy.
If you are open to dynamically creating a <style>
element containing that CSS instead, you can modify it programmatically.
var slidingTagLiAfterStyle = document.createElement("style");
slidingTagLiAfterStyle.innerHTML =
".slidingTag li:after {
content: '';
z-index: 3;
height: 6px;
}";
document.head.appendChild(slidingTagLiAfterStyle);
...
slidingTagLiAfterStyle.innerHTML = slidingTagLiAfterStyle.innerHTML.replace(/height: [0-9]+px/, "height: 12px"); // or whatever you want to set it to
Pseudo-elements like :before and :after are handled by CSS, not the DOM. Because of this, you need to take a different approach.
What you can do is find the CSS rule responsible for this pseudo-element, and change that. You do this using CSSOM, which is a rather different API, even though you first get access to it from the DOM.
Unlike the DOM, CSS rules don't have ids or class names that can be searched for cleanly and quickly, so we have to search through the list of stylesheets and style rules. This can be expensive, so if it's possible to search for it only once, I strongly recommend doing that. Here's a quick-and-dirty way to do that:
function getRuleWithSelector(selector) {
var numSheets = document.styleSheets.length,
numRules,
sheetIndex,
ruleIndex;
// Search through the style sheets.
for (sheetIndex = 0; sheetIndex < numSheets; sheetIndex += 1) {
numRules = document.styleSheets[sheetIndex].cssRules.length;
for (ruleIndex = 0; ruleIndex < numRules; ruleIndex += 1) {
if (document.styleSheets[sheetIndex].cssRules[ruleIndex].selectorText === selector) {
return document.styleSheets[sheetIndex].cssRules[ruleIndex];
}
}
}
// If we get this far, then the rule doesn't exist.
// So the return value is undefined.
}
var afterSlidingTagRule = getRuleWithSelector('.slidingTag li::after');
console.debug(afterSlidingTagRule);
window.addEventListener('DOMContentLoaded', function() {
afterSlidingTagRule.style.fontSize = "10px";
}, false);
.slidingTag {
color: blue;
}
.slidingTag li {
color: green;
}
.slidingTag li:after {
content: "World";
font-size: 32px;
}
<ul class="slidingTag">
<li class="selected">Hello</li>
<li>World</li>
</ul>
Once you've got the rule you need, the rest is very similar to working with getComputedStyle(), or with a DOM element's style
attribute. The snippet above does it in a DOMContentLoaded event handler, but you should be able to do it at any point once things have loaded.
There are a few caveats to be considered with this approach:
- When you change a CSS rule, that change gets reflected in every element that the rule selects. If you have a rule that affects many elements, and you need to change the way all those elements look, this is great. If you have a rule that affects many elements, but you only need to change the look of one of those elements, this isn't so good.
- CSSOM's view of your selector text may not match what you wrote. This comes up in this very example, in fact, because your selector should read
.slidingTag li::after
(note the extra colon). The browser corrects this when it parses your CSS, and this is what CSSOM knows to look for.
- Just because a rule says something doesn't mean the element will display that way. Anything that can override a CSS rule -element-specific styles, more specific rules elsewhere in the set,
!important
declarations, and so on- can also override your changes.
- This isn't a substitute for
getComputedStyle()
. That follows from the above: if something changes an element's presentation, that doesn't affect the underlying CSS rules. If anything, it is the opposite of getComputedStyle()
: instead of getting what an element currently displays, it sets what certain elements should display (barring unforeseen circumstances).
You can add an extra class to you element that have a different property on the :after
, like:
first you have this:
HTML:
<div class="slidingTag">
<li>lorem ipsum</li>
</div>
CSS:
.slidingTag li:after {
content: '';
z-index: 3;
height: 6px;
}
then you got this:
New class that will override the property height
:
.slidingTag-modifier li:after {
content: '';
z-index: 3;
height: 10px !important;
}
final HTML:
<div class="slidingTag slidingTag-modifier">
<li>lorem ipsum</li>
</div>
To do that with javascript:
var element = document.querySelector('.slidingTag');
//use this instruction wherever you want to add the new class that will override the property
element.classList.add('slidingTag-modifier');
//works only on recent browsers
cheers!