2020
Some advantages of this method:
- Does not require (but allows) stylesheet to be specified.
- Allows multiple styles to be added / modified at once
- Accepts
!important
attribute
- Ignores extra whitespace when matching CSS selector
- Changes last matching existing rule, or appends to end of last matching stylesheet. (Other answers add/change the first rule which may be then overruled.)
Usage:
adjustCSSRules('#myDiv', 'width: 300px !important');
Method:
function adjustCSSRules(selector, props, sheets){
// get stylesheet(s)
if (!sheets) sheets = [...document.styleSheets];
else if (sheets.sup){ // sheets is a string
let absoluteURL = new URL(sheets, document.baseURI).href;
sheets = [...document.styleSheets].filter(i => i.href == absoluteURL);
}
else sheets = [sheets]; // sheets is a stylesheet
// CSS (& HTML) reduce spaces in selector to one.
selector = selector.replace(/\s+/g, ' ');
const findRule = s => [...s.cssRules].reverse().find(i => i.selectorText == selector)
let rule = sheets.map(findRule).filter(i=>i).pop()
const propsArr = props.sup
? props.split(/\s*;\s*/).map(i => i.split(/\s*:\s*/)) // from string
: Object.entries(props); // from Object
if (rule) for (let [prop, val] of propsArr){
// rule.style[prop] = val; is against the spec, and does not support !important.
rule.style.setProperty(prop, ...val.split(/ *!(?=important)/));
}
else {
sheet = sheets.pop();
if (!props.sup) props = propsArr.reduce((str, [k, v]) => `${str}; ${k}: ${v}`, '');
sheet.insertRule(`${selector} { ${props} }`, sheet.cssRules.length);
}
}
The method takes three arguments:
- selector [String] - CSS selector - eg: '#myDiv'
Whitespaces are auto-reduced (.myClass #myDiv
will match .myClass #myDiv
)
- rules [CSS String, Object] - eg (either is acceptable):
{ border: "solid 3px green", color: "white" }
'border: solid 3px green; color: white'
- sheet (Optional) [String, StyleSheet]
- if empty, all stylesheets will be checked
- 'myStyles.css' A relative or absolute URL to sheet
document.styleSheets[1]
- A reference to a sheet
Other examples:
adjustCSSRules('#myDiv', {width: '30px'}); // all stylesheets
adjustCSSRules('#myDiv', 'width: 30px', 'style.css'); // style.css only
adjustCSSRules('#myDiv .myClass', 'width: 30px', document.styleSheets[0]); // only first stylesheet