Als het gaat om weergave op de DOM van iemand anders, kun je niet naïef HTML en CSS schrijven zoals je zou kunnen doen voor je eigen onafhankelijke webapplicatie. U moet goed nadenken over de manier waarop bestaande CSS- en JavaScript-code uw toepassing kunnen beïnvloeden.

Voordat u begint met het schrijven van HTML of CSS, moet u een belangrijke beslissing nemen over het uiterlijk en het gevoel van uw toepassing. Wilt u dat uw toepassing er overal hetzelfde uitziet? Of wilt u dat de toepassing het native uiterlijk en gevoel krijgt van de pagina waarop deze wordt gehost? Uw antwoord heeft een diepgaand effect op uw strategie voor het weergeven van uw app.

Eén ding is constant: op een bepaald niveau oefen je wat we defensieve rendering noemen. Met defensief bedoelen we het nemen van stappen voor het uitvoeren van HTML en CSS die de impact van de bovenliggende pagina op uw toepassing minimaliseren. Hoe minder u wilt dat uw widget wordt beïnvloed door de bovenliggende pagina, des te meer stappen u moet nemen. Deze stappen kunnen zo klein zijn als het toevoegen van namen aan uw HTML en CSS om naamconflicten te verminderen of uw CSS-regels te veel te specificeren, zodat ze voorrang krijgen boven regels op de bovenliggende pagina. Voor widgets die volledige immuniteit van de bovenliggende pagina willen, kan dit ook betekenen dat u uw widget op een volledig afzonderlijke DOM serveert, ingebed in een iframe.

We zullen ons richten op het renderen van HTML en CSS die op dezelfde DOM leven als de pagina van de uitgever. Voor widgets die een bepaald niveau van aanpassing willen bieden, kan dit de meest flexibele oplossing voor uitgevers zijn, omdat de uitgever eenvoudig uw elementen kan targeten en ze naar hun voorkeuren kan stijlen.

Helaas is dit ook het nadeel. De uitgever kan onbewust CSS-regels en / of JavaScript-code gebruiken die onbedoeld uw widget targeten en grote schade aanrichten.

We zullen een aantal manieren bekijken om de HTML en CSS van uw applicatie te beschermen tegen de uitgeverscode. Eerst leer je over HTML- en CSS-naamruimten. Vervolgens leert u meer over CSS-specificiteit en hoe de stijlen van de bovenliggende pagina uw eigen stijlen kunnen overschrijven.

Ten slotte zul je technieken leren om de bovenliggende stijlen van de pagina te negeren, door je CSS teveel te specifiëren en het! Belangrijke sleutelwoord te misbruiken. Ten eerste, naamruimten.

namespaces

Alle DOM ID's, klassen, data- * attributen en bijpassende CSS selectors zijn voorafgegaan door ooievaar-. De bedoeling? Om de kans te verkleinen dat die kenmerken in strijd zijn met de bovenliggende pagina.

Overweeg de volgende situatie. Je widget heeft een topniveau

element dat als een container fungeert. Het doet dit door een expliciete breedte en hoogte in te stellen, waardoor het gebied dat door uw widget is opgenomen effectief wordt begrensd. Je hebt dit gegeven
een eenvoudige klassenaam, container, die overeenkomt met een stijlregel in uw bijbehorende CSS:

...

Dit is misschien perfect geschikt voor een gewone thuis-thuistoepassing, maar voor een app van derden is dit een compleet nee-nee. De reden? Zo'n generieke klassennaam heeft een goede kans om al door de bovenliggende pagina te worden gebruikt. Als u deze stijlregel invoert, kunt u een bestaande stijlregel negeren die door de uitgever is ingesteld en de lay-out van de site ruïneren. Of, aan de andere kant, kan hun regel de uwe overschrijven en de grootte van uw widget onbedoeld wijzigen.

De oplossing? Alle klassennamen (en andere kenmerken) voorvermengen met een unieke ID voor uw toepassing: een naamruimte. In het geval van de Stork-widget moet de vorige markup worden gewijzigd om er als volgt uit te zien:

...

Het idee is dat u uw JavaScript-code een naam geeft, zodat u geen globale objecten declareert die conflicteren met code die op de bovenliggende pagina wordt uitgevoerd. Dit geldt voor elk stukje HTML dat u op de pagina invoegt: ID's, klassen, gegevens- * kenmerken, formuliernamen, enzovoort.

Namespacing HTML en CSS is een must voor elke toepassing van derden die rechtstreeks naar de pagina van de uitgever leidt. Dit is niet alleen nodig om conflicterende CSS-regels te voorkomen; Het is ook denkbaar dat de bovenliggende pagina JavaScript heeft die de DOM bevraagt ​​voor elementen waarvan de identificerende eigenschappen overeenkomen met de uwe. Wees rigoureus in het opnemen van namen voor alles wat u op de DOM plaatst.

