Quando si tratta di eseguire il rendering sul DOM di qualcun altro, non è possibile scrivere in modo ingenuo HTML e CSS come si potrebbe per la propria applicazione web autonoma. Devi riflettere attentamente su come il codice CSS e JavaScript preesistente potrebbe influire sulla tua applicazione.
Prima di iniziare a scrivere qualsiasi HTML o CSS, dovrai prendere una decisione importante riguardo all'aspetto della tua applicazione. Vuoi che la tua applicazione sia uguale ovunque? O vuoi che l'applicazione erediti il look and feel nativo della pagina su cui è ospitato? La tua risposta avrà un profondo impatto sulla tua strategia per il rendering della tua app.
Una cosa è costante: ad un certo livello, praticherete ciò che chiamiamo rendering difensivo. Per difensivo, intendiamo prendere misure per l'output di HTML e CSS che riducano al minimo l'impatto della pagina padre sulla tua applicazione. Meno impatti il tuo widget dalla pagina padre, più passaggi dovrai intraprendere. Questi passaggi possono essere piccoli come il namespace del codice HTML e CSS per ridurre i conflitti di nome o la sovrastimolazione delle regole CSS in modo che abbiano la priorità sulle regole della pagina padre. Per i widget che vogliono l'immunità completa dalla pagina padre, potrebbe anche significare servire il tuo widget su un DOM completamente separato, incorporato in un iframe.
Ci concentreremo sul rendering di HTML e CSS che vivono sullo stesso DOM della pagina del publisher. Per i widget che mirano a offrire un certo livello di personalizzazione, questa può essere la soluzione più flessibile per gli editori, dal momento che l'editore può facilmente indirizzare i tuoi elementi e adattarli alle loro preferenze.
Sfortunatamente, questo è anche il lato negativo. L'editore potrebbe inconsapevolmente avere regole CSS e / o codice JavaScript che mirano inavvertitamente al tuo widget e causano il caos.
Vedremo un certo numero di modi per proteggere HTML e CSS della tua applicazione dal codice del publisher. In primo luogo, imparerai a conoscere gli spazi dei nomi HTML e CSS. Quindi, imparerai a conoscere la specificità CSS e in che modo gli stili della pagina madre possono sovrascrivere i tuoi.
Infine, imparerai le tecniche per ignorare gli stili principali della pagina, superpecificando il tuo CSS e abusando della parola chiave! Important. Innanzitutto, namespace.
Tutti gli ID DOM, le classi, gli attributi data- * e i selettori CSS corrispondenti sono stati preceduti da cicogna-. La proposta? Ridurre la probabilità che tali attributi siano in conflitto con la pagina principale.
Si consideri la seguente situazione. Il tuo widget ha un livello superiore
...
Questo potrebbe essere perfettamente appropriato per una normale applicazione stay-at-home, ma per un'app di terze parti è un no-no completo. La ragione? Un nome di classe generico ha buone possibilità di essere già utilizzato dalla pagina padre. Se si introduce questa regola di stile, è possibile sovrascrivere una regola di stile esistente messa in atto dal publisher e rovinare il layout del proprio sito. Oppure, il rovescio della medaglia, la loro regola potrebbe ignorare la tua e ridimensionare il tuo widget inavvertitamente.
La soluzione? Prefissazione di tutti i nomi delle classi (e altri attributi) con un identificativo univoco per la tua applicazione, uno spazio dei nomi. Nel caso del widget Stork, il markup precedente dovrebbe essere modificato per assomigliare a questo:
...
L'idea è di assegnare uno spazio ai nomi al codice JavaScript in modo da non dichiarare oggetti globali in conflitto con il codice in esecuzione sulla pagina padre. Si estende a ogni pezzo di HTML che inserisci nella pagina: ID, classi, attributi data- *, nomi di moduli e così via.
Namespacing HTML e CSS è un must per qualsiasi applicazione di terze parti che viene visualizzata direttamente nella pagina del publisher. Questo non è solo necessario per prevenire le regole CSS in conflitto; è anche concepibile che la pagina padre abbia JavaScript che sta interrogando il DOM per elementi le cui proprietà identificative potrebbero corrispondere alle tue. Sii rigoroso nel namespace di tutto ciò che inserisci nel DOM.
È importante notare che, sebbene sia utile, il namespace del codice HTML e CSS impedisce solo i casi in cui il publisher utilizza stili o query che fanno riferimento ad attributi con lo stesso nome del tuo. Sfortunatamente, il tuo widget può ancora entrare in conflitto con gli stili definiti dalla pagina padre, anche se i loro CSS utilizzano ID, nomi di classi e attributi che non fanno direttamente riferimento ai tuoi elementi. Questo perché alcune regole CSS sono pesate più pesantemente dal browser e possono avere la precedenza su regole apparentemente non correlate che potreste definire. Questo fenomeno viene definito come specificità CSS e dovrai comprenderlo prima di poter eseguire il rendering in sicurezza degli elementi nella pagina del publisher.
Torniamo all'esempio del contenitore della sezione precedente su namespace. Supponiamo che l'HTML del publisher abbia un DIV di livello superiore che avvolge tutto il loro contenuto, con un ID della pagina:
... ...
Inoltre, supponiamo che la pagina abbia il seguente CSS, in cui la prima regola è definita dall'editore e la seconda regola, targeting per cicogna-contenitore, viene aggiunta dallo script di terze parti:
/* Publisher */#page div {background-color: green;}/* Camera Stork */.stork-container {background-color: blue;}
Ora, di che colore avrà il contenitore di cicogne? La risposta potrebbe scioccare e spaventarti: verde. In questo semplice esempio, la regola del publisher (#pag div) ha la priorità sulla regola della classe dell'applicazione di terze parti (.stork-container). Ciò accade perché il browser pesa le regole contenenti ID più alti di quelli che hanno come target classi o attributi.
La specifica CSS del W3C descrive come i browser intendano dare la priorità a diversi tipi di regole. Ecco un elenco di questi tipi di regole, ordinati dalla priorità più alta alla più bassa:
Secondo questo grafico, gli stili in linea vengono pesati sopra tutti i tipi di regole seguenti: ID, classi ed elementi. Questo continua logicamente verso il basso l'elenco, con ID priorizzato più in alto di classi ed elementi, e così via. C'è una eccezione a questo elenco: le proprietà contrassegnate con la parola chiave! Important hanno la priorità più alta. Nota che la parola chiave! Important ha effetto su una singola proprietà all'interno di una regola, non sull'intera regola.
Cosa succede quando hai più regole CSS dello stesso peso, ognuna delle quali potrebbe influenzare lo stesso elemento? Diamo un'occhiata a un esempio:
Eat your vegetables!
Cosa pensi che sia il colore dello span? La risposta potrebbe essere sorprendente: il giallo. Anche se queste regole sono tutte principalmente basate su classi, la seconda regola (estensione .storkcontainer) è considerata più specifica della prima e la terza regola (.stork-container .stork-msg) è più specifica della seconda. Come funziona?
In termini di specificità CSS, cioè. Se ti ricordi di prima in questo capitolo, abbiamo detto che gli stili in linea hanno il vantaggio di raramente in conflitto con la pagina madre. Ora è chiaro il motivo: hanno la priorità su ogni altro tipo di regola CSS standard (esclusi quelli con la parola chiave! Important). Se stai scrivendo un widget particolarmente semplice, potrebbe non essere una cattiva idea usare gli stili in linea; eviterete la maggior parte dei conflitti di specificità CSS.
Il browser utilizza un semplice sistema di punteggio per determinare quale regola ha la priorità. Per una determinata regola, ciascun selettore che compone quella regola vale un certo valore. Questi valori sono sommati per creare un punteggio di specificità. Quando più regole influenzano lo stesso elemento, il browser confronta il punteggio di specificità di ciascuna regola e la regola con il punteggio più alto ha la priorità. In caso di parità, la regola che è stata definita per ultima vince. Attributi di stile in linea: 1000; ID: 100; classi, pseudo-classi e attributi: 10, elementi e pseudo-elementi: 1.
Quindi, guardando al nostro precedente esempio, a quelle regole CSS sarebbero stati assegnati i seguenti punteggi, con la regola del punteggio più alta che viene data la priorità al browser: Noterai rapidamente che questi non sono numeri ordinari. Un punteggio di specificità è in realtà una tupla della forma (a, b, c, d), con un essere più prezioso di b, b più prezioso di c, e così via. Ciò significa che uno stile causato da un singolo attributo di stile inline (1, 0, 0, 0) ha una specificità più alta di una regola con cento selettori di ID (0, 100, 0, 0).
A questo punto, dovresti avere una buona padronanza su come funzioni la specificità CSS e sul perché il browser dia priorità ad alcune regole rispetto ad altre. In seguito utilizzerai questa conoscenza per esplorare alcuni approcci per la scrittura di CSS che si ergono alti di fronte agli stili dei publisher in conflitto.
Il primo e più semplice approccio alla scrittura di CSS che non sia in conflitto con la pagina del publisher è quello di sovrastimare le tue regole. Ciò significa dichiarare selettori aggiuntivi per aumentare la specificità delle tue regole, in modo tale che quando il browser confronta le tue regole con quelle della pagina padre, è probabile che ottengano punteggi più alti e abbiano la priorità.
Diamo un'occhiata a questo in pratica. Considera questo esempio rivisto del contenitore del widget Stork, ora con due elementi contenitore, ciascuno con un ID univoco:
Mikon E90 Digital SLR
"/> $ 599
4.3 / 5.0 • 176 Recensioni
Il CSS di accompagnamento per questo HTML potrebbe quindi assomigliare a questo:
#stork-main #stork-container { ... }#stork-main #stork-container .stork-product { ... }#stork-main #stork-container .stork-price { ... }
Specificando in modo ridondante entrambi gli ID contenitore come selettori padre di tutte le tue regole CSS, stai effettivamente dando a ciascuna delle tue regole CSS un punteggio di specificità minimo di (0,2,0,0). In seguito, la regola #page generica del publisher precedente non sarà più in conflitto con il tuo widget, poiché utilizza solo un ID singolo. Nessuna delle regole puramente classiche o basate sugli elementi è in conflitto, perché quelle sono una intera classe di peso CSS sotto ID s. Anche se, per scopi di selezione, non è assolutamente necessario specificare un secondo ID per le tue regole, qui funziona come un dispositivo efficace per aumentare la specificità.
Scrivere CSS in eccesso può essere un vero problema: devi sempre riscrivere gli stessi ID ripetutamente per ognuna delle tue regole CSS. È possibile risolvere questo problema utilizzando un preprocessore CSS, che estende il linguaggio CSS con funzionalità aggiuntive come la possibilità di dichiarare gerarchie nidificate di regole. Ad esempio, utilizzando il preprocessore LESS CSS, è possibile scrivere l'esempio precedente in questo modo:
#stork-main {#stork-container {.stork-product { ... }.stork-price { ... }}}
Oggi sono disponibili numerosi e popolari preprocessori CSS, tutti con serie di funzioni diverse. Tra i più popolari sono DI MENO,Sass, e Stilo.
Il rovescio della medaglia, questo esempio richiede che il tuo widget utilizzi i contenitori di livello superiore con ID, il che non sarà pratico per i widget che possono essere visualizzati più volte sulla stessa pagina. Inoltre, non è ancora a prova di proiettile: un editore potrebbe seguire il tuo esempio e sovrastimare le proprie regole CSS, causando lo stesso problema che avevi prima.
Ma questo è uno scenario improbabile, soprattutto perché hai specificato in modo ridondante due ID in ciascuna delle regole. In alternativa potresti usarne uno, ma questo sarà ovviamente più vulnerabile. La realtà è che la maggior parte degli editori utilizza regole CSS sane, e l'overspecifying delle regole come questa sarà compatibile con la maggior parte di esse.
Se prendi in considerazione eccessivamente il tuo CSS in questo modo, potresti trovare un nemico improbabile: strumenti che valutano la qualità del tuo codice CSS, come CSS Lint, Google Page Speed e Yahoo YSlow. Questi strumenti indicheranno che stai facendo selettori CSS ridondanti e ti consiglieranno di rimuovere tali selettori per ridurre le dimensioni dei file e migliorare le prestazioni CSS dei browser. Sfortunatamente, questi strumenti non sono programmati con gli script di terze parti in mente, e non valutano in modo imparziale l'utilità di un eccesso di CSS. I vantaggi dell'eccessiva definizione per le applicazioni di terzi superano le dimensioni extra del file e il minimo impatto sulle prestazioni.
Se ritieni che la sovrascrittura del tuo CSS con ID o selettori di classe extra non sia abbastanza ampia, puoi rompere l'opzione nucleare: la parola chiave! Important. Le proprietà all'interno di una regola CSS che presentano la parola chiave! Important hanno la priorità più alta di tutte, anche sopra gli stili in linea. Questo perché la parola chiave! Important è stata progettata per offrire agli utenti del browser un metodo sicuro per ignorare gli stili "autore" (editore), nel caso di plug-in del browser o stili specifici del sito. Puoi abusare di! Importante usandolo su tutte le tue proprietà CSS, assegnandogli priorità su tutte le altre regole.
Ecco come puoi utilizzare la parola chiave! Important su una singola regola CSS:
.stork-price {font-size: 11px !important;color: #888 !important;text-decoration: none !important;display: block !important;}
Dal momento che è per proprietà, la parola chiave! Important deve essere ripetuta in questo modo, che può diventare un trascinamento su un foglio di stile lungo e complesso. Ma, in cambio, ottieni un solido set di fogli di stile che è molto improbabile che vengano resettati dalla pagina del publisher.
È ancora ipotizzabile che l'editore possa a sua volta utilizzare! È importante indirizzare i tuoi elementi e impostare i propri stili, a quel punto è probabile che mirino miratamente ai tuoi elementi per la personalizzazione. Da un lato, ciò può essere frustrante se si sta tentando di mantenere un aspetto coerente. Tuttavia, se hai deciso di consentire ai publisher di personalizzare il tuo widget, probabilmente questo è il comportamento desiderato.
Una cosa dovrebbe essere chiara: la condivisione del DOM con l'editore può rendere particolarmente difficile il rendering di un widget dallo stile coerente. Sebbene sia possibile adottare misure per iperspecificare le regole CSS per ridurre la probabilità di conflitti, è sempre possibile che l'editore scelga come target i propri elementi con le loro regole, in modo accidentale o intenzionale.
Ma se condividere il DOM con l'editore è ciò che causa così tanto dolore, è possibile rendere il tuo widget fuori dal DOM? Perché, sì, sì puoi.
Per un'applicazione JavaScript di terze parti, l'inserimento di HTML e CSS nella pagina del publisher richiede più attenzione rispetto a quando si aggiungeva il markup a un ambiente "sicuro". È necessario assicurarsi che quando si invia HTML alla pagina, non si sta rallentando la pagina con un'operazione di blocco. Devi anche considerare che il tuo script potrebbe essere incluso più volte nella stessa pagina, e dovrebbe renderizzare più istanze con grazia. Inoltre, dovresti scegliere un metodo ottimale per iniettare i CSS nella pagina del publisher, inserendo tutti i tuoi stili, aggiungendo elementi di collegamento o incorporando le regole CSS nel tuo JavaScript.
Ma ottenere solo HTML e CSS sulla pagina non è sufficiente. Devi riconoscere che gli elementi che introduci nel DOM possono entrare in conflitto con la pagina padre. È inoltre necessario considerare in che modo i tuoi stili potrebbero entrare in conflitto con stili esistenti definiti dal publisher. Puoi usare una serie di tecniche per ridurre l'impatto degli stili genitore sul tuo widget: sovradimensionando le tue regole CSS o presentando il tuo contenuto dietro un iframe, sia che sia un iframe src-less o che contenga un documento HTML esterno.
Quali tecniche usi quando produci CSS e HTML per terze parti? Ti ricolleghi mai! Importante? Fateci sapere nei commenti.
Immagine in primo piano / miniatura, immagine di difesa via Shutterstock.