Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to specify inject target in GM_addStyle to style Shadow DOM on CSP sites #1714

Closed
AlttiRi opened this issue Feb 21, 2023 · 3 comments
Closed

Comments

@AlttiRi
Copy link

AlttiRi commented Feb 21, 2023

I want to use Shadow DOM in order to isolate my userscript's popup from the page's CSS, and the page from my popup's CSS.
Also it will hide the popup's HTML from body.textContent, for example.

It's easy to do for usual sites.

However, on sites with enabled CSP I need to use GM_addStyle to add styles. But it (TM/VM) adds the styles into the head element.
So, it's impossible to style Shadow DOM on these sites (for example, https://mastodon.social/home).

I want to be able to specify the place where to inject the style element.

Like this:

GM_addStyle(cssText, shadowWrapper.shadowRoot);

Script

// ==UserScript==
// @name         Shadow DOM Style
// @namespace    gh.alttiri
// @version      0.2
// @description  Adds Shadow DOM
// @match        https://mastodon.social/*
// @grant        GM_addStyle
// ==/UserScript==


let shadowWrapper = document.createElement("div");
document.querySelector("body").append(shadowWrapper); // "html"
shadowWrapper.setAttribute("id", "ujs-outer-shadow-wrapper");
shadowWrapper.attachShadow({mode: "open"});
shadowWrapper.shadowRoot.innerHTML = `
<div id="shadow-content-wrapper">
  <h1>Shadow header</h1>
  <div>Shadow content</div>
  <div>
    <span>1</span>
    <span>2</span>
    <span>3</span>
  </div>
  <!-- Inline styles will not work on CSP sites. -->
  <style>h1 + div:after { content: " (on non CSP-site)"; color: green; }</style>
</div>`;
shadowWrapper.shadowRoot.querySelector("h1").onclick = () => console.log("clicked");

let cssText = `
#shadow-content-wrapper { position: fixed; padding: 24px; margin: 12px; font-weight: bold; background-color: white; border-radius: 8px; }
h1  { color: darkorange; }
div { color: red; }
`;
function addCSS(css, target = document.head) {
    const styleElem = document.createElement("style");
    styleElem.textContent = css;
    target.append(styleElem);
    return styleElem;
}

// 1.
addCSS(cssText, shadowWrapper.shadowRoot); // Works fine, but only on sites without CSP

// 2.
// It works on sites with CSP, but I need to inject CSS into the shadow DOM element, not into "head" tag.
// GM_addStyle(cssText);

// 3.
// I want something like this
// GM_addStyle(cssText, shadowWrapper.shadowRoot);

(Note: I updated the example code to make it more common.)

@double-beep
Copy link

double-beep commented Feb 21, 2023

This should be possible via GM_addElement(), no?

@AlttiRi
Copy link
Author

AlttiRi commented Feb 21, 2023

Yeah, it works.

I just found #881 (comment) now.

Works fine in TM and VM.

GM_addElement(shadowWrapper.shadowRoot, "style", {textContent: cssText});

@AlttiRi AlttiRi closed this as completed Feb 21, 2023
@7nik
Copy link

7nik commented Feb 21, 2023

There is another way, which is even more preferable when you add multiple shadows due to re-using already parsed styles

const css = `#href-taker-shadow {color: red;}`;
const sheet = new CSSStyleSheet();
// you may use replace() method as well, but I had a flickering issue in FF with it
sheet.replaceSync(css);
wrapper.shadowRoot.adoptedStyleSheets = [sheet];

Though Safari still didn't implement adoptedStyleSheets, maybe it will be in version 17.
https://caniuse.com/mdn-api_document_adoptedstylesheets

Here is our actual usage of this approach with fallbacks https://github.com/evazion/translate-pixiv-tags/blob/master/translate-pixiv-tags.user.js#L920-L941

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants