Come isolare veramente i fogli di stile nell’estensione di Google Chrome?

Ho scritto l’estensione per google chrome, che apre una finestra di dialogo con il campo di completamento automatico e il suo stile personale, ma ci sono alcuni siti in cui i miei CSS diventano completamente danneggiati che non sembrano molto belli.

So di isolare gli stili con iFrame, ma nell’estensione di Google Chrome non c’è modo di isolare il mio HTML e CSS in questo modo. Un altro metodo è quello di avvolgere tutte le mie cose nel div separato con il proprio id e gli stili relativi per quell’id, e lo faccio, ma sembra non funzionare su alcuni siti con sovraccarico di stile hard tag o direttive “! Important” in il codice CSS.

Quindi voglio sapere c’è un modo per isolare veramente i miei stili in modo conveniente o è il mio cattivo carma sovraccaricare ogni piccola proprietà CSS per correggere uno o un altro bug di stile su ogni sito?

A proposito: ho impostato il mio manifest per caricare tutte le cose nel “document_end”, ma vedo che non si applica ai fogli di stile che vengono caricati ogni volta prima che un DOM sia pronto.

Al momento di porre la domanda, l’unica opzione era utilizzare iframe o fogli di stile con una specificità molto alta e impostare esplicitamente tutte le proprietà che potrebbero influenzare gli stili. L’ultimo metodo è molto macchinoso, perché ci sarà sempre qualche proprietà che viene trascurata da te. Di conseguenza, l’unico metodo utilizzabile per isolare i fogli di stile era usare iframe.

La soluzione a questo problema – isolamento di stili senza iframe – è Shadow DOM ( da Chrome 25 ). Puoi trovare un tutorial su HTML5 Rocks . Per un’estensione di Chrome reale che utilizza Shadow DOM per isolare gli stili, consulta Mostra #Anchors ( codice sorgente qui ).

Come ho recentemente affrontato il guanto di questo problema, voglio condividere alcune informazioni che ritengo sia preziosa.

Innanzitutto, la risposta di Rob W è corretta. Shadow DOM è la soluzione corretta a questo problema. Tuttavia, nel mio caso non solo avevo bisogno dell’isolamento CSS, avevo anche bisogno di eventi JavaScript. Ad esempio, cosa succede se l’utente fa clic su un pulsante che risiede nell’HTML isolato? Questo diventa davvero brutto solo con Shadow DOM, ma abbiamo un’altra tecnologia Web Components, Custom Elements, in soccorso. Tranne che al momento in cui scrivo c’è un bug in chrome che impedisce l’elemento personalizzato nelle estensioni di Chrome. Vedi le mie domande qui e qui e il bug qui .

Allora, dove ci lascia? Credo che la soluzione migliore oggi sia l’IFrames, che è quello con cui sono andato. L’articolo shahalpk collegato è ottimo ma descrive solo parte del processo. Ecco come l’ho fatto:

Innanzitutto, crea un file html e un file js per il tuo widget isolato. Tutto all’interno di questi file verrà eseguito in un ambiente isolato in un iframe. Assicurati di cercare il tuo file js dal file html.

 //iframe.js var button = document.querySelector('.my-button'); button.addEventListener('click', function() { // do useful things }); //iframe.html    

Quindi, all’interno dello script di contenuto, crea un elemento iframe in javascript. Devi farlo in javascript perché devi usare chrome.extension.getURL per prendere il tuo file html iframe:

 var iframe = document.createElement('iframe'); iframe.src = chrome.extension.getURL("iframe.html"); document.body.appendChild(iframe); 

E questo è tutto.

Una cosa da tenere a mente: se è necessario comunicare tra l’iframe e il resto dello script di contenuto, è necessario chrome.runtime.sendMessage () alla pagina di sfondo, quindi chrome.tabs.sendMessage dalla pagina di sfondo indietro alla scheda Non possono comunicare direttamente.

EDIT: Ho scritto un post sul blog che descrive in dettaglio tutto ciò che ho appreso durante il mio processo, tra cui un esempio di estensione chrome completo e molti link a informazioni diverse:

https://anderspitman.net/blog/chrome-extension-content-script-stylesheet-isolation/

Nel caso in cui il mio blog cada, ecco le fonti del post originale:

Post sul blog

Fonte di esempio

O usare all

 .some-selector { all: initial; } .some-selector * { all: unset; } 

oppure usa Shadow DOM

Biblioteca

 function Widget(nodeName, appendTo){ this.outer = document.createElement(nodeName || 'DIV'); this.outer.className = 'extension-widget-' + chrome.runtime.id; this.inner = this.outer.createShadowRoot(); (appendTo || document.body).appendChild(this.outer); } Widget.prototype.show = function(){ this.outer.style.display = 'block'; return this; }; Widget.prototype.hide = function(){ this.outer.style.display = 'none'; return this; }; 

uso

 var myWidget = new Widget(); myWidget.inner.innerHTML = '

myWidget

';

È ansible accedere ai contenuti del widget tramite myWidget.inner e l’esterno tramite myWidget.outer .

stili

 /* * Reset Widget Wrapper Element */ [email protected]@extension_id__ { background: none; border: none; bottom: auto; box-shadow: none; color: black; cursor: auto; display: inline; float: none; font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-size: inherit; font-style: normal; font-variant: normal; font-weight: normal; height: auto; left: auto; letter-spacing: 0; line-height: 100%; margin: 0; max-height: none; max-width: none; min-height: 0; min-width: 0; opacity: 1; padding: 0; position: static; right: auto; text-align: left; text-decoration: none; text-indent: 0; text-shadow: none; text-transform: none; top: auto; vertical-align: baseline; white-space: normal; width: auto; z-index: 2147483648; } /* * Add your own styles here * but always prefix them with: * * [email protected]@extension_id__ * */ [email protected]@extension_id__{ position: fixed; top: 100px; margin: 0 auto; left: 0; right: 0; width: 500px; } [email protected]@extension_id__::shadow h1 { display: block; margin: 0 auto; padding: 20px; background-color: yellow; border: 10px solid green; font-size: 20px; text-align: center; } 

Ho recentemente creato Boundary, una libreria CSS + JS per risolvere problemi come questo. Boundary crea elementi completamente separati dal CSS della pagina web esistente.

Ad esempio, crea una finestra di dialogo. Dopo aver installato Boundary, puoi farlo nel tuo script di contenuto

 var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName"); Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css"); Boundary.appendToBox( "#yourDialogID", "" ); Boundary.find("#submit_button").click(function() { // some js after button is clicked. }); 

Gli elementi all’interno di #yourDialogID non saranno interessati dalla pagina Web esistente. La funzione find () restituisce un normale elemento jQuery DOM in modo che tu possa fare tutto ciò che vuoi con esso.

Spero che questo ti aiuti. Per favore fatemi sapere se avete qualche domanda.

https://github.com/liviavinci/Boundary

Usa iframe. È una soluzione, ma funziona bene.

Maxime ha scritto un articolo su di esso .