← Område 7 Fördjupning · Optimering och diskret funktionalitet Felsökning

Webbutveckling 1 · område 7 · fördjupning

Diskret funktionalitet: sajter som håller även när något fattas

Den här guiden går längre än de andra. Den är skriven för dig som siktar mot A, men avsnitt 1–6 gäller alla: att sajten inte ska krascha utan JavaScript är ett ska-krav i Projekt 6, inte en utmaning.

Exemplen kommer ur referensprojekt/. Den rätta versionen heter diskret/, den avskräckande hardkodad/. Koden i den här guiden är samma kod som ligger där.

Kraven guiden stödjer står i uppgift/projekt-6.md.

Vad du kan efter guiden

1. Vad diskret betyder

Diskret (på engelska unobtrusive) betyder att JavaScript lägger sig ovanpå en sida som redan fungerar, i stället för att bära den.

Tänk på en hiss i ett hus med trappa. Fungerar hissen tar du hissen. Står den stilla går du i trappan – du kommer fortfarande upp. Ett hus där hissen är enda vägen är ett sämre hus, hur bra hissen än är.

Din sajt är huset. HTML och CSS är trappan. JavaScript är hissen.

Varför någon skulle sakna JavaScript

Frågan kommer alltid, och den är rimlig. Nästan alla har JavaScript på. Men:

SituationHur ofta
Skriptet hann inte laddas innan besökaren klickadeVarje dag, på varje sajt
Uppkopplingen bröts mitt i hämtningenTunnelbana, hiss, landsbygd
Ett fel i en annan del av koden stoppade alltOftare än du tror
Företagets brandvägg blockerar externa skriptVanligt på arbetsplatser
Webbläsartillägg som blockerar skriptEtt par procent av alla besökare
Sökmotorn som indexerar sidanGoogles robot kör JavaScript, andra gör det inte
Skärmläsare och äldre hjälpmedelKlarar ofta inte dynamiskt innehåll

Den vanligaste är den första, och den drabbar alla. Mellan att HTML:en är ritad och att skripten körts finns en lucka. Är knappen klickbar i den luckan och gör ingenting, ser sajten trasig ut – för alla, varje gång.

Det är inte "för säkerhets skull"

En diskret sajt blir också enklare att läsa, enklare att felsöka, bättre för skärmläsare och lättare att flytta. Att den dessutom överlever utan JavaScript är resultatet, inte syftet.

2. De tre lagren

LagerFilSvarar på
Struktur.htmlVad är det här? En rubrik, en lista, ett formulär
Stil.cssHur ser det ut?
Beteende.jsVad händer när någon gör något?

Regeln är att varje lager ska gå att ta bort underifrån och uppåt. Ta bort JavaScript: sidan ser likadan ut och innehållet finns. Ta bort CSS:en också: sidan blir ful men fullt läsbar. Kvar finns strukturen, och den bär allt.

Du har redan sett vad som händer när lagren blandas. I område 3 lärde du dig att inte skriva style= ute i HTML:en. Det här är samma regel, ett steg upp.

Så ser en blandning ut

Ur hardkodad/:

<button type="button" class="lagesknapp"
        onclick="byteLage()">Mörkt läge</button>

Ett element som är tre saker samtidigt: struktur (en knapp), utseende (klassen) och beteende (onclick). Ur diskret/:

<button type="button" class="lagesknapp" hidden
        aria-pressed="false">Mörkt läge</button>

Struktur och en klass. Beteendet ligger i js/morkt-lage.js, som letar upp knappen själv.

3. Beteende hör inte hemma i HTML

"Det är fult" är inget skäl. Här är fyra som är det.

1. Du hittar det aldrig igen. Ett onclick på rad 48 i en av fem sidor syns inte när du söker i js/-mappen. Skriptet däremot står på ett ställe.

2. Bara en funktion per händelse. onclick kan hålla ett anrop. Behöver du två saker vid ett klick får du skriva om. addEventListener kan sätta hur många lyssnare som helst på samma element, oberoende av varandra.

3. Funktionen måste vara global. onclick="byteLage()" kräver att byteLage finns i fönstrets globala namnrymd. Det är därför hardkodad/js/sidan.js inte kan använda kapseln (function () { … })(); som alla moduler i område 6 har – och därmed kan två skript skriva över varandras variabler utan att någon märker det.

4. Knappen ljuger i luckan. Står onclick i HTML:en är knappen klickbar redan innan skriptet laddats. Klickar någon då händer ingenting, och felet syns inte någonstans.

Samma sak gäller länkar

<a href="javascript:visa('faglar')">Fåglar</a>

En länk som inte leder någonstans. Utan JavaScript är den helt död: den går inte att öppna i ny flik, den betyder ingenting för en sökmotor, och en skärmläsare säger att det är en länk fast det inte är det. Är det en knapp ska det vara en <button>. Leder den någonstans ska href vara den adressen.

<a href="#faglar">Fåglar</a>

Den här fungerar utan skript – den hoppar till avsnittet. Ett skript får gärna fånga klicket och göra något finare i stället.

4. Vad som ska fungera utan JavaScript

Kravet är inte att allt ska fungera. Det är att innehållet ska finnas och ingenting ska se trasigt ut.

Ska fungera utan JavaScriptFår sluta fungera
All text och alla bilder synsFiltrering och sortering
Alla länkar leder rättBildspel som bläddrar automatiskt
Menyn går att användaAtt menyn fälls ihop till en hamburgare
Formuläret går att fylla i och skickaFelmeddelanden under fälten medan du skriver
Rubrikerna och strukturen står kvarMörkt läge som sparas till nästa gång
Tabeller och listor är komplettaQuizet som rättar sig självt

Det avgörande är vem som äger innehållet. Står texten i HTML:en finns den alltid. Skrivs den in av ett skript finns den bara ibland.

Jämför de två versionerna av stigsidan utan skript:

diskret/hardkodad/
Bilder på sidan30
Knappar som inte gör något03

Den hårdkodade sidan bygger sina bilder ur en lista i sidan.js. Utan skript finns listan inte, och då finns inte bilderna. Den diskreta har dem i HTML:en och låter skriptet göra om dem till en karusell.

5. hidden-mönstret

Mönstret som bär alla sex modulerna i område 6, i tre rader:

1. Det som bara fungerar med skript är gömt i HTML:en.

<button type="button" class="menyknapp" hidden
        aria-expanded="false"
        aria-controls="huvudmeny-lista">Meny</button>

2. Skriptet kontrollerar att elementet finns.

const knapp = document.querySelector(KNAPP);
const lista = document.querySelector(LISTA);
if (!knapp || !lista) { return; }

3. Först när skriptet vet att det fungerar tar det bort hidden.

knapp.hidden = false;

Läs ordningen igen: knappen syns inte förrän skriptet som styr den är igång. Därför kan det aldrig finnas en död knapp på sidan. Utan skript stannar hidden kvar, och menyn visas som en vanlig lista med länkar – som på en sida i område 4.

Fällan: CSS slår ut hidden

Det här kostade tid när området byggdes, och det är värt att kunna.

Attributet hidden sätter display: none – men i webbläsarens egen stilmall, och den är svagare än din. Skriver du någonstans i stil.css:

.karusell-styr {
  display: flex;
}

…så syns raden ändå, med hidden och allt. Sidan ser rätt ut så länge JavaScript körs, eftersom skriptet tar bort attributet. Med JavaScript av står tre döda knappar kvar, och du får aldrig veta om det förrän någon säger till.

Lösningen är att låta regeln gälla bara när elementet inte är gömt:

.karusell-styr:not([hidden]) {
  display: flex;
}

