Hoppa till innehåll

Webbläsarens API:er

En PWA ska vara installerbar, pålitlig och kapabel. De två första har du arbetat med i kursvecka 15 och 16. Den här artikeln handlar om den tredje: att webben kan göra sådant som tidigare krävde en installerad app, som att dela via operativsystemet, läsa platsen eller prata med en Bluetooth-enhet.

Ingen förväntar sig att du kan alla dessa API:er utantill. Poängen är att veta att de finns, och att kunna ta ett nytt API i bruk på ett sätt som håller. För högre betyg på B3 ska PWD:et eller någon underapplikation använda minst ett webbläsar-API du inte redan har använt i kursen. Listan nedan är ett bra ställe att börja leta.

Tidsåtgång: Ungefär 15 minuter.

MDN har en lista över alla Web API:er, och den är lång. Innan du bygger på något av dem behöver du svar på tre frågor: finns det, får jag använda det, och vad händer annars?

På MDN:s sida för varje API finns en tabell över webbläsarstöd. Märkningen Baseline betyder att funktionen fungerar i alla de stora webbläsarna, och Limited availability att den inte gör det. Can I use ger samma information. Slå alltid upp det, för läget ändras.

Testa om funktionen finns i stället för att gissa vilken webbläsare det är:

if ('share' in navigator) {
shareButton.hidden = false
}

Ofta kan du erbjuda något enklare i stället. Web Share öppnar operativsystemets delningsmeny, men finns inte i alla webbläsare. Clipboard API finns i alla:

shareButton.addEventListener('click', async () => {
const data = { title: 'Memory', url: location.href }
try {
if ('share' in navigator) {
await navigator.share(data)
} else {
await navigator.clipboard.writeText(data.url)
status.textContent = 'Länken är kopierad.'
}
} catch (error) {
if (error.name !== 'AbortError') {
status.textContent = 'Det gick inte att dela.'
}
}
})

Det här är progressive enhancement: applikationen fungerar överallt, och blir bättre där det går. AbortError betyder här att användaren stängde delningsmenyn, vilket inte är något fel.

Får jag? Secure context, aktivering och behörighet

Section titled “Får jag? Secure context, aktivering och behörighet”

Webbläsaren ger inte vilken sida som helst tillgång till enheten. Det finns tre spärrar.

Secure context. De flesta nyare API:er finns bara på sidor som laddats över HTTPS. localhost räknas också som säkert, så under utvecklingen märks inget. Det kan du kontrollera med window.isSecureContext.

Användaraktivering. En del API:er kräver att användaren nyss har gjort något, till exempel klickat. Så hindras en sida från att öppna en delningsmeny eller gå till helskärm av sig själv. Aktiveringen varar bara en kort stund.

Behörighet. För känsliga uppgifter frågar webbläsaren användaren, och användaren kan säga nej:

locateButton.addEventListener('click', () => {
navigator.geolocation.getCurrentPosition(
(position) => showPosition(position.coords),
(error) => {
status.textContent =
error.code === error.PERMISSION_DENIED
? 'Du har inte gett tillgång till din position.'
: 'Det gick inte att hitta din position.'
},
{ timeout: 10000 }
)
})

Fråga när användaren gör något som behöver svaret, inte när sidan laddas. En fråga utan sammanhang får oftast ett nej, och ett nej är svårt att ändra. Användaren måste då själv gå in i webbläsarens inställningar. Vill du veta läget i förväg, utan att fråga, finns navigator.permissions.query().

Du testar PWD:et på din telefon. Du startar Vite med npm run dev -- --host och öppnar http://192.168.1.20:5173 på telefonen. Delningsknappen ovan fungerar på datorn via localhost. Vad händer på telefonen?

Knappen ger fel, trots att telefonens webbläsare har stöd för både delning och urklipp. Sidan laddas över HTTP från en vanlig IP-adress och är inget secure context, så navigator.share och navigator.clipboard finns inte. Koden tar då else-grenen, och navigator.clipboard.writeText() ger ett TypeError som fångas av catch.

Det är en bra påminnelse om att även det du faller tillbaka på behöver kontrolleras. Service workers och installation kräver också secure context, så för att testa de delarna på en telefon behöver applikationen ligga på HTTPS.

Innan delningen ska länken hämtas från en server som är långsam:

shareButton.addEventListener('click', async () => {
const response = await fetch('/api/share-link')
const { url } = await response.json()
await navigator.share({ url })
})

Ibland fungerar det, ibland inte. Varför?

Aktiveringen från klicket varar bara en kort stund. Tar förfrågan för lång tid har den gått ut när navigator.share() anropas, och promiset blir rejected med ett NotAllowedError.

Hämta det du behöver innan användaren klickar, så att anropet kan göras direkt i lyssnaren. Den här sortens fel är lätt att missa på en snabb utvecklingsmaskin.

Tabellen visar läget i MDN:s kompatibilitetsdata i november 2026. Stödet för Firefox och Safari gäller utan flaggor.

