What CSS techniques do you need to build a responsive website?

iPhone & 100vh: Kampen om Højden på iOS

17/03/2023

Rating: 4.38 (10759 votes)

Er du webudvikler og har du nogensinde revet håret ud i frustration, fordi dit CSS-layout, der ser perfekt ud på desktop og Android-telefoner, pludselig opfører sig mærkeligt på en iPhone? Specifikt, når du bruger height: 100vh; og pludselig står med en uønsket scrollbar, eller elementer der ikke passer ind på skærmen? Du er langt fra den eneste. Dette er et klassisk problem, der plager mange, og det skyldes en fundamental forskel i, hvordan mobile browsere – især Safari og Chrome på iOS – fortolker 'viewport-højden'.

How to get the inner height of a viewport in JavaScript?
Now let’s get the inner height of the viewport in JavaScript: We told JavaScript to grab the height of the viewport and then drilled it down into 1/100th of that total so we have a value to assign as our viewport height unit value. Then we politely asked JS to create the CSS variable (--vh) at the :root.

Lad os dykke ned i, hvorfor dette sker, og vigtigst af alt, hvordan du kan løse det. Det handler ikke om, at HTML og CSS ikke virker på iPhone – det gør det absolut. Problemet ligger i definitionen af 'viewport height' (vh) i et mobilt miljø, hvor browserens brugerflade (som adressebaren og navigationsbaren) dynamisk ændrer størrelse eller forsvinder, når brugeren scroller.

Indholdsfortegnelse

Forståelse af Problemet: Hvad er 'vh' på Mobil?

CSS-enheden vh står for 'viewport height' og er defineret som 1% af viewportens højde. Så 100vh burde ideelt set fylde hele den synlige skærmhøjde. På desktop-browsere fungerer dette stort set som forventet. Men på mobile enheder, især iOS, bliver det kompliceret. Den mobile browser har en dynamisk brugerflade, der inkluderer adressebaren øverst og eventuelt en navigationsbar nederst. Disse barer kan forsvinde eller ændre størrelse, når brugeren scroller.

Traditionelt har vh været beregnet baseret på den aktuelle viewport, inklusive disse dynamiske elementer. Hvis du begyndte at scrolle, og adressebaren forsvandt, ville vh-værdien pludselig ændre sig, hvilket resulterede i et 'spring' i indholdet. For at undgå denne ubehagelige brugeroplevelse valgte Safari på iOS (og senere Chrome) at definere en fast værdi for vh. Denne faste værdi er baseret på skærmens maksimale højde, altså når browserens brugerflade er minimeret eller helt ude af syne. Selvom dette forhindrer spring, betyder det også, at når adressebaren er synlig, er den faktiske synlige højde af viewporten mindre end den faste 100vh-værdi. Resultatet? Dit element, der er sat til height: 100vh;, kan strække sig ud over den synlige skærm og forårsage en scrollbar eller at indhold bliver beskåret nederst.

Dine observationer bekræfter problemet

Den situation, du beskriver med din div class="whatever", er et perfekt eksempel på dette. Den fungerer på desktop Safari, Brave, og andre mobile browsere, men ikke på iPhone Safari eller Chrome. Dette skyldes præcis den faste vh-implementering på iOS. Elementet forsøger at være 100% af den maksimale skærmhøjde, selv når adressebaren optager plads, hvilket skaber en overskydende højde og dermed en scrollbar. Problemet med din 'sign-up-banner' og 'eind section', hvor 'nothing fits' og 'heights don't properly work on iOS', er også direkte relateret til denne adfærd.

Løsninger på '100vh'-problemet på iOS

Heldigvis findes der flere strategier til at omgå dette problem. Vi vil gennemgå tre primære løsninger, der hver har deres fordele og ulemper.

How to use 100% DOM in CSS?
1. Use 100% instead of 100vh - “DOM tree nightmare” Now the quickest, and most CSS way is to use 100% in your page for the whole DOM tree till your target element: This will work correctly on both mobile and desktop websites.

1. Brug height: 100% i Hele DOM-træet

Den mest "rene CSS"-løsning er at bruge height: 100% i stedet for 100vh. Forskellen er, at 100% refererer til den umiddelbare forælders højde, hvorimod vh refererer til viewporten. For at denne løsning skal virke, skal alle forældre-elementer i DOM-træet, op til og med <html> og <body>, også have en defineret højde på 100%.

html, body { height: 100%; margin: 0; padding: 0; } .whatever { background-color: salmon; height: 100%; width: 100%; }

Fordele:

  • Ren CSS-løsning.
  • Virker konsistent på tværs af platforme, inklusive iOS.

Ulemper:

  • Kræver, at du propagerer height: 100%; gennem hele DOM-træet op til det ønskede element. Dette kan blive en "DOM tree nightmare", især hvis dit element er dybt indlejret.
  • Mindre fleksibel, hvis du ønsker, at et element skal fylde *præcis* den synlige viewport, uanset forældrenes højde.

2. Brug JavaScript med window.innerHeight

