11

I am developing a web page capturer and find that some stylesheet rules of a web page captured from Reddit.com are lost.

After a further investigation I found that the source HTML code of a Reddit.com page has a style element like this:

<style type="text/css" data-styled-components="..." data-styled-components-is-local="true">...</style>

When JavaScript has been on, the style element is processed by the script and be emptied:

<style type="text/css" data-styled-components="" data-styled-components-is-local="true"></style>

And that's why my capturer failed to get the stylesheets.

When the content of a style element is changed by script, the document stylesheet of the page would normally change accordingly and the page would be re-rendered to reflect the change.

However, for the Reddit.com page, after the style element is emptied, its stylesheet rules can still be accessed via document.styleSheets[1].cssRules, while document.styleSheets[1].ownerNode.textContent is "".

Additionally, if I modify the style element by running a script like document.styleSheets[1].ownerNode.textContent = "/*null*/", document.styleSheets[1].cssRules becomes empty and the web page is re-rendered, just like what my capturer has got.

I am confused by the bizarre behavior. I'd like to know why and how the Reddit.com page keep the styles after emptying the style element. Any information is appreciated.

Danny Lin
  • 2,050
  • 1
  • 20
  • 34
  • _"However, for the Reddit.com page, after the style element is emptied, its stylesheet rules can still be accessed via `document.styleSheets[1].cssRules`"_ If you are able to get the CSS rules what is the issue? – guest271314 Feb 24 '19 at 10:23
  • 2
    1. My capturer rely on raw stylesheet text rather than document.styleSheets, which is not accessible for a stylesheet file from another origin due to SOP. 2. This question is not only for the issue of my capturer, but also the reason why such inconsistency of style element content and the actual document stylesheet can exist. – Danny Lin Feb 24 '19 at 10:32
  • What is a "raw stylesheet"? Am not certain what the issue is. How can the result be reproduced? Have you asked the authors of the site why the code performs in the manner that you have described? – guest271314 Feb 24 '19 at 10:36
  • Row stylesheet text is the text content of a style element or the retrieved file text of an external or imported stylesheet. You can open a page in Reddit.com, such as *https://www.reddit.com/* and run `document.styleSheets[1].cssRules` and `document.styleSheets[1].ownerNode.textContent` from the console to see whether this issue exists. – Danny Lin Feb 25 '19 at 06:51
  • Still not following what the issue is. `document.styleSheets[1].cssRules` lists the rules of the `styleSheet`, `document.styleSheets[1].ownerNode.outerHTML` is `""`, `document.styleSheets[1].ownerNode.sheet` references the `styleSheet`. Are you expecting for no `cssRules` to exist because no CSS text exists in the ` – guest271314 Feb 25 '19 at 06:56
  • _"the reason why such inconsistency of style element content and the actual document stylesheet can exist."_ The description of the result at the question is not exclusive to *eddit, or any other HTML `document`. There is no inconsistency. The rules of a `sheet` associated with a ` – guest271314 Feb 25 '19 at 07:38

2 Answers2

3

CSS rules of a <style> element sheet can be inserted, added or modified programmatically, where the .textContent of the <style> element returns an empty string "" if CSS text is not set at or appended to the <style> element.

<!DOCTYPE html>
<html>
  <head>
    <style id="style"></style>
  </head>
  <body>
    <div>abc</div>
    <p>123</p>
    <script>
      const style = document.querySelector("#style");
      const {sheet} = style;
      sheet.insertRule("div{color:blue}", 0);
      sheet.addRule("p", "color:green", 1);
      console.log(style.textContent);
      style.textContent = "";
      console.assert(style.textContent.length > 0, [style.textContent]); // assertion failed
      console.log(style.textContent === ""); // true
    </script>
  </body>

</html>

See also Modify element :before CSS rules programmatically in React

guest271314
  • 1
  • 15
  • 104
  • 177
  • Thank you . I did not know changing style via script with `insertRule` alike does not correapond to DOM change, which differs from changing element styles with `.style.<...>`. – Danny Lin Feb 26 '19 at 00:36
  • It is interesting that the css is reconstructed per rule in `styleElement.sheet.cssRules[0].cssText`, but it is not concatenated into `styleElement.textContent`. This api is very misleading, as `el.textContent = el.textContent;` will actually remove all the styles. – Tamas Hegedus Sep 18 '19 at 14:51
0

Also check out Modify a stylesheet rule with CSSOM example from the MDN:

<html>
<head>
<title>Modifying a stylesheet rule with CSSOM</title>
<style type="text/css">
  body {
   background-color: red;
  }
</style>
<script type="text/javascript">
  var stylesheet = document.styleSheets[0];
  stylesheet.cssRules[0].style.backgroundColor="blue";
</script>
</head>
<body>
The stylesheet declaration for the body's background color is modified via JavaScript.
</body>
</html>
Mechanic
  • 5,015
  • 4
  • 15
  • 38