Vårstäda din webbplats

När våren kommer passar många på att storstäda hemma. Vi delar med oss av några tips på hur du kan ge din webbplats kodbas en vårstädning genom att gno bort gammal JavaScript-kod och ersätta den med putsade, moderna standardlösningar.

När Tim Berns Lee uppfann Internet var huvudsyftet att dela vetenskapliga dokument. Många år senare utvecklades JavaScript, vilket ledde till större möjligheter att göra webbplatser dynamiska. Under en lång tid var JavaScript den dominerande tekniken för att skapa avancerade gränssnitt på webben. Genom projekt som Open UI och Interop har många av de funktioner som utvecklare i regel skapar med JavaScript kunnat standardiseras så att de istället kan lösas med HTML och CSS. 

Det finns fall där JavaScript behöver användas men sträva efter att använda det minst kraftfulla verktyget för att utföra en uppgift: HTML i första hand, därefter CSS och JavaScript i sista hand.

Fördelen med att använda standardlösningar är: enklare utveckling, mer robusta lösningar, bättre prestanda samt mindre risk för buggar och tillgänglighetsproblem.

Här följer ett antal exempel på funktioner som helt eller delvis kan ersättas med standardfunktioner.

Expanderbart innehåll

Kärt barn har många namn: Dragspelsmeny, expanderbar panel, collapse, discolosure. Att kunna visa och dölja innehåll kan ha stora fördelar. Framför allt kan det underlätta för användare som navigerar med tangentbord då det blir enklare att navigera om det går att fälla ihop innehåll som inte är intressant.

Expanderbart innehåll kan i dag till stor del lösas med HTML:s Details-element. Genom att använda detta standardelement skapas en utfällbar sektion som fälls ut när användaren trycker på elementets ”rubriktext”, som skapas med Summary-elementet. Detta utan en enda rad JavaScript-kod. Dessutom får vi alla nödvändiga tillgänglighetsfunktioner på köpet: Det fungerar med tangentbordsnavigation, existerande fokusmarkering, roll och tillstånd som kan förmedlas av hjälpmedel. En skärmläsare kan förklara för användare som inte ser gränssnittet att innehållet går att fälla ut samt om det är utfällt eller ej för tillfället.

En ytterligare fördel är att det går att söka i det hopfällda innehållet med webbläsarens sökfunktion och innehållet fälls då ut.

Exempel på Details

<details>
  <summary>Produktbeskrivning</summary>
  <p>Beskrivning av produkten…</p>
</details>

Presentationen kan enkelt ändras med CSS och details kan då t.ex användas för att skapa en dropdown-meny eller en utfällbar navigationsmeny. Obs! En sådan dropdown ska inte användas för utfällbara listor i formulär. Där bör istället Select eller Data-list användas.

Details bör endast användas när innehållet som fälls ut kommer direkt efter det som fäller ut. Om innehållet fälls ut på en annan plats är det förmodligen Dialog eller popover som ska användas.

För att skapa en dragspelsmeny, där endast ett innehåll är utfällt åt gången, anges ett name-attributdetails-elementet. Alla details-element som har samma värde är då sammankopplade och så fort ett details-element fälls ut kommer andra innehåll med samma värde att fällas ihop.

Exempel på dragspelsmeny

<details name="questions">
  <summary>Frågor om frakt</summary>
  <p>...</p>
</details>
<details name="questions">
  <summary>Frågor om retur</summary>
  <p>...</p>
</details>

Se fler exempel i vår demo på CodePen.

Webbläsarstöd

Details-elementet har haft stöd i alla webbläsare i många år. Om webbläsaren mot förmodan inte skulle ha stöd för Details så kommer innehållet att visas som utfällt eftersom webbläsaren inte känner till vad den ska göra med ett details-element. Användaren kan alltså ta del av innehållet, men det går inte att fälla ihop.

Dialogfönster

Dialogfönster är ett lika kärt som problematiskt designmönster. Under internetboomen på nittitalet var det populärt att öppna nya fönster automatiskt när en webbsida laddades. Detta var så störande för användare att webbläsartillverkarna tog bort denna möjlighet. Användare måste idag godkänna att webbsidor får öppna nya fönster. Som svar på detta började utvecklare i stället att visa ett HTML-element utformat som en dialogruta på webbsidan, ovanför innehållet. Ett standard-element för att visa dialogrutor föreslogs redan kring 2009 men det var först 10 år senare som standarden var klar och webbläsarstödet var tillräckligt bra. Därmed finns det idag säkert tusentals olika JavaScript-lösningar för att visa dialogrutor. Det är väldigt vanligt att sådana lösningar inte fungerar med tangentbordsnavigation eller hjälpmedel som skärmläsare.

Genom att använda HTML dialog-elementet slipper du ladda in onödig JavaScript-kod och undviker att skapa tillgänglighetsbrister.

Exemepel på HTML dialog

<button command="show-modal" commandfor="my-dialog">Öppna dialogruta</button>

<dialog id="my-dialog">
  <p>Innehåll för dialogruta.</p>
  <button commandfor="my-dialog" command="close">Stäng</button>
</dialog>

En nyhet som kom så sent som förra året är att det numera går att öppna och stänga dialoger med endast HTML genom command- och command-for-attributen.

Se fler exempel på Dialog i vår CodePen-demo

Webbläsarstöd

Dialog-elementet har haft stöd i alla webbläsare i många år och är markerat som Baseline Widely available. Var försiktig med command-attributen då de är relativt nya och är markerade som Baseline Newly available. Dessa bör användas i kombination med ett polyfill.

Mjuk scrollning

Mjuk scrollning innebär att en webbsida animeras stegvis till ett innehåll. Som standard hoppar webbläsare direkt till ett innehåll som länkas. 
Detta var under en lång tid endast möjligt med genom att använda JavaScript. Numera går det enkelt att åstadkomma med CSS. Det blir därmed också enkelt att respektera användarens inställningar för animationer med prefers-reduced-motion.

Exempel på mjuk scrollning som respekterar användarens inställningar

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

Ett vanligt problem är att innehåll som scrollas till hamnar högst upp på skärmen precis, kant i kant med skärmens överdel. Detta kan göra att det blir svårare för användaren att uppfatta. Därför brukar det vara önskvärt att lägga in ett litet avstånd mellan kanten och innehållet. Även detta går idag att åstadkomma med endast CSS genom att använda scroll-margin-top eller scroll-margin-block-start. Det löser också ett annat vanligt problem; att innehållet hamnar bakom en eventuell ”sticky meny”.

h2:target {
  scroll-margin-top: 1rem;
}

Se en demo av mjuk scrollning i vår CodePen-demo

Webbläsarstöd

Samtliga webbläsare har haft stöd för scroll-behaviour och scroll-margin i många år och de är markerade som Baseline Widely available. Om webbläsare mot förmodan inte har stöd för mjuk scrollning är det enda som händer att webbläsaren hoppar direkt till innehållet.

Formulärvalidering

Formulärvalidering är ytterligare en uppgift som JavaScript använts till. Även om informationen som skickas alltid ska kontrolleras när den tas emot av en server så är det en god idé att validera informationen i webbläsaren innan användaren kan skicka formuläret och ge användaren tydliga instruktioner om hur de ska rätta till felaktig information.

Detta går till stor del att göra med endast HTML och CSS och det går att rensa bort större delen av JavaScript-koden som hanterar validering.

HTML har särskilda typer av formulärfält för vanliga informationstyper som e-postadress, tal eller telefonnummer. Om det inte räcker finns även ett pattern-attribut där ett reguljärt uttryck kan anges: ett mönster som informationen måste matcha för att vara giltig. Detta räcker oftast för de vanligaste fallen som exempelvis validering av postnummer eller registreringsnummer. 

Genom att använda CSS valid, invalid, user-valid och user-invalid-pseudoselektorer går det att visa och dölja texter eller ändra färg på formulärfält beroende på om värdet är giltigt eller ej. Skillnaden mellan dessa är att valid och invalid appliceras direkt om ett obligatoriskt fält är tomt innan användaren har interagerat med formuläret. Vanligtvis är detta inte önskvärt. User-attributens regler appliceras endast om användaren har interagerat med formuläret.

Exempel på validering av svenskt fordonsregistreringsnummer

<form>
  <label for="registration">
    Registreringsnummer (obligatoriskt)
  </label>
  <input type="text" id="registration" name="registration" 
    aria-describedby="registration-error-message" 
    pattern="[a-zA-ZåäöÅÄÖ]{3}(\d{3}|\d{2}[a-zA-ZåäöÅÄÖ])" 
    required>
  <span id="registration-error-message" class="error-message">
    Vänligen ange ett giltigt svenskt registreringsnummer. Tre bokstäver följt av tre siffror eller två siffror och en bokstav.
  </span>
</form>