API Gör det möjligt att Stöd
Canvas rita 2D-grafik med JavaScript Alla
WebGL rita hårdvaruaccelererad 3D-grafik Alla
WebGPU använda grafikkortet, efterföljaren till WebGL Chromium, Safari, delvis Firefox
Web Animations styra animationer från JavaScript Alla
Fullscreen visa ett element i helskärm Alla, delvis på iPhone
Geolocation läsa enhetens position Alla
Clipboard läsa från och skriva till urklipp Alla
Gamepad läsa av spelkontroller Alla
Screen Wake Lock hindra skärmen från att släckas Alla
WebRTC skicka ljud, bild och data direkt mellan klienter Alla
MediaRecorder spela in ljud och bild Alla
Web Share öppna operativsystemets delningsmeny Chromium, Safari
Payment Request låta webbläsaren hantera betalningsuppgifter Chromium, Safari
Speech Recognition tolka tal till text Varierar, med prefix i Safari
WebXR bygga AR och VR Chromium
Web Bluetooth prata med Bluetooth-enheter Chromium
WebUSB prata med USB-enheter Chromium
Web NFC läsa och skriva NFC-taggar Chrome på Android
EyeDropper hämta en färg från skärmen Chromium på dator

Mönstret är tydligt. Det som rör grafik och enkel interaktion finns i alla webbläsare. Det som ger direkt tillgång till hårdvara finns i stort sett bara i Chromium, eftersom Mozilla och Apple har valt att inte införa de API:erna, bland annat av integritetsskäl.

Några saker som är lätta att missa:

  • WebRTC behöver ändå en server. Trafiken kan gå direkt mellan klienterna, men de måste först hitta varandra via en server, till exempel över en WebSocket. Ibland går inte en direkt anslutning att skapa, och då skickas trafiken via en server.
  • Gamepad har inga händelser för knappar. Bara gamepadconnected och gamepaddisconnected är händelser. Knapparnas läge läser du av i en loop med navigator.getGamepads() och requestAnimationFrame().
  • Drag and Drop API behövs inte i B3. Att flytta ett fönster är enklare med vanliga mushändelser.

Ett API som finns i dag finns inte nödvändigtvis kvar. Battery Status API visade batterinivån och togs bort ur Firefox, eftersom värdet kunde användas för att känna igen användare mellan webbplatser. Det finns kvar i Chromium, men har aldrig funnits i Safari. Vibration API har tagits bort ur Firefox och har heller aldrig funnits i Safari. Ambient Light Sensor kräver fortfarande en flagga även i Chromium.

Det är ännu ett skäl att bygga så att applikationen fungerar även utan API:et.

<canvas> är en rityta av pixlar. Du ritar med kommandon, och när kommandot har körts finns bara pixlarna kvar, inga objekt att flytta eller lyssna på. Det skiljer den från SVG, där varje form är ett element i DOM:en.

Så här kan antalet försök i de senaste memoryspelen visas som staplar:

/**
* Draws one bar per game.
*
* @param {HTMLCanvasElement} canvas - The canvas to draw on.
* @param {number[]} attempts - The number of attempts in each game.
*/
function drawHistory(canvas, attempts) {
const context = canvas.getContext('2d')
const barWidth = canvas.width / attempts.length
const highest = Math.max(...attempts)
context.clearRect(0, 0, canvas.width, canvas.height)
context.fillStyle = 'rebeccapurple'
attempts.forEach((value, index) => {
const barHeight = (value / highest) * canvas.height
context.fillRect(index * barWidth, canvas.height - barHeight, barWidth - 2, barHeight)
})
}
<canvas width="300" height="150" role="img" aria-label="Antal försök i de senaste spelen"></canvas>

Attributen width och height anger ritytans storlek i pixlar. Storleken i CSS bara skalar resultatet, så sätter du en annan storlek i CSS blir bilden utdragen eller suddig. Eftersom det bara är pixlar kan varken skärmläsare eller tangentbord nå något i bilden. role="img" och aria-label beskriver bilden, och det som går att göra i en canvas behöver också gå att göra med tangentbordet.

För animationer ritar du om i en loop med requestAnimationFrame(). Starta loopen i connectedCallback() och avbryt den med cancelAnimationFrame() i disconnectedCallback().

Listan i B3:s krav är exempel. Tänk igenom några saker innan du väljer:

  • Måste det fungera offline? Canvas, Clipboard och Web Animations gör det. Taligenkänning kan kräva nätverk, beroende på webbläsare. I så fall ska användaren få veta det.
  • Finns det i webbläsaren där du examineras? Ett API som bara finns i Chromium går bra, om du använder feature detection och visar det i en webbläsare som har stöd.
  • Går det att visa? Bygger du på hårdvara som en spelkontroll eller en Bluetooth-enhet, ha den med vid den muntliga examinationen, eller kontakta kursledningen i god tid.
  • Känns det i applikationen? En färgpipett i ett ritprogram är bättre än ett API som läggs till bara för att kravet ska bockas av. Du ska kunna förklara vad det gör och varför det sitter där.
  • Att vara kapabel betyder att en PWA kan göra sådant som tidigare krävde en installerad app.
  • Slå upp stödet på MDN eller Can I use, och använd feature detection i koden.
  • Många API:er kräver secure context, användaraktivering eller behörighet. localhost räknas som säkert, en vanlig IP-adress över HTTP gör det inte.
  • Fråga om behörighet när användaren behöver funktionen, och hantera ett nej.
  • Canvas är pixlar. Rita med kommandon, och tänk på tillgängligheten.
  • API:er kan försvinna. Bygg så att applikationen fungerar även utan dem.
CCBY