# Viewport

## Vad det är

En viewport, på svenska ibland kallad visningsområde, är den rektangel som en webbläsare lägger ut
ett dokument i och målar upp det i: på en skärm ytan innanför fönstrets egna verktygsfält, på papper
sidytan på varje ark. CSS mäter mot den hela tiden. Det initiala innehållande blocket, den ruta som
rotelementet läggs ut i, får sin storlek från den, en media query på `width` eller `height` frågar
efter den, och enheterna `vw` och `vh` är hundradelar av den. På en telefon behöver ordet en
bestämning, och specifikationerna har flera att välja på: layout, visuell, liten, stor och dynamisk.

På en dator är viewporten och fönstret nästan samma sak. På en telefon går de isär. Eftersom så
många dokument formgavs för fönster på datorer lägger mobila webbläsare ut en sida som inte ger
några instruktioner i en fast bredd som efterliknar ett datorfönster, enligt specifikationen CSS
Viewport vanligen 980–1 024 CSS-pixlar, och skalar sedan ned resultatet så att det får plats på
glaset. En sida väljer bort det med ett enda element i sitt head, som tar emot `width`, `height`,
tre gränser för skalning, `user-scalable` och `interactive-widget`:

```html
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

Zoom delar viewporten i två. Layoutviewporten är den som CSS lägger ut sidan mot, och nypzoom lämnar
den i fred, så radbrytningarna ligger kvar. Den visuella viewporten är den del av sidan som syns på
glaset i stunden: den krymper när du zoomar in och flyttas när du panorerar. Som standard krymper
ett skärmtangentbord bara den visuella viewporten. Med `interactive-widget=resizes-content` ber
sidan webbläsaren att ändra storlek på layouten också, och med `overlays-content` att inte ändra
någon av dem.

Telefoner har dessutom webbläsarfält som glider undan. Adressfältet tar plats när en sida laddas och
dras in när du scrollar, så den synliga höjden ändras under en sida som inte har rört sig. CSS
Values 4 ger tre storlekar för det här: den stora viewporten utgår från att varje infällbart
verktygsfält är indraget, den lilla från att alla visas, och den dynamiska följer det som faktiskt
gäller. Enheterna bär prefixen, `lvh`, `svh` och `dvh`, med motsvarande bredder, och vanliga `vh`
och `vw` är definierade mot den stora viewporten. Ett gränssnitt som lägger sig över innehållet utan
att flytta det, vanligen skärmtangentbordet, ändrar ingen av de här längderna.

## Varför det spelar roll

Responsiv design vilar på viewporten. Varje brytpunkt i en stilmall är en fråga om dess bredd, så en
sida som saknar `meta`-elementet läggs ut i datorbredd på en telefon och krymps tills texten inte
går att läsa, hur omsorgsfullt dess media queries än är skrivna.

Höjden är den svåra axeln. Bredden ligger still så länge telefonen inte vrids. Höjden ändras när
verktygsfältet glider, när tangentbordet öppnas och när telefonen vänds, så allt som tar skärmens
höjd som mått måste säga vilken höjd det menar. Den lilla viewporten får alltid plats och lämnar en
remsa tom yta när verktygsfälten dras in. Den stora fyller skärmen och lägger innehåll bakom
verktygsfälten medan de visas. Den dynamiska är exakt, och specifikationen varnar själv för att den
kan ändra storlek på innehåll medan du scrollar, vilket flyttar allt nedanför.

Skärmar har också hörn. En telefon med rundade hörn eller ett urtag för kameran är ingen rektangel,
och med standardvärdet `auto` förblir hela sidan synlig på den. Med `viewport-fit=cover` ber sidan
att viewporten ska vara rektangeln runt hela den fysiska skärmen, och tar själv på sig att hålla
texten fri från urtaget med variablerna `env(safe-area-inset-*)`. De värdena måste vara noll på en
rektangulär skärm, så en och samma regel för utfyllnad fungerar för båda sorterna.

Fast positionering hänger också på viewporten. En fast ruta placeras mot layoutviewporten, som CSS
Positioned Layout ger samma storlek som den dynamiska viewporten, så rutor om cookies, bakgrunder
till modala dialoger och menyer i helskärm står still medan sidan scrollar. Var och en utgår från
att ingen förfader har tagit den rollen, och `transform`, `will-change` och `contain` kan göra just
det.

Utskrift är den viewport som en stilmall skriven bara för skärm aldrig möter. På papper mäter
viewportenheterna sidytan, en media query på `width` frågar efter sidrutan, och ett fast element
upprepas på varje sida.

## Så ser det ut i praktiken

Sidorna på den här webbplatsen deklarerar `width=device-width, initial-scale=1, viewport-fit=cover`,
så de läggs ut i telefonens bredd och går ända ut till kanten under en notch. Stilmallen betalar för
den andra halvan: utfyllnaden på sidorna är `max(1rem, env(safe-area-inset-left))` och dess högra
tvilling, så texten håller en rem från kanten och flyttas längre in bara där ett urtag finns. På
låga skärmar i liggande läge höjs golvet till `max(2rem, 7vw, env(safe-area-inset-left))`, eftersom
värdena är noll på en telefon utan urtag och en rem satt för nära kanten.

Sektioner i helskärm tar sin höjd från en gemensam variabel satt till `100dvh`, med `100vh` som
reserv, och kommentaren bredvid förklarar varför: `100vh` kan vara högre än det som syns medan
adressfältet är framme, och det hade låtit nästa sektion titta fram under hero-ytan. Två element
struntar medvetet i variabeln. Märket i sidhuvudet har statiska `vh` som mått, eftersom ett märke
knutet till den dynamiska viewporten skulle ändra storlek när webbläsarens fält gled undan och bryta
om hero-ytan mitt i en scroll. Den fasta bakgrunden på pekskärmar är `100lvh` hög, så den ändrar
aldrig storlek när adressfältet kommer och går, och den ligger på ett eget kompositlager, eftersom
webbläsare på pekskärmar rev sönder den i ljusa och mörka band vid tröghetsscroll.

Varje tjänsteblock på startsidan är minst `100dvh` högt, vilket ger ett block per skärm så länge
innehållet är kortare än skärmen. Vid 852 × 393 pixlar blir ett blocks innehåll 412 pixlar högt, och
blocken stötte ihop. Utfyllnad innanför `100dvh`, genom `box-sizing: border-box`, kostar ingenting
på en hög skärm och öppnar ett mellanrum först när innehållet svämmar över.

Testerna följer media queries.
[Webbplatsens webbläsarstyrda kvalitetsgrind](/sv/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/)
breddade sina kontroller till en gemensam tabell med tjugotvå fönsterformer, hämtade ur varje media
query i stilmallen, och det tog enbart layoutkontrollen från 95 sekunder till 405.

Utskriften blottade skillnaderna mellan motorerna.
[Utskriftsstilmallen](/sv/portfolio/built-a-637-line-print-stylesheet-136/)
dokumenterar att viewportenheter räknas mot sidrutan i en motor och mot fönstret i en annan, så att
en sida som skrevs ut från ett brett fönster förlorade en tredjedel av varje rad i den andra.
Sidhuvudets egen stilmall dokumenterar samma glapp från media queryns sida: utskriften behöll
fönstrets orientering, höjd och bredd, så ark som skrevs ut från ett brett och ett smalt fönster
fick sidhuvuden som skilde sig 47 pixlar åt, tills `screen and` först i frågan begränsade regeln
till fönster.

Fällan med innehållande block finns också dokumenterad.
[Arbetet med reduced-motion](/sv/portfolio/made-reduced-motion-honest-135/)
visade att fem olika egenskaper var för sig gör ett element till innehållande block för allt som är
positionerat mot viewporten, och att det i tysthet hade krympt ett stängningslager till en bråkdel
av skärmen.

## Var det går fel

**Telefonen visar en pytteliten datorsida.** Utan `meta`-elementet för viewporten lägger webbläsaren
ut sidan i datorbredd och skalar ned den, och sidans media queries ser den bredden. Lägg till
`width=device-width, initial-scale=1`, och låt zoomen vara på: `user-scalable=no` tar ifrån läsaren
det egna sättet att förstora liten text.

**En sektion i helskärm sträcker sig förbi skärmens nederkant.** `100vh` är den stora viewporten, så
medan adressfältet är framme hamnar sektionens nederdel, och varje knapp som ligger där, bakom det.
Använd `svh` för ett element som alltid måste få plats, och `dvh` bara där storleksändring mitt i en
scroll är godtagbar.

**Ett överlägg i helskärm krymper till en ruta inne på sidan.** En förfader med `transform`, med
`will-change` som nämner en sådan egenskap eller med containment blir innehållande block för
`position: fixed`, och överlägget tar sin storlek från den förfadern. Rendera överlägg utanför alla
transformerade element.

**En utskriven sida tappar slutet av varje rad.** Viewportenheter och media queries som är skrivna
för fönstret läcker in i utskriften, och en motor som räknar dem mot fönstret lägger ut arket för en
skärm. Håll viewportenheter borta från allt som skrivs ut, och sätt `screen and` först i frågor som
är tänkta för fönster.

## Läs mer

- [CSS Viewport Module Level 1](https://www.w3.org/TR/css-viewport-1/) — `meta`-elementet för
  viewporten och de tre beteendena för `interactive-widget`.
- [CSS Values and Units Level 4: viewport-percentage lengths](https://www.w3.org/TR/css-values-4/#viewport-relative-lengths)
  — de små, stora och dynamiska viewportstorlekarna och varje enhet som bygger på dem.
- [CSS Positioned Layout Level 3](https://www.w3.org/TR/css-position-3/) — fast positionering,
  egenskaperna som fångar den och vad den gör på papper.
- [CSS Environment Variables Level 1](https://www.w3.org/TR/css-env-1/) — safe-area-värdena och
  regeln som gör dem till noll på en rektangulär skärm.
- [Media Queries Level 4](https://www.w3.org/TR/mediaqueries-4/) — `width`, `height` och
  `orientation`, mätta på viewporten på skärm och på sidrutan vid utskrift.

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