En anden tilgang er at bruge JavaScript til at hente den faktiske synlige højde af viewporten via window.innerHeight. Denne værdi tager højde for browserens brugerflade og er altid den aktuelle synlige højde.

// JavaScript const setHeight = () => { const element = document.querySelector('.whatever'); element.style.height = `${window.innerHeight}px`; }; // Kald funktionen ved indlæsning og ved resize window.addEventListener('load', setHeight); window.addEventListener('resize', setHeight);

Fordele:

  • window.innerHeight giver altid den præcise synlige højde på tværs af alle enheder, inklusive mobil.
  • Løser problemet direkte for det specifikke element.

Ulemper:

  • Kræver JavaScript for hvert element, du ønsker at style på denne måde. Dette kan føre til gentagen kode og en mindre "CSS-native" tilgang.
  • Kan forårsage en let "jump" eller gentegning, når brugeren scroller og adressebaren forsvinder, da højden opdateres dynamisk.

3. Den Fleksible Løsning: CSS Custom Properties (Variabler) med JavaScript

Dette er ofte betragtet som den "bedste af begge verdener"-løsning, da den kombinerer JavaScripts præcision med CSS's fleksibilitet. Ideen er at bruge JavaScript til at beregne den korrekte viewport-højde og gemme den i en CSS-variabel (også kendt som custom property). Denne variabel kan derefter bruges i dit CSS, præcis som du ville bruge vh.

Trin 1: Sæt CSS-variablen med JavaScript

Først skal du definere en CSS-variabel, f.eks. --vh, på rod-elementet af dit dokument (:root eller <html>) baseret på window.innerHeight. Du skal også sørge for, at denne variabel opdateres, når vinduet ændrer størrelse (f.eks. ved rotation af enhed).

// JavaScript for at sætte og opdatere --vh variablen const setVhVariable = () => { let vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`); }; // Sæt variablen ved indlæsning setVhVariable(); // Opdater variablen ved resize-event (f.eks. ved rotation eller scroll) window.addEventListener('resize', setVhVariable); // Anbefalet: Debounce resize event for bedre performance (se nedenfor)

Her beregner vi 1vh-ækvivalenten (window.innerHeight * 0.01) og gemmer den som --vh i pixels. Dette gør den tilgængelig i hele din CSS.

Trin 2: Brug CSS-variablen i din CSS

Nu kan du bruge --vh-variablen i dit CSS ved hjælp af calc()-funktionen, hvilket simulerer vh-enheden, men med den korrekte højde.

How to fix 100vh in iOS?
PostCSS plugin to fix iOS’s bug with 100vh. It works in Chrome (just -webkit-fill-available causes problems in Chrome in some cases), iOS/iPad/MacOS Safari and all other browsers. Pure CSS solution, no JS required. /* Footer will be hidden on iOS Safari because of bottom panel */ height: 100vh; height: 100vh;
.whatever { background-color: salmon; /* Fallback for browsere, der ikke understøtter CSS Custom Properties */ height: 100vh; /* Brug vores korrigerede --vh variabel */ height: calc(var(--vh, 1vh) * 100); width: 100%; } /* Eksempler på brug: */ /* 100vh */ .full-screen { height: calc(var(--vh, 1vh) * 100); } /* 50vh */ .half-screen { height: calc(var(--vh, 1vh) * 50); }

var(--vh, 1vh) giver en fallback til standard 1vh, hvis browseren ikke understøtter CSS-variabler, hvilket er en god praksis, selvom understøttelsen er bred i dag.

Vigtig note om resize-event:
Opdatering af --vh-værdien ved hver resize-event kan potentielt udløse mange repaints af siden, hvilket kan forårsage små "hop" i indholdet. For at undgå dette, især når en bruger scroller eller drejer enheden, kan det være en god idé at debounceresize-eventet. Debouncing begrænser, hvor ofte funktionen kaldes, så den kun udføres, når resizing er færdig (eller efter en kort pause).

// JavaScript med debounce for bedre performance const debounce = (func, delay) => { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), delay); }; }; const setVhVariableDebounced = debounce(() => { let vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`); }, 100); // 100ms forsinkelse // Sæt variablen ved indlæsning setVhVariableDebounced(); // Opdater variablen ved resize-event window.addEventListener('resize', setVhVariableDebounced);

Fordele ved CSS Custom Properties-løsningen:

  • Giver den mest nøjagtige synlige højde på tværs af alle enheder.
  • Kombinerer JavaScripts præcision med CSS's deklarative natur, hvilket gør det nemt at genbruge.
  • Løser problemets kerne: inkonsekvent vh-beregning på mobile enheder.

Ulemper:

  • Kræver JavaScript.
  • Potentielle for repaints/jumps ved resize, selvom debouncing kan minimere dette.
  • Kræver understøttelse af CSS Custom Properties (som er bred i moderne browsere).

En Yderligere iOS-specifik Løsning: -webkit-fill-available