CSS-specificiteit

Het is belangrijk om op te merken dat, hoewel nuttig, namespacing van uw HTML en CSS alleen voorkomt dat de uitgever stijlen of query's gebruikt die verwijzen naar attributen met dezelfde naam als de uwe. Helaas kan uw widget nog steeds conflicteren met stijlen die zijn gedefinieerd door de bovenliggende pagina, zelfs als hun CSS ID's, klassenamen en kenmerken gebruikt die niet rechtstreeks naar uw elementen verwijzen. Dit komt omdat sommige CSS-regels zwaarder worden gewogen door de browser en kunnen prevaleren boven ogenschijnlijk niet-gerelateerde regels die u zou kunnen definiëren. Dit fenomeen wordt CSS-specificiteit genoemd en u moet het begrijpen voordat u elementen op de pagina van de uitgever veilig kunt renderen.

Laten we teruggaan naar het containervoorbeeld uit de vorige sectie over naamruimten. Stel dat de HTML van de uitgever een DIV van het hoogste niveau heeft die al zijn inhoud omspant, met een ID van de pagina:

...
...

Laten we daarnaast zeggen dat de pagina de volgende CSS heeft, waarbij de eerste regel wordt gedefinieerd door de uitgever en de tweede regel, gericht op ooievaar-container, wordt toegevoegd door uw script van een derde partij:

/* Publisher */#page div {background-color: green;}/* Camera Stork */.stork-container {background-color: blue;}

