user8846537
user8846537

Reputation:

Chrome Extension: Removing all styles using Javascript

I'm admittedly a bit new to this; I know HTML/CSS more then I know Javascript. I know enough to code an extension, but I'm having problems that I believe may be specific to Chrome. I don't want to be too specific, but as part of my extension I'd like to remove styles from all webpages.

Here's what I have:

manifest.json

{
"manifest_version": 2,
    "name": "[redacted]",
    "description": "[redacted]",
    "version": "1.0",
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["script.js"],
                "run_at": "document_start"
        }
    ]
}

script.js

function lolxd() {
    var hs = document.getElementsByTagName('style');
    for (var i=0, max = hs.length; i < max; i++) {
        hs[i].parentNode.removeChild(hs[i]);
}

window.onload = lolxd();

I've tried multiple different scripts, none of which have worked. Strangely the extension loads fine, but the Javascript doesn't work and I can still see styles on all webpages. Any help?

Upvotes: 0

Views: 1240

Answers (3)

Fighter178
Fighter178

Reputation: 413

A simple answer that removes most styles is pretty basic.

document.body.parentElement.innerHTML = document.body.innerHTML; 

This works by kinda placing all HTML inside the head element, so I'll give props to any screen reader that can do any decent job on this new webpage. However, there are two main problems with this method.

  1. As mentioned before, accessibility will be ruined.
  2. The style attribute will still work.

So, To solve both these problems, we might me able to do something like this:

document.querySelectorAll("*").forEach(elem => { //this gets ALL the elements on the page.
  elem.removeAttribute('style') // fix problem 2
  if (elem.nodeName.toLowerCase() === "style") { // if element is a style element, remove it.
    elem.remove()
    return;
  };
  if (elem.nodeName.toLowerCase() === "link" && elem.hasAttribute("href") && elem.hasAttribute("rel")) { // Check if the element is a link, has href and rel attributes 
    if (elem.getAttribute('rel') === "stylesheet") {
      elem.remove();
      return;
    };
  };
});

This, for most practical applications is pretty good, of course, if there were children in the style and/or link elements, it would also remove them, so there may be a way to retain those, and a few other minor things. If your target site is large, and thus has many elements, this could drastically add to the loading time, because it has to loop over every element, and do some (admittedly quite quick) operations to them So, I devised a new solution using the Intersection Observer API. This only executes on elements that are visible to the user, so it should increase performance.

const observer = new IntersectionObserver((entries)=>{
  entries.forEach(entry => {
    entry.target.removeAttribute('style')
  });
}, {
    rootMargin:"1%",
    threshold:0.01
});
document.querySelectorAll("*").forEach(elem=>{
  if (elem.nodeName.toLowerCase() !== "style" && elem.nodeName.toLowerCase !== "link") {
    observer.observe(elem);
  } else {
    if (elem.nodeName.toLowerCase() === "style") {
      elem.remove();
      return;
    };
    if (elem.nodeName.toLowerCase() === "link" && elem.hasAttribute("href") && elem.hasAttribute("rel")) {
      if (elem.getAttribute("rel") === "stylesheet") {
        elem.remove();
        return;
      };
    };
  };
 });

Note: We do not need the root to be supplied, because by default, it is the browser viewport, which is what we want. We only call this function when 1% of the element is visible. We still need to have the style and link elements checked, because they are never shown, so this is not a major performance improvement, but it is there, you do need quite a bit of elements for it to pay off though, otherwise it would be slower.

One interesting thing I noticed, when I tried it on Google, was that the Search mangifer icon is huge, as well as the X, also you can see all of the 'I'm feeling lucky' options. When you hover over your icon, which I took 5 minutes to find, was that it flashes the tooltip, so possibly google is creating elements here, but most likely is that they are setting "style=display:block;" but then the code realizes that it is visible, removing the style attribute. Also tried it on StackOverflow and it does some crazy stuff, absolutely nothing, but the slow version works? I have no idea why, but that's interesting. This could be used for nefarious means, because you could use it to see data that you weren't supposed to, though I think that DevTools and the View Source feature do that better. However with this you don't have to deal with hundreds of lines of HTML,CSS, and JavaScript, its just right there. This does not interfere with the functionality of the page, just makes most look horrible, but I guess that sometimes it could make some look better. Please someone fix the version that uses the Intersection Observer API, because on some sites it works fine, but others, like StackOverflow, not so much.

I also think that this is the best approach because, while all the others (as of current) don't take into account that the link element is not entirely for stylesheets, but that is of course the main use of it. It can be used to render icons, including the favicon. The docs of the link element is here. So, if you did want to remove some icons and possibly the favicon, then just remove the filter for rel=stylesheet and if it has an href.

Upvotes: 1

CodeIt
CodeIt

Reputation: 3618

You can recursively iterate through all elements and remove the style attribute, remove all linked (external) stylesheets and embedded stylesheets.

BEFORE

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="https://www.w3schools.com/html/styles.css">
  <style>
    p {
      font-size: 150%;
    }
  </style>
</head>

<body>

  <h1>This is a heading</h1>
  <p style="font-weight: bold;">This is a paragraph.</p>

</body>

</html>

AFTER

function removeStyles(el) {
  // code to remove inline styles 
  el.removeAttribute('style');

  if (el.childNodes.length > 0) {
    for (var child in el.childNodes) {
      /* filter element nodes only */
      if (el.childNodes[child].nodeType == 1)
        removeStyles(el.childNodes[child]);
    }
  }

  // code to remove embedded style sheets 

  var styletag = document.getElementsByTagName('style');
  var i = 0;
  for (; i < styletag.length; i++) {
    styletag[i].remove();
  }

  // code to remove external stylesheets
  var stylesheets = document.getElementsByTagName('link'),
    sheet;

  for (i = 0; i < stylesheets.length; i++) {
    sheet = stylesheets[i];

    if (sheet.getAttribute('rel').toLowerCase() == 'stylesheet')
      sheet.parentNode.removeChild(sheet);
  }
}

removeStyles(document.body);
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="https://www.w3schools.com/html/styles.css">
  <style>
    p {
      font-size: 150%;
    }
  </style>
</head>

<body>

  <h1>This is a heading</h1>
  <p style="font-weight: bold;">This is a paragraph.</p>

</body>

</html>

Upvotes: 1

danny.hu
danny.hu

Reputation: 110

like this:

function removeCSS() {
    // remove `link`
    var links = document.getElementsByTagName('link');
    for(var i = 0, len = links.length; i < len; i++) {
        links[i].parentNode.removeChild(links[i]);
    }

    // remove `style`
    var styles = document.getElementsByTagName('style');
    for(var j = 0, len = styles.length; j < len; j++) {
        styles[j].parentNode.removeChild(styles[j]);
    }

    // remove inline style
    var nodes = document.querySelectorAll('[style]');
    for(var h = 0, len = nodes.length; h < len; h++) {
        nodes[h].removeAttribute('style');
    }
}

Upvotes: 0

Related Questions