Use browser to parse CSS without touching DOM / styles

I have something like:

const someCSS = ` .foo { padding: 20px; background-color: #ddf; width: 100px; } .bar { height: 100px; } .foo { padding-top: 30px; /* this overrides the previous one */ } `; 

I can add this to the DOM and return all selectors with every rule like this ( jsFiddle ):

 const style = document.createElement('style'); style.innerHTML = someCSS; document.head.append(style); const styleSheet = Array.from(document.styleSheets).find(ss => ss.ownerNode == style); const rules = Array.from(styleSheet.rules).map(rule => rule.cssText); function styleToObject(rules, mergeWith = {}) { return [...rules].reduce( (obj, rule) => (obj[rule] = rules[rule], obj), mergeWith ); } const styleObject = Array.from(styleSheet.rules).reduce( (obj, rule) => (obj[rule.selectorText] = styleToObject(rule.style, obj[rule.selectorText]), obj), {} ); document.querySelector('pre').appendChild( document.createTextNode(JSON.stringify(styleObject, null, '\t')) ); 

and get something like this:

 { ".foo": { "padding-top": "30px", "padding-right": "20px", "padding-bottom": "20px", "padding-left": "20px", "background-color": "rgb(221, 221, 255)", "width": "100px" }, ".bar": { "height": "100px" } } 

Is there any other way to get the browser to do this without touching the DOM? I mean, CSS text is processed by the browser (without regular expression) without actually styling anything on the page.

Although I am adding it to iFrame, but before adding it to the DOM the document is not available ...

+5
source share
1 answer

The short answer is no, you cannot change the DOM without changing it.

If you are concerned that the added element triggers a redraw or a loaded style that affects the page in any way, you can add an β€œinappropriate” media rule to the <style> element you are creating.

For instance:

 style.setAttribute('media', '(max-width: 0)'); 

Working violin

EDIT While working on an example using this trick / hack / solution, you can find it here . Just now we noticed an update to a question that is quite similar in mechanics (although my example will work in less green browsers (not part of the question, I know)).

I checked some sources that I came across when I tried to do a similar thing, especially MDN - CSSStylesheets is very thorough and states:

A CSSStyleSheet object is created and inserted into the document styleSheets is automatically displayed in the browser when the stylesheet is loaded for the document. Since the list document.styleSheets cannot be changed directly, there is no useful way to create a new CSSStyleSheet object manually (although the Style Sheet constructive objects can get added to the web interfaces at some point). To create a new stylesheet, insert an element or element into the document.

(Emphasis mine. CSO is already mentioned by @Ouroborus)

I did not do much testing in different browsers, but I did not see redrawing and / or recounting, adding the w630> style to <head> , as opposed to adding <iframe> .

I am wondering if someone here knows about a solution that relies on (cross-browser) to handle CSS without getting into the DOM, since I did not find it and finished creating Tokenizer / Lexer to create such a tree).

+6
source

Source: https://habr.com/ru/post/1260046/


All Articles