En nyere og enklere løsning, der specifikt retter sig mod WebKit-baserede browsere (som Safari på iOS), er at bruge min-height: -webkit-fill-available;. Denne egenskab er en WebKit-specifik værdi, der instruerer elementet i at fylde den tilgængelige plads.

.whatever { background-color: salmon; height: 100vh; /* Fallback for andre browsere */ min-height: -webkit-fill-available; /* Specifik løsning for WebKit/iOS */ width: 100%; }

Denne løsning kan være en god progressiv forbedring, da den er ren CSS og løser problemet for iOS-enheder, mens 100vh stadig fungerer som fallback for andre browsere. Den er dog ikke en standard CSS-egenskab og bør bruges med omtanke.

Valg af den Rette Løsning til Dit Projekt

Hvilken løsning du skal vælge afhænger af dit specifikke projekt og dine krav:

  • Hvis du søger en ren CSS-løsning og dit layout tillader, at alle forældre-elementer har height: 100%, er metode 1 den enkleste.
  • Hvis du har brug for præcis kontrol over den synlige højde og er komfortabel med JavaScript, er metode 2 eller 3 ideel. Metode 3 med CSS-variabler er ofte at foretrække for genanvendelighed og renere CSS.
  • Hvis dit primære mål er at løse problemet på iOS Safari/Chrome med minimal indsats, kan -webkit-fill-available være en hurtig og effektiv løsning, især som en progressiv forbedring.

Det er vigtigt at teste din implementering grundigt på tværs af forskellige iOS-enheder og versioner for at sikre, at den fungerer som forventet under alle forhold (stående/liggende tilstand, scroll med adressebar synlig/usynlig).

How to apply 100vh on iPhone?
The fix is very simple. For the elements where you need to apply 100vh, just match the element height with the device height using media queries that targets the older versions of iPhone and iPad resolution.

Ofte Stillede Spørgsmål

Hvorfor opfører 100vh sig anderledes på iPhone end på Android eller desktop?

Det skyldes primært iOS Safaris (og Chromes) implementering af vh-enheden. For at forhindre irriterende indholdsspring, når browserens adressebar forsvinder ved scroll, beregner iOS 100vh ud fra skærmens maksimale højde (når browserens UI er minimeret). Dette betyder, at når adressebaren er synlig, er den faktiske synlige viewport mindre end den beregnede 100vh, hvilket fører til overskydende højde og scrollbars.

Er der en ren CSS-løsning, der virker på alle browsere?

Den mest "rene CSS"-løsning er at bruge height: 100%. Men for at dette skal virke korrekt for et element dybt i DOM-træet, skal alle dets forældre-elementer op til <html> og <body> også have en defineret højde (typisk height: 100%). Dette kan være besværligt for komplekse layouts.

Skal jeg bruge JavaScript for at løse dette problem på iOS?

Ofte ja, for at opnå den mest præcise og dynamisk tilpassede højde. JavaScript, især i kombination med CSS Custom Properties, giver dig mulighed for at beregne den faktiske synlige viewport-højde (window.innerHeight) og anvende den direkte i din CSS, hvilket løser inkonsekvenserne med vh på mobile enheder.

Hvad er -webkit-fill-available, og hvornår skal jeg bruge det?

-webkit-fill-available er en WebKit-specifik CSS-værdi, der instruerer et element til at fylde den tilgængelige plads inden for sin forælder. Den er særligt nyttig på iOS Safari til at få elementer til at fylde den korrekte højde, selv når adressebaren er synlig. Det er en god, enkel løsning for WebKit-baserede browsere, men det er ikke en standard og bør bruges som en progressiv forbedring sammen med en fallback som 100vh.

Kan dette problem påvirke andre CSS-egenskaber end højde?

Primært er det højde-relaterede problemer, der opstår med vh-enheden. Bredde (vw) er generelt mere konsistent, da browserens lodrette rullepanel sjældent påvirker den vandrette viewport på samme måde som mobile UI-elementer påvirker den lodrette. Dog kan lignende udfordringer opstå med dvh, lvh og svh enheder, som er designet til at adressere netop disse dynamiske viewport-problemer, men deres understøttelse er stadig under udvikling.

Konklusion

Problemet med 100vh på iOS er en velkendt udfordring i mobil webudvikling, der stammer fra browsernes forsøg på at skabe en flydende brugeroplevelse på trods af dynamiske brugerflader. Ved at forstå, hvordan iOS Safari og Chrome fortolker vh, kan du vælge den mest passende løsning for dit projekt. Uanset om du foretrækker en ren CSS-tilgang, en JavaScript-drevet løsning med CSS-variabler, eller den WebKit-specifikke -webkit-fill-available, er der veje til at sikre, at dit design ser lige så fejlfrit ud på iPhone, som det gør alle andre steder. Husk altid at teste grundigt på de enheder, du sigter efter, for at garantere en optimal brugeroplevelse. Din frustration kan nu forvandles til en veldesignet, responsiv hjemmeside!

Hvis du vil læse andre artikler, der ligner iPhone & 100vh: Kampen om Højden på iOS, kan du besøge kategorien Teknologi.

Go up