Regeln att komma ihåg: sätter du display på något som också kan ha hidden, skriv :not([hidden]). Det gäller display: flex, display: grid och display: block lika mycket.

6. Progressive enhancement, steg för steg

Progressive enhancement betyder ungefär "förbättra stegvis". Arbetsordningen är hela idén, och den är tvärtom mot hur de flesta börjar.

StegDu byggerDu kontrollerar
1HTML som fungerar helt utan stil och skriptLäs sidan utan CSS. Går innehållet att förstå?
2CSS som gör den läsbar och responsivSidan är färdig att lämna in. Den är klar här
3JavaScript som gör något bättreStäng av skriptet. Är du tillbaka på steg 2?

Steg 2 är den viktiga raden i tabellen: en sajt utan JavaScript ska vara en färdig sajt, inte en trasig.

Ett exempel hela vägen

Reservatets artsida ska gå att filtrera på grupp.

Steg 1, HTML. Tre avsnitt med id och en innehållsförteckning som länkar till dem. Filterraden ligger där, tom och gömd:

<nav class="pasidan" aria-label="Innehåll på sidan">
  <ul>
    <li><a href="#faglar">Fåglar</a></li>
    <li><a href="#daggdjur">Däggdjur</a></li>
  </ul>
</nav>

<div class="filter" role="group" aria-label="Visa" hidden></div>

<section id="faglar" data-grupp="faglar"> … </section>

Utan skript har besökaren en innehållsförteckning som hoppar till rätt avsnitt. Det är inte filtrering, men det löser samma problem: att hitta.

Steg 2, CSS. Avsnitten staplas, innehållsförteckningen blir en sidospalt på bred skärm. Filterraden får display: flex – med :not([hidden]), enligt avsnitt 5.

Steg 3, JavaScript. galleri.js läser vilka data-grupp som finns, bygger en knapp per grupp, tar bort hidden och gömmer det som inte valts.

Tre lager, tre filer, och varje steg fungerar utan det ovanför.

Testet som avgör

Fråga dig: om jag tar bort det här skriptet, förlorar besökaren en genväg eller förlorar hen innehållet?

Genväg är rätt svar. Innehåll är fel.

7. Formulär: HTML först, skript sedan

Formulär är där det här blir konkret, och där skillnaden mellan E och A syns tydligast.

Vad HTML gör alldeles själv

<p>
  <label for="epost">E-postadress</label>
  <input type="email" id="epost" name="epost"
         autocomplete="email" required>
</p>

<p>
  <label for="antal">Antal personer</label>
  <input type="number" id="antal" name="antal"
         min="1" max="15" value="1" required>
</p>

Fyra attribut gör fyra jobb utan en rad JavaScript: required kräver ett svar, type="email" kräver ett snabel-a, min och max kräver ett rimligt tal, och autocomplete gör att telefonen fyller i åt besökaren. Webbläsaren stoppar sändningen och visar ett meddelande, på besökarens eget språk.

Den hårdkodade versionen slänger bort allt det:

<form novalidate>
  <input type="text" id="namn" name="namn" autocomplete="name">
  …
  <button type="button"
          onclick="skickaAnmalan()">Skicka anmälan</button>
</form>

novalidate stänger av webbläsarens kontroll. type="button" gör att knappen inte skickar något. Utan JavaScript går formuläret att skicka tomt – nej, värre: det går inte att skicka alls, för knappen gör ingenting.

Så gör modulen i stället

Det här är kärnan i hela guiden, och det står på tre rader i validering.js:

const formular = document.querySelector(FORMULAR);
if (!formular) { return; }

formular.setAttribute("novalidate", "");

Läs den sista raden igen. novalidate sätts av skriptet, inte i HTML:en.

Utan JavaScriptMed JavaScript
novalidate finns?NejJa, skriptet satte det
Vem kontrollerar?WebbläsarenSkriptet
Hur visas fel?Webbläsarens egen bubbla<p class="fel"> under fältet

Sidan har alltså alltid validering. Den byts bara ut mot en bättre när det går.

Skriptet bestämmer inte vad som är fel

Ett misstag som ser ut som ambition: att skriva egna regler i JavaScript för vad som är en giltig e-postadress. Modulen gör tvärtom – den frågar webbläsaren:

if (falt.checkValidity()) {
  taBortFel(falt);
} else {
  visaFel(falt);
}

checkValidity() returnerar sant eller falskt utifrån required, type, min och max i HTML:en. Objektet falt.validity säger sedan vilket av felen det var: valueMissing, typeMismatch, rangeUnderflow, rangeOverflow.

Vinsten är att reglerna bara finns på ett ställe. Lägger du till required på ett fält behöver skriptet inte ändras alls.

Och sändningen

formular.addEventListener("submit", function (handelse) {
  const forstaFel = kontrollera();
  if (forstaFel) {
    handelse.preventDefault();
    forstaFel.focus();
  }
});

Lyssnaren ligger på submit, inte på knappens click. Det är skillnaden mellan ett formulär som fungerar och ett som bara ser ut att göra det: submit utlöses också av Enter i ett textfält, och av alla sätt att skicka ett formulär som du inte tänkt på.

preventDefault() stoppar sändningen – men bara när det finns fel. Är allt rätt gör skriptet ingenting, och formuläret skickas som vanligt.

8. Säg det som händer: aria-live

När ett skript ändrar något på sidan ser du det. Den som använder skärmläsare gör det inte – uppläsningen står där den står.

aria-live löser det. Ett element med det attributet läses upp när innehållet ändras, utan att fokus flyttas.

<div class="karusell-styr" hidden>
  <button type="button" class="karusell-forra">Föregående</button>
  <p class="karusell-lage" aria-live="polite"></p>
  <button type="button" class="karusell-nasta">Nästa</button>
</div>

Skriptet skriver "Bild 2 av 3" i stycket varje gång någon bläddrar, och skärmläsaren säger det.

VärdeBetyder
politeLäses när användaren är tyst. Det du ska använda
assertiveAvbryter mitt i. Bara för fel som måste stoppa något
offStandard. Läses inte

Tre regler:

  1. Elementet ska finnas i HTML:en från början, tomt. Skapar skriptet det samtidigt som det fyller det hinner skärmläsaren inte uppfatta ändringen.
  2. Skriv kort. "Bild 2 av 3" är bra. Ett helt stycke blir tjat.
  3. En i taget. Fem aria-live på samma sida pratar i munnen på varandra.

Referensprojektet har två: karusellens lägesrad och quizets resultat. Båda är tomma i HTML:en, båda är polite.

aria-live är det tillgänglighetsverktyg du inte hade i område 4, och det är just för att det hör ihop med skript som ändrar saker.

9. Graceful degradation

Graceful degradation betyder att det ska bli sämre, inte trasigt, när något fattas. Det är samma mål som progressive enhancement, sett från andra hållet: där börjar man nerifrån och bygger uppåt, här börjar man med det färdiga och frågar vad som händer när delar faller bort.

Faller bortSnyggtTrasigt
JavaScriptMenyn är en vanlig listaKnapp som inte gör något
En bildfilalt-texten står där bilden skulle varitEn tom ruta utan förklaring
Ett typsnittTexten visas i reservtypsnittetSidan står tom och väntar
localStorage (privat läge)Läget gäller den här sidan, glöms sedanSkriptet kraschar och menyn slutar fungera
En CSS-egenskap webbläsaren inte kanNågot enklare visas i ställetLayouten faller isär

Den fjärde raden är verklig. localStorage kastar ett fel i privat läge i vissa webbläsare, och ett fel som inte fångas stoppar resten av filen. Därför ser morkt-lage.js ut så här:

function spara(lage) {
  try {
    localStorage.setItem(NYCKEL, lage);
  } catch (fel) {
    // Går inte att spara. Läget gäller ändå tills sidan laddas om.
  }
}

try/catch betyder "försök – går det inte, gör det här i stället". Den tomma catch-satsen är ett medvetet val, och kommentaren finns för att en tom catch annars ser ut som ett misstag.

10. Skriv en egen diskret funktion

A-spåret i Projekt 6 vill ha en funktion du skrivit själv. Här är reglerna och ett helt exempel.

Reglerna

RegelVarför
Allt i (function () { "use strict"; … })();Ingen global variabel, inga krockar
Zon ÄNDRA HÄR överst med klassnamn och texterDen som använder modulen ska slippa läsa resten
Leta upp elementen, return om de saknasEtt skript ska aldrig krascha en sida
Det som bara fungerar med skript har hiddenInga döda knappar
Byt attribut och klasser – CSS:en gör restenBeteende och utseende hålls isär
addEventListener, aldrig onclick i HTMLAvsnitt 3
textContent, inte innerHTML, för textSäkerhet och enkelhet
Inga console.log kvarKonsolen ska vara tom när det fungerar

Ett helt exempel: visa mer

Funktionen: ett långt avsnitt kortas av, och en knapp fäller ut resten. Utan skript står hela texten där.

HTML – hela texten finns, knappen är gömd:

<section class="fallbar">
  <h2>Reservatets historia</h2>
  <div class="fallbar-text" id="historia-text">
    <p>Mossen dikades ut första gången 1912 …</p>
    <p>Kommunen köpte marken 1984 …</p>
    <p>Reservatet bildades 1987 …</p>
  </div>
  <button type="button" class="fallbar-knapp" hidden
          aria-expanded="false"
          aria-controls="historia-text">Visa mer</button>
</section>

CSS – korta av bara när skriptet är igång:

.fallbar-knapp:not([hidden]) {
  display: inline-block;
}

.fallbar:has(.fallbar-knapp[aria-expanded="false"]) .fallbar-text {
  max-height: 8rem;
  overflow: hidden;
}

:has() läser "ett .fallbar som innehåller en knapp med aria-expanded="false"". Knappen står efter texten i HTML:en, och en vanlig väljare kan bara peka framåt – :has() är det som låter regeln peka bakåt. Den fungerar i alla webbläsare sedan 2023.

JavaScript:

(function () {
  "use strict";

  /* ===== ÄNDRA HÄR ========================================== */
  const KNAPP = ".fallbar-knapp";
  const TEXT_MER = "Visa mer";
  const TEXT_MINDRE = "Visa mindre";
  /* ===== SLUT PÅ ÄNDRA HÄR ================================== */

  const knapp = document.querySelector(KNAPP);
  if (!knapp) { return; }

  const id = knapp.getAttribute("aria-controls");
  const text = document.getElementById(id);
  if (!text) { return; }

  knapp.hidden = false;
  knapp.textContent = TEXT_MER;

  knapp.addEventListener("click", function () {
    const utfalld = knapp.getAttribute("aria-expanded") === "true";
    knapp.setAttribute("aria-expanded", utfalld ? "false" : "true");
    knapp.textContent = utfalld ? TEXT_MER : TEXT_MINDRE;
  });

})();

Gå igenom den mot reglerna: kapsel, zon, två kontroller med return, hidden bort först när allt hittats, attributbyte i stället för style, textContent.

Notera .fallbar-text i CSS:en: det är aria-expanded på knappen som styr höjden, inte en klass skriptet sätter. Skriptet ändrar ett attribut, och CSS:en gör tre saker av det.

Vad du kan bygga

Förslag som är lagom stora och lätta att göra diskreta:

IdéUtan skript
Visa mer / visa mindreHela texten syns
Tillbaka till toppen-knappSidan går att skrolla
Kopiera adressen-knappAdressen står som text bredvid
Räknare för tecken kvar i ett textfältmaxlength i HTML:en gör jobbet
Filtrera en tabellTabellen är komplett och sorterad
Bekräfta innan en länk öppnas i ny flikLänken fungerar som vanligt

11. Testa med JavaScript avstängt

Ett krav du inte provat är ett krav du inte uppfyllt.

Så stänger du av

WebbläsareVäg
Chrome, EdgeInspektera → Ctrl + Shift + P → skriv javascript → Disable JavaScript. Gäller så länge Inspektera är öppen
FirefoxSkriv about:config i adressfältet, sök javascript.enabled, sätt till false. Kom ihåg att sätta tillbaka den
AllaEtt tillägg som NoScript. Onödigt för det här

Chrome-vägen är den att använda: den slås av när du stänger Inspektera, så du kan inte glömma den.

Vad du ska titta efter

Gå igenom varje sida och fråga i den här ordningen:

  1. Finns all text och alla bilder? Saknas något skrivs det in av ett skript och ska flyttas till HTML:en.
  2. Syns någon knapp eller kontroll som inte gör något? Då saknas hidden, eller så slår CSS:en ut det – avsnitt 5.
  3. Går menyn att använda? Alla länkar ska nås.
  4. Går formuläret att fylla i och skicka? Med required kvar?
  5. Ser sidan trasig ut? Tomma rutor, halva layouter, avhuggna avsnitt.
  6. Står det något som ljuger? "Klicka för att rätta" när knappen är död.

Skriv ner resultatet

I README.md, under en rubrik. Det är det som bedöms – inte att allt fungerar, utan att du vet vad som inte gör det:

Testat med JavaScript avstängt 4 mars:
  Startsidan       OK. Allt innehåll finns, inga döda knappar
  Galleriet        OK. Filterraden gömd, alla bilder syns
  Kontakt          OK. required kvar, webbläsaren validerar själv
  Quizsidan     Knappen "Rätta" syns och gör inget när den
                trycks. Medvetet: den är type="submit" och
                sidan laddas om. Frågorna finns kvar.

Sista raden är den som visar att du förstått skillnaden mellan degraderad och trasig.

12. Ta det längre

<noscript> – nästan aldrig svaret

<noscript>Den här sidan kräver JavaScript.</noscript>

Taggen visas bara när JavaScript är av. Frestelsen är att lösa hela guiden med den. Det är fel väg: den förklarar varför sidan är trasig i stället för att låta bli att vara trasig.

Det finns ett rimligt bruk: att säga att en specifik funktion inte är tillgänglig, när innehållet ändå finns. "Kartan visas inte utan JavaScript. Adressen står under."

:has() på fler ställen

Du såg :has() i avsnitt 10. Det gör samma tjänst i större delar av sidan:

.karusell:has(.karusell-styr:not([hidden])) .karusell-bilder {
  max-height: 20rem;
  overflow: hidden;
}

"Ser karusellen att dess knappar är synliga, alltså att skriptet är igång, så beter sig listan som en karusell." Samma idé som hidden-mönstret, utan att skriptet behöver sätta en klass.

En klass på <html> i stället

Ett vanligt mönster på riktiga sajter: det första skriptet på sidan sätter en klass, och CSS:en kan då skilja på de två världarna.

document.documentElement.classList.add("js");
.js .bara-utan-js { display: none; }

Det fungerar, och det är värt att känna igen. hidden-mönstret är ändå att föredra i den här kursen: det håller ihop element och beteende, och det kräver ingenting av <head>.

Läs modulerna som förlagor

De sex modulerna i diskret/js/ är skrivna efter reglerna i avsnitt 10. meny.js är kortast och lättast att läsa. validering.js är den som lär ut mest.

13. Felsökning

14 rader

SymtomTrolig orsakGör så här
Knappen syns utan JavaScripthidden saknas i HTML:enLägg till det. Skriptet tar bort det
Knappen syns fast hidden står därEn display-regel i CSS:en:not([hidden]) på regeln. Avsnitt 5
Knappen syns aldrig, inte ens med JavaScriptSkriptet hittar inte sitt element och avslutarJämför klassnamnet i HTML och i zonen
Innehåll försvinner utan JavaScriptSkriptet skriver in det med innerHTMLFlytta texten till HTML:en
Formuläret går att skicka tomtnovalidate står i HTML:enTa bort det. Skriptet sätter det själv
Formuläret skickas fast fält är felLyssnaren ligger på knappens clickLyssna på submit i stället
Enter i ett fält gör ingettype="button" på knappentype="submit"
Felmeddelandet läses inte upparia-live saknas, eller elementet skapades nyssHa ett tomt element i HTML:en från början
Skärmläsaren läser samma sak om och omassertive där polite räckerByt
Allt slutar fungera i privat lägelocalStorage utan try/catchAvsnitt 9
Ett skript stoppar de andraFel i en fil som körs innanKonsolen. Röda raden säger fil och radnummer
Sidan fungerar lokalt men inte publiceradSökväg med stor bokstav, eller absolut sökvägRelativa sökvägar, gemener
aria-expanded ändras men inget händerCSS:en lyssnar på en klass, inte attributetVälj ett av dem och håll dig till det
Länken gör inget utan JavaScripthref="javascript:…" eller href="#"Ge den en riktig adress, eller gör den till en button

14. Snabbreferens

hidden-mönstret

<button type="button" class="knapp" hidden
        aria-expanded="false">Text</button>
const knapp = document.querySelector(".knapp");
if (!knapp) { return; }
knapp.hidden = false;
.knapp:not([hidden]) { display: inline-block; }

Formulär som validerar i båda världarna

<input type="email" id="epost" required>
formular.setAttribute("novalidate", "");
if (falt.checkValidity()) { /* rätt */ } else { /* fel */ }

Meddelande som läses upp

<p class="status" aria-live="polite"></p>

Checklistan före inlämning

1Stäng av JavaScript i Inspektera
2Öppna varje sida
3Finns all text och alla bilder?
4Syns någon kontroll som inte gör något?
5Går formuläret att skicka, med required kvar?
6Skriv ner resultatet i README.md

Tre saker som aldrig hör hemma i HTML

onclick="…"Använd addEventListener
href="javascript:…"Använd button, eller en riktig href
novalidateLåt skriptet sätta det

15. Ordlista

Ordträning

OrdBetyder
aria-liveAttribut som gör att ändringar i ett element läses upp av skärmläsare
assertivearia-live-värde som avbryter uppläsningen. Används sällan
checkValidity()Metod som frågar webbläsaren om ett fält är korrekt ifyllt
degraderadFungerar sämre men inte trasigt när något fattas
diskretOm skript: lägger sig ovanpå en sida som redan fungerar
globalVariabel eller funktion som syns i hela fönstret. Krockar lätt
graceful degradationAtt det blir sämre, inte trasigt, när delar faller bort
hiddenHTML-attribut som gömmer ett element tills ett skript tar bort det
inline-attributBeteende skrivet i HTML:en, som onclick. Undviks
kapsel(function () { … })(); – håller variabler för sig själva
luckaTiden mellan att HTML:en ritats och att skripten körts
noscriptTagg vars innehåll bara visas när JavaScript är av
novalidateAttribut som stänger av webbläsarens formulärkontroll
politearia-live-värde som väntar tills användaren är tyst
preventDefault()Stoppar det webbläsaren annars skulle gjort, till exempel skicka ett formulär
progressive enhancementAtt bygga nerifrån: HTML, sedan CSS, sedan JavaScript
submitHändelsen när ett formulär skickas, oavsett hur
try/catch"Försök – går det inte, gör det här i stället"
unobtrusiveEngelska för diskret
validityObjekt som säger vilket fel ett fält har