Sajtbygget
Hur sajten har skapats
Sidan handlar i stort sett om hur jag arbetat med 3 områden: design, tillgänglighet och optimering.
För den som undrar så består den s.k. "tech-stacken" av Next.js - skriven i TypeScript och SCSS.
Hoppas du finner nåt som är intressant för dig.
/Jakob
Design
För att pusha mina kunskaper i styling valde jag tidigt att bryta med den mer traditionella, fyrkantiga layouten.
Därför har bl.a. text puttats utanför dess “container”, gradienter lagts ovanpå bilder och vågiga SVG-element placerats över kanter.
Designen kanske bara är världens näst snyggaste, men till mitt försvar - jag är ingen designer.
Färg
Jag ville ha en färgprofil med rena, matchande och naturliga färger. Därför sökte jag efter bilder med bra färgpaletter på unsplash.com som har en stor bildbank man kan använda sig av.
Jag fastnade för den här ljusa bilden och extraherade sedan fram ett färgtema med hjälp av Adobe Color.
Kontraster
För att uppfylla WCAG:s direktiv om tillgänglighet på webben, skall färger minst ha en kontrastratio på 3:1, men den generella rekommendationen är minst 4.5:1.
Därför kontrollerade jag att huvudfärgerna uppfyllde detta, vilket de gör med råge.
Mer om stylingen
Tillgänglighet
Tillgänglighetsanpassning är ett omfattande arbete och jag har haft det i åtanke när jag byggt sajten.
Med det sagt så finns det ännu en del anpassningar att göra, nedan är ett axplock av det jag har gjort.
Semantik
Alla HTML-element (förutom <div> och <span>) har en semantisk betydelse, vilket innebär att de berättar vad för betydelse i sammanhanget dess innehåll har. Det är viktigt att skriva semantisk korrekt HTML, delvis för personer som förlitar sig på skärmläsare, men också för SEO:n då sökmotorers indexering utgår ifrån den semantiska uppmärkningen.
Jag har sett till att alla sidor har en <header>, <main> och <footer> eftersom de elementen beskriver basstrukturen på sidan.
Rubriknivåer
Varje sida har ett h1-element (högsta rubriknivån) sedan ligger följande rubriker i hierarkisk ordning, som baseras på om rubriken är en underrubrik till ett annat stycke eller bör vara en ny rubrik. Man hoppar aldrig över en nivå, d.v.s. går från h1 till h3. Bilden illustrerar hur rubrikhierarkin bör märkas upp för en sida.
I övrigt har allt innehåll en adekvat HTML-tagg, d.v.s. en <p>- innehåller löptext, <img> innehåller en bild o.s.v.
Markup för hamburgaren
Eftersom vissa användare förlitar sig helt på skärmläsare är det viktigt att knappar som styr flikar och dolda element har kopplad markup. Ett sådant exempel är “hamburgaren” - knappen som öppnar menyn i mobilläge. I koden för knappen, framgår det i aria-controls vilket element som triggas. Knappen styr elementet med id=”menu”. Markupen anger också om knappen är aktiverad eller ej via aria-expanded, som sätts huruvida statevariabeln openNav är true eller false. Elementet med id=”menu” är också gömd för skärmläsaren, så länge värdet aria-hidden är true. Elementet bör vara gömt eftersom användaren inte skall höra/få tillgång till menyalternativen när menyn inte är öppnad.
Sr-only
En annan viktig detalj är klassen “sr-only”, vars CSS visuellt döljer innehållet, men skärmläsaren kommer fortfarande läsa upp det. Eftersom hamburgerknappen inte anger vad som sker när man klickar på den, måste dess roll förtydligas med en sr-only-text - “Öppna meny”/”Stäng meny”.
En ikon ger bara en mening för den som kan se den, därför måste ikonens betydelse alltid finnas med i text, för att vara tillgänglig för alla.
Optimering
Core Web Vitals är ett kvalitetsinitiativ från Google som mäter hur väl en sajt presterar utifrån olika parametrar.
Fr.o.m. mitten av juni 2021 kommer CWV-värdet vägas in i sajtens SEO-ranking.
Därför är det extra viktigt att sajten har bra prestanda.
Hur jag arbetat med optimering
Jag har arbetat med sajtens prestanda genomgående under projektet och har kontinuerligt gjort mätningar i Lighthouse för att se hur koden påverkar resultatvärdena.
Lighthoue är ett inbyggt verktyg i Chrome som ger poäng i hur bra CWV-värdet är. Dock är mätresultatet bara giltigt när granskningen gjorts i incognito-läge då browsertilläggen inte påverkar.
Bildkomponenten
Förutom att jag komprimerat bilderna, så har jag även utformat Image, till att ta en array med source-värden för att kunna byta bild beroende på användarenhetens skärmstorlek. Dessutom skickas bildens orginalmått in med width och height, vilket gör att browsern kalkylerar ut bildstorleken som förhindrar CLS (cumulative layout shift - att sidan hoppar under laddning) vilket är ett av CWV-värdena. Dessutom laddas bilden “lazy”, d.v.s. när användaren scrollar till bilden. Alla dessa optimeringar påverkar Lighthouseresultatet.
Onödiga uppdateringar
I React-DevTool ser man hur ofta komponenten uppdateras genom “blinkningar”. Komponenten "Tablist" och alla dess barn uppdateras varje gång man klickar på någon Tab-knapp vilket är onödigt.
Anledningen till detta är att varje klick orsakar en state-ändring högt upp i komponentträdet.
Före
Det här kan man lösa genom att använda React.memo, som gör en shallow copy på propsen och uppdaterar därmed bara när props-värdena inte är dem samma som de förra. Dessutom nyttjar jag hookarna useCallback och useMemo som cachar funktioner och funktionsreturer.
Efter optimeringen har de onödiga blinkningarna försvunnit, och renderingstiden i profiler (React DevTools) har gått ner från ett genomsnitt på 2,03 ms till 1,28 ms, vilket är 37% snabbare.
Just denna optimering har dock ingen inverkan på sajtens Lighthouseresultat.
Efter
Dynamiska importer
Dynamic import är ett intressant koncept som finns inbyggt i Next.js och liknar React.lazy. Funktionaliteten möjliggör "chunkning" av javascriptet och inladdning av komponenten om och när sajten behöver den.
Jag har laborerat en hel del med dynamiska importer och märkt en skillnad på hur mycket js som sidan “sajtbygget” kräver.
Före
Det är primärt komponenter som har tyngre tredjepartsbibliotek som ger en positiv effekt av att importeras dynamiskt. Sajtbyggets js-laddning har minskat med 46,2% efter optimeringen.
Däremot ger inte flera mindre chunkar alltid bäst effekt, eftersom kompileringen och exekveringen kan ta längre tid om en chunk använder sig av en annan chunk.
Efter
Webpack bundle analyzer
För att få inblick i vad chunkarna innehåller används analysverktyget Webpack bundle analyzer.
Det ger en visuell representation över innehållet och dess storlek i förhållande till andra paket, bibliotek, komponenter och annat.
Före
Tack vare WBA förstod jag att det inte är smart att bygga in stöd för komponenter med tunga dependancies i wrapperkomponenter, även när de inte används och importeras dynamiskt.
Efter en refaktorering av dessa komponenter ser man att "react-syntax-highlighter" (gulgrön) och "Carousel"-komponenten (grön) har egna bundles. Detta har lett till snabbare laddningstider då dessa paket orsakade onödigt stora bundles.