Welke kleur heeft .spot-container? Het antwoord kan choqueren en u ontzetten: groen. In dit eenvoudige voorbeeld heeft de uitgeversregel (#page div) voorrang op de klasse-regel van uw derde toepassing (.stork-container). Dit gebeurt omdat de browser regels weegt met ID's die hoger zijn dan die welke zich richten op klassen of attributen.

Prioriteiten voor CSS-regels

De W3C CSS-specificatie geeft aan hoe browsers verschillende soorten regels moeten rangschikken. Hier is een lijst met deze regeltypen, gerangschikt van de hoogste tot de laagste:

  1. Inline stijlen (style = "...")
  2. IDs
  3. Klassen, attributen en pseudo-klassen (: focus,: hover)
  4. Elementen (div, span, enzovoort) en pseudo-elementen (: before,: after)

Volgens dit diagram worden inline stijlen gewogen boven alle volgende soorten regels: ID's, klassen en elementen. Dit gaat logisch verder in de lijst, met ID's met een hogere prioriteit dan klassen en elementen, enzovoort. Er is één uitzondering op deze lijst: eigenschappen die zijn getagd met het belangrijkste woord, hebben de hoogste prioriteit. Merk echter op dat het! Belangrijke trefwoord invloed heeft op een enkele eigenschap binnen een regel, niet op de hele regel.

Wat gebeurt er wanneer u meerdere CSS-regels van hetzelfde gewicht hebt, waarvan elk mogelijk hetzelfde element zou kunnen beïnvloeden? Laten we een voorbeeld bekijken:

Eat your vegetables!

Wat denk je dat de kleur van de overspanning is? Het antwoord is misschien weer verrassend: geel. Hoewel deze regels allemaal primair op klassen zijn gebaseerd, wordt de tweede regel (.storkcontainer span) specifieker dan de eerste regel beschouwd, en de derde regel (.stork-container .stork-msg) specifieker dan de tweede. Hoe werkt dit?

Inline stijlen zijn koning

In termen van CSS-specificiteit, dat wil zeggen. Als je je eerder in dit hoofdstuk herinnert, hebben we vermeld dat inline-stijlen het voordeel hebben van zelden in conflict te komen met de bovenliggende pagina. Nu is het duidelijk waarom: ze hebben voorrang boven elk ander type reguliere CSS-regel (met uitzondering van die met het! Belangrijke sleutelwoord). Als u een bijzonder eenvoudige widget schrijft, is het misschien geen slecht idee om inline stijlen te gebruiken; je zult de meeste CSS-specificiteitsconflicten vermijden.

De browser gebruikt een eenvoudig scoresysteem om te bepalen welke regel voorrang krijgt. Voor een bepaalde regel is elke selector die die regel samenstelt, een bepaalde waarde waard. Deze waarden worden opgeteld om een ​​specificiteitsscore te creëren. Wanneer meerdere regels hetzelfde element beïnvloeden, vergelijkt de browser de specificiteitsscore van elke regel en heeft de regel met de hoogste score voorrang. In het geval van een gelijkspel wint de regel die als laatste werd bepaald. Inline stijleigenschappen: 1000; ID's: 100; klassen, pseudo-klassen en attributen: 10, elementen en pseudo-elementen: 1.

Terugblikkend op ons vorige voorbeeld, zouden aan die CSS-regels de volgende scores zijn toegewezen, waarbij de hoogste score door de browser wordt geprioriteerd: u zult snel merken dat dit geen gewone nummers zijn. Een specificiteitsscore is eigenlijk een tupel van de vorm (a, b, c, d), waarbij een wezen waardevoller is dan b, b waardevoller is dan c, enzovoort. Dat betekent dat een stijl die wordt veroorzaakt door een enkel inline-stijlkenmerk (1, 0, 0, 0) een hogere specificiteit heeft dan een regel met honderd ID-selectors (0, 100, 0, 0).

  • .stork-container (0,0,1,0-een klasse selector)
  • .stork-containeroverspanning (0.0,1,1-een klassenkiezer, een elementselector)
  • .stork-container .stork-msg (0,0,2,0-twee klasse selectors)

Op dit punt moet u goed weten hoe CSS-specificiteit werkt en waarom de browser bepaalde regels voorrang geeft op andere regels. U zult vervolgens deze kennis gebruiken om te gebruiken, terwijl we enkele benaderingen onderzoeken voor het schrijven van CSS die bestand zijn tegen tegenstrijdige stijlen van uitgevers.

Overspecifieke CSS

De eerste en eenvoudigste manier om CSS te schrijven die niet conflicteert met de pagina van de uitgever, is om je regels te veel te specificeren. Dit betekent dat extra selectors worden gedeclareerd om de specificiteit van uw regels te vergroten, zodat wanneer de browser uw regels vergelijkt met die van de bovenliggende pagina, deze waarschijnlijk hoger scoren en prioriteit krijgen.

Laten we dit in de praktijk bekijken. Overweeg dit herziene voorbeeld van de Stork-widgetcontainer, nu met twee containerelementen, elk met een unieke ID:

Mikon E90 Digital SLR

"/>

$ 599

4.3 / 5.0 • 176 Beoordelingen

De bijbehorende CSS voor deze HTML kan er dan als volgt uitzien:

#stork-main #stork-container { ... }#stork-main #stork-container .stork-product { ... }#stork-main #stork-container .stork-price { ... }

Door beide container-ID's redundant op te geven als bovenliggende selectors van al uw CSS-regels, geeft u effectief aan elk van uw CSS-regels een minimale specificiteitsscore van (0,2,0,0). Daarna genereert de generieke #page-regel van de uitgever van eerder niet langer conflict met uw widget, omdat deze slechts één ID gebruikt. Noch zullen enige zuiver op klassen of elementen gebaseerde regels in conflict zijn, omdat die een volledige CSS-gewichtsklasse onder ID's zijn. Hoewel het voor selectiedoeleinden helemaal niet nodig is om een ​​tweede ID voor uw regels op te geven, hier werkt het als een effectief apparaat om de specificiteit te vergroten.

Bewaar uw gezond verstand met een CSS-preprocessor

Het schrijven van niet-gespecificeerde CSS kan een echte sleur zijn: je moet constant dezelfde ID's opnieuw herschrijven voor elk van je CSS-regels. U kunt dit verhelpen door een CSS-preprocessor te gebruiken, die de CSS-taal uitbreidt met extra functies, zoals de mogelijkheid om geneste hiërarchieën van regels te declareren. Als u bijvoorbeeld de prepressor LESS CSS gebruikt, kunt u het vorige voorbeeld als volgt schrijven:

#stork-main {#stork-container {.stork-product { ... }.stork-price { ... }}}

Een aantal populaire CSS-preprocessors zijn vandaag beschikbaar, die allemaal verschillende functiesets hebben. Een van de meest populaire zijn MINDER,Sass, en Stylus.

Aan de andere kant vereist dit voorbeeld dat uw widget containers van het hoogste niveau met ID's gebruikt, wat niet praktisch is voor widgets die meerdere keren op dezelfde pagina kunnen worden gerenderd. Bovendien is het nog steeds niet kogelvrij: een uitgever kan je voorbeeld volgen en zijn eigen CSS-regels overspecificeren, wat resulteert in hetzelfde probleem dat je eerder had.

Maar dit is een onwaarschijnlijk scenario, vooral omdat u in elk van de regels redundant twee ID's hebt opgegeven. Je kunt er ook een gebruiken, maar dit is natuurlijk kwetsbaarder. De realiteit is dat de meeste uitgevers verstandige CSS-regels gebruiken en dat het overdreven specificeren van uw regels als deze compatibel zal zijn met de meeste van hen.

Overspecifieke CSS gaat niet samen met hulpmiddelen voor codekwaliteit

Als je het overmatig specificeren van je CSS op deze manier beschouwt, zou je een onwaarschijnlijke vijand kunnen vinden: tools die de kwaliteit van je CSS-code evalueren, zoals CSS Lint, Google Page Speed ​​en Yooze van Yoo. Deze hulpmiddelen geven aan dat u overbodige CSS-kiezers maakt en zij zullen u adviseren dergelijke selectors te verwijderen om de bestandsgrootte te verkleinen en de CSS-prestaties van browsers te verbeteren. Helaas zijn deze hulpprogramma's niet geprogrammeerd met scripts van derden, en wordt het nut van overaanbevelende CSS niet redelijk geëvalueerd. De voordelen van overspecificatie voor toepassingen van derden wegen op tegen de extra bestandsgrootte en de minuscule prestatiesucces.

Misbruik! Belangrijk

Als u vindt dat het overdreven specificeren van uw CSS met extra ID of class selectors niet ver genoeg gaat, kunt u de nucleaire optie uitbreken: het! Belangrijke trefwoord. Eigenschappen binnen een CSS-regel met het! Belangrijke sleutelwoord krijgen de hoogste prioriteit, zelfs boven inline-stijlen. Dit komt omdat het! Important keyword is ontworpen om browsergebruikers een zekere manier te geven om de "auteur" -stijl (publisher-stijlen) te overschrijven, in het geval van browser-plug-ins of site-specifieke stijlen. U kunt misbruik maken! Belangrijk door het te gebruiken op al uw CSS-eigenschappen, effectief prioriteit te geven boven alle andere regels.

Hier leest u hoe u het! Important keyword op een enkele CSS-regel kunt gebruiken:

.stork-price {font-size: 11px !important;color: #888 !important;text-decoration: none !important;display: block !important;}

Omdat het per eigenschap is, moet het! Belangrijke trefwoord op deze manier worden herhaald, wat een slepen kan worden over een lange en complexe stylesheet. Maar in ruil daarvoor krijgt u een keiharde set stijlbladen waarvan het onwaarschijnlijk is dat ze worden gereset door de pagina van de uitgever.

Het is nog steeds denkbaar dat de uitgever op zijn beurt kan gebruiken! Belangrijk om je elementen te targeten en hun eigen stijlen in te stellen, op welk moment ze je doelgericht opzettelijk richten op maatwerk. Aan de ene kant kan dat frustrerend zijn als je een consistent uiterlijk en gevoel probeert te behouden. Maar als je hebt besloten om uitgevers toe te staan ​​je widget aan te passen, is dit waarschijnlijk het gewenste gedrag.

Eén ding moet duidelijk zijn: het delen van de DOM met de uitgever kan het bijzonder moeilijk maken om een ​​consistent gestileerde widget weer te geven. Hoewel u stappen kunt nemen om uw CSS-regels te specificeren om de kans op conflicten te verkleinen, is het altijd mogelijk voor de uitgever om uw elementen met hun regels te targeten, per ongeluk of opzettelijk.

Maar als het delen van de DOM met de uitgever de oorzaak is van zoveel verdriet, is het dan mogelijk om je widget van de DOM te verwijderen? Waarom, ja - ja dat kan.

Overzicht

Voor een JavaScript-toepassing van derden vereist het injecteren van HTML en CSS op de pagina van de uitgever meer aandacht dan wanneer u markeringen zou toevoegen aan een "veilige" omgeving. U moet ervoor zorgen dat wanneer u HTML naar de pagina uitvoert, u de pagina niet vertraagt ​​met een blokkeerbewerking. U moet ook bedenken dat uw script meerdere keren op dezelfde pagina kan worden opgenomen en dat het meerdere instanties sierlijk moet weergeven. Bovendien moet u een optimale methode kiezen voor het injecteren van CSS in de pagina van de uitgever, door al uw stijlen in te voegen, koppelingselementen toe te voegen of CSS-regels in uw JavaScript in te sluiten.

Maar alleen HTML en CSS op de pagina krijgen is niet voldoende. Je moet erkennen dat elementen die je aan de DOM introduceert, conflicteren met de bovenliggende pagina. U moet ook overwegen hoe uw stijlen kunnen botsen met bestaande stijlen die zijn gedefinieerd door de uitgever. U kunt een aantal technieken gebruiken om de impact van bovenliggende stijlen op uw widget te verminderen: door uw CSS-regels te veel te specificeren of uw inhoud achter een iframe te presenteren, of het nu een iframe is dat geen src is of een dat een extern HTML-document bevat.

Welke technieken gebruikt u bij het produceren van CSS en HTML voor derden? Val je ooit terug, belangrijk? Laat het ons weten in de comments.

Uitgelichte afbeelding / thumbnail, verdediging afbeelding via Shutterstock.