<style>
.error-message {
  display: none;
  color: red;
}

input:user-valid {
  border-color: green;
}

input: user-invalid {
  border-color: red;
}

input: user-invalid+.error-message {
  display: block;
}
</style>

JavaScript kan fortfarande krävas för mer avancerad validering som kräver beräkningar samt för att hantera fokusordning och statusmeddelanden.

Demo av formulärvalidering på CodePen

Webbläsarstöd

Validering av formulärfält har haft fullt stöd i alla webbläsare i över 10 år. Även CSS valid och invalid har haft stöd i alla webbläsare i många år. User-valid och User-invalid är relativt nya och är markerade som Baseline Newly awailable.

Autofocus

Det är väldigt vanligt att JavaScript används för att flytta fokus till ett HTML-element när en sida laddas eller när en dialogruta öppnas. Ibland kan det vara nödvändigt, men förmodligen glömmer många att det går att använda HTMLs autofocus-attribut.

Exempelvis på autofocus för sökfält

<label for="site-search">Sök på webbplatsen</label>
<input type="search" id="site-search" autofocus”>

Autofocus är inte begränsat till endast formulärfält utan kan användas på alla HTML-element. Om elementet inte är fokuserbart (saknar ett tabindex) så måste också tabindex anges.

Autofocus kan anvädas i dialog-element för att bestämma vilket element som ska få fokus när en dialogruta öppnas.

<dialog>
  <label for="name">Namn</label>
  <input type="text" id="name" autofocus>
</dialog>

Exempel på autofocus i vår CodePen-demo

Webbläsarstöd

Autofocus har haft stöd i alla webbläsare i många år och är markerat som Baseline Widely available.

Lazy loading

Lazy loading innebär att innehåll laddas in fördröjt, vanligtvis när användaren behöver innehållet. Exempelvis om en bild ligger långt ner på en sida laddas bilden först när användaren scrollat ner på sidan. Detta leder till att mindre data behöver skickas när en webbsida laddas. Webbsidan laddar snabbare och mindre resurser används.

Bilder, iframes, ljud och video kan idag laddas in fördröjt med HTMLs loading-attribut. Trots detta är det väldigt vanligt att stöta på webbsidor som använder JavaScript för detta.

Så här enkelt är det att ladda in bilder med fördröjning.

<img loading="lazy" src="cat.gif" alt="" />

En annan fördel är att detta också gör att dolda bilder inte laddas in förrän de visas. Det är lätt att tro att webbläsare inte kommer ladda in bilder för img-element som döljs med CSS display: none, men bilden laddas faktiskt in även fast den inte syns. I kombination med loading="lazy" laddas bilden inte förrän bilden blir synlig.

Webbläsarstöd

Loading-attributet har haft stöd i alla webbläsare sedan 2022 och är markerat som Baseline Widely available.

Animera till auto-höjd eller bredd

Att animera ett HTML-elements storlek har länge varit möjligt med CSS-animationer, så länge storleken på elementet är känd. Men om innehållets bredd eller höjd inte är känd eller varierar har det tidigare inte varit möjligt att exempelvis animera en utfällbar sektion från dold till utfälld. Det är lätt att tro att det fungerar att ange height: 0 och sedan animera till height: auto men detta har inte fungerat eftersom CSS endast tillåtit animeringar med exakta värden. Lösningen har då ofta varit att använda JavaScript för att animera.

Nu går det att animera ett elements storlek utifrån innehållets storlek genom att använda CSS-egenskapen interpolate-size: allow-keywords. Detta instruerar webbläsaren att det ska vara tillåtet att animera nyckelord, inte bara värden. Webbläsaren kan nu animera med värden som auto eller max-content.

Exempel på Details-element med animering

:root {
  interpolate-size: allow-keywords;
}

::details-content {
  transition: height .25s ease-in-out;
  height: 0;
  overflow: clip;
}
    
[open]::details-content {
  height: auto;
}

Se exempel på animering av details-element på CodePen

Varför måste interpolate-size anges? Vore det inte bättre att använda detta som standard? Det handlar om bakåtkompabilitet. Att införa en förändring som denna skulle kunna förstöra existerande webbsidor. 

Webbläsarstöd

Interpolate-size fungerar idag bara i Chromium-webbläsare som Chrome, Vivaldi och Edge och har därmed Baseline Limited availability. Det går dock i regel bra att använda redan idag. Effekten för webbläsare som inte stöder funktionen är att innehållet inte animeras stegvis.

Publicerad: