# Stilmall

## Vad det är

En stilmall, på engelska style sheet eller stylesheet och i dagligt tal ofta
bara CSS-filen, är en samling CSS-regler som en webbläsare hämtar, tolkar och
tillämpar på ett dokument som en enda enhet. I bestämd form heter den
stilmallen, och i plural stilmallar.

En sida kan få sina stilmallar på fyra sätt. Ett `link`-element med
`rel="stylesheet"` pekar på en separat fil. Ett `style`-element bär regler inuti
själva HTML-koden. En `@import`-regel överst i en stilmall drar in en annan. Och
ett skript kan bygga en med `new CSSStyleSheet()` och koppla den till ett
dokument eller en shadow root genom `adoptedStyleSheets`. De två första ser ut
så här i sidans `head`:

```html
<link rel="stylesheet" href="/css/site.css" />
<link rel="stylesheet" href="/css/print.css" media="print" />
<style>
    .banner {
        border-block-end: 2px solid;
    }
</style>
```

Författarens stilmallar är inte de enda som spelar in. Varje webbläsare har med
sig en standardstilmall, och det är därför en rubrik utan egen stil ändå blir
stor och fet, och en läsare kan lägga till en egen användarstilmall. Kaskaden
väger de tre ursprungen mot varandra. Attributet `style` på ett enskilt element
är något annat: deklarationer utan selektor, som hör till just det elementet och
inte till någon stilmall.

När en stilmall har laddats blir den ett `CSSStyleSheet`-objekt i CSS Object
Model (CSSOM), den specifikation som definitionen av termen här kommer från.
Objektet håller reda på elementet som äger stilmallen, vilka medier den gäller
för, dess titel, om den är avstängd och dess lista med regler, och
`document.styleSheets` räknar upp en sidas stilmallar i ordning. En flagga finns
för integritetens skull: en stilmall som hämtats från ett annat ursprung utan
CORS är inte origin-clean, och ett skript som frågar efter dess regler får i
stället ett säkerhetsfel.

Attributet `media` begränsar en stilmall till en viss miljö. En stilmall märkt
`media="print"` laddas fortfarande ned, men webbläsaren väntar bara på
stilmallar vars medium matchar, så en stilmall för utskrift håller inte upp
visningen på skärmen.

## Varför det spelar roll

En stilmall avgör vad en webbläsare måste hämta innan den visar något alls.
HTML-standarden behandlar en länk till en stilmall som parsern hittar som
renderingsblockerande när dess medium matchar, så den första utritningen väntar
tills filen har kommit fram och tolkats, i stället för att rita sidan utan stil
och sedan rita om den framför läsaren. Filens storlek, servern den ligger på och
de rundresor som krävs för att upptäcka den ligger alla mellan ett klick och det
första som läsaren ser.

Antalet filer är det första beslutet. Ett gemensamt paket för alla sidor hämtas
en gång och serveras sedan från cachen. En stilmall per sida skickar mindre i
början och mer allteftersom läsaren rör sig på webbplatsen. Regler som bäddats
in i ett `style`-element kostar ingen extra förfrågan, men de följer med på nytt
med varje sida, eftersom de inte kan cachas skilt från dokumentet som bär dem.
Varje `@import` lägger till en hel rundresa, eftersom webbläsaren får veta den
importerade adressen först när den importerande filen har kommit fram.

Cachning är det andra. En stilmall som cachas i ett år gör varje senare sida
snabbare, men en ändring måste då nå läsare som har den gamla kopian. Det
vanliga svaret är ett filnamn med fingeravtryck, en hash av innehållet i själva
namnet, så att en ändrad fil får en ny adress och en gammal kan ligga kvar i
cachen hur länge som helst, medan HTML-koden som pekar på den hålls kortlivad.

Förtroende är det tredje. En stilmall avgör vad som syns och var. Den kan dölja
en varning, ge en knapp ett nytt utseende eller begära bilder från vilken adress
som helst som dess regler nämner. Att ladda en från en tredje part lämnar över
den makten till tredje parten, tillsammans med en server som sidan inte kan
visas utan. Subresource Integrity låter sidan ange en kryptografisk hash för
filen, och webbläsaren vägrar använda en fil vars innehåll skiljer sig.

## Så ser det ut i praktiken

Webbplatsens eget paket med stilmallar visar hur långt en enda inbäddad resurs
kan tippa balansen. På 87 KB var det, för en dokumentwebbplats utan ramverk,
större delen av en sidas vikt, förbrukad innan något innehåll kommit fram, och
två tredjedelar av den största stilmallen visade sig vara ett enda base64-kodat
typsnitt: ungefär 56 KB text som kodade ungefär 42 KB typsnitt. Det hade bäddats
in för en fördel vid den första utritningen som en förladdad extern fil ändå
får, och varje sida betalade för det oavsett om vikten behövdes eller inte. När
det togs bort minskade den filen från 84 KB till 28 och
[hela paketet från 87 KB till 31 KB](/sv/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/),
och typsnittsvikterna förladdas i stället. Base64 skriver varje grupp om tre
byte som fyra tecken, så en binär fil som bäddas in i en stilmall väger alltid
ungefär en tredjedel mer än samma fil levererad för sig.

Papper är också ett medium som en stilmall måste betjäna. Webbplatsens
fallstudier är det som någon skriver ut och tar med sig till ett möte, så
[en stilmall på 637 rader](/sv/portfolio/built-a-637-line-print-stylesheet-136/)
med en enda sidregel och ett utskriftsblock gör att de går att skriva ut på
okänt papper i båda färgtemana. Sidregeln anger en marginal och avsiktligt ingen
pappersstorlek, och en radlängd på ungefär sjuttiotvå tecken hindrar ett
liggande ark från att få rader på ungefär hundratio tecken. Fyra beteenden hos
webbläsarmotorer är nedskrivna som fällor, och vart och ett har orsakat ett
verkligt fel: längder i viewport-enheter, som en motor löser upp mot sidrutan
och en annan mot fönstret, vilket skar bort en tredjedel av varje rad; element
med fast position som ritas ut på varje ark; en palett med vit text som standard
för det mörka temat, som skrev ut fyra avsnittsetiketter vitt på vitt; och en
flex- eller grid-ruta som paginerade medier inte kan dela, vilket gav ett tomt
första ark. En kontroll i sex delar täcker sex kombinationer av papper och
orientering, båda inställningarna för färgschema och det verkliga sidantalet,
och det var den kontrollen som märkte när en vilsekommen kommentarsavslutning
fick CSS-lintern att svälja en hel regel och passera utan anmärkning två gånger.

Webbplatsens [säkerhetssida](/sv/security/) tar upp Subresource Integrity på
stilmallen: paketet får ett fingeravtryck och en hash när webbplatsen byggs, så
att läsarens webbläsare kan kontrollera att det kom fram oförändrat. Samma sida
ber läsaren räkna värdarna i webbläsarens nätverkspanel och ger svaret: en,
webbplatsens egen.

## Var det går fel

En stilmall som webbläsaren får veta om sent kommer också fram sent. En länk i
slutet av `body`, en stilmall som ett skript lägger in eller en kedja av
`@import`-regler låter var och en sidan ritas ut innan stilarna har kommit, så
att rå text hoppar in i en layout, eller en färdig layout flyttar sig. En kedja
av importer ser harmlös ut i källkoden:

```css
/* site.css: webbläsaren hittar base.css först när den här filen har kommit */
@import url("base.css");
@import url("theme.css");
```

Lägg länkarna till stilmallar i `head` och platta ut importerna till paketet när
webbplatsen byggs.

En driftsättning kan para ihop ny märkning med gamla regler. Läsare vars cache
har den förra stilmallen får HTML som förväntar sig klasser som den gamla filen
aldrig har hört talas om, och deras layout går sönder tills cachen löper ut,
medan den som testar med en tom cache ser en fungerande webbplats. Orsaken är
ett namn på stilmallen som aldrig ändras i kombination med en lång livslängd i
cachen, och ett filnamn med fingeravtryck tar bort den.

En stilmall som levereras med fel innehållstyp ignoreras. HTML-standarden
tillämpar en länkad stilmall bara när den kommer fram som `text/css`, med ett
undantag för en fil från samma ursprung på en sida i quirks-läge. En server som
märker `.css`-filer som `text/plain`, eller som svarar på en fil som saknas med
en HTML-sida och en statuskod för lyckad förfrågan, lämnar sidan utan stil medan
nätverkspanelen visar en förfrågan som verkar ha fungerat. Kontrollera huvudet
`Content-Type` på den driftsatta filen.

En integritetshash slutar stämma när filen ändras efter att hashen räknades
fram: en handredigering på servern, ett CDN som minifierar filen på vägen, eller
ett bygge som räknar fram hashen före sin sista omskrivning. Webbläsaren
behandlar avvikelsen som ett nätverksfel och visar sidan utan stilmallen. Från
ett annat ursprung kräver integritetskontrollen också CORS: ett
`crossorigin`-attribut på länken och ett matchande huvud från servern. Räkna
fram hashen i det steg som skriver den slutliga filen.

En stilmall för ett ramverk på ett publikt CDN motiverades förr med att läsarna
redan hade den i cachen från andra webbplatser. Fetch-standarden delar upp
HTTP-cachen efter webbplatsen på översta nivån, så varje webbplats egen kopia
hämtas och lagras för sig, och det som återstår är en extra server på den
kritiska vägen, under någon annans kontroll. Att leverera filen från
webbplatsens egen server kostar lika många byte utan den extra anslutningen.

## Läs mer

- [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/#css-style-sheet)
  — vad en stilmall är inuti webbläsaren, och gränssnittet som skript använder
  för att läsa och ändra den.
- [HTML Standard: Links](https://html.spec.whatwg.org/multipage/links.html)
  — länktypen `stylesheet`, regeln om innehållstyp och när en stilmall blockerar
  renderingen.
- [Subresource Integrity](https://www.w3.org/TR/SRI/)
  — attributet `integrity` och vad webbläsaren gör med en fil som inte klarar
  kontrollen.
- [Fetch Standard: HTTP cache partitions](https://fetch.spec.whatwg.org/#http-cache-partitions)
  — hur cachen delas upp efter webbplatsen på översta nivån.
- [CSS Paged Media Module Level 3](https://www.w3.org/TR/css-page-3/)
  — regeln `@page` och de sidmarginaler som en stilmall för utskrift arbetar
  med.
- [Media Queries Level 5](https://www.w3.org/TR/mediaqueries-5/)
  — utskrift, skärm, inställningar för färgschema och de andra villkor som ett
  `media`-attribut kan testa.

<https://engineer.company/sv/glossary/stylesheet/>
