Vad är diskreta domskript?
För betygen A-C i kursen Webbutveckling 1 så står det
I produkten infogar eleven enkla diskreta domskript.
Så kan det bli när reglerna förbjöd mig
använda engelska. Annars hade det stått unobtrusive DOM-scripts
. Jag skall här försöka reda ut
de tre nycklarna som finns för att förstå skrivningen, vilket enklast görs bakifrån genom att vi
tittar på orden (3) DOM-skript, (2) diskreta och (1) infogar.
Testa dig själv
Finn (minst) fem fel (utöver att koden inte är komplett).
<div id="a">Lorem ipsum.</div> <button onclick="hideme()">Dölj</button> <script language="javascript"> <!--// Dölj från gamla webbläsare function hideme() { the_div = document.getElementById("a"); the_div.style.display="none"; } --> </script> <noscript>Din webbläsare måste stödja JavaScript för att denna sida skall fungera.</noscript>
Du kan också titta på det kompletta kodexemplet.
DHTML
JavaScript i kombination med CSS salufördes under 90-talet under namnet DHTML. Och till allra största delen var det av ondo.
- Man blandade ihop olika slags kod: HTML, CSS och JavaScript blandades huller om buller.
- HTML användes fortfarande till att styra utseendet.
- Skripten ändrade i dokumenten med metoden
document.write
som är en mardröm ur varje tänkbar aspekt. Metoden borde aldrig ha uppfunnits enligt Brendan Eich (språkets upphovsman). - Programkoden var oftast ostrukturerad och grötig. Globala variabler användes och ett skript kunde skriva över variablerna från ett annat skript.
- Olika webbläsare hade olika DOM-funktioner och för att skilja mellan Netscape och
Internet Explorer så
sniffade
man efter vilken det var ochforkade
(förgrenade) koden för att hantera skillnaderna. Ibland nöjde sig utvecklarna med att bara stödja den ena och uppmanande besökarna att byta webbläsare om de användefel
. - Om JavaScript inte fanns i webbläsaren eller inte var aktiverat så fick man ofta meningslösa meddelande genom
<noscript>
. - Man hade tabeller i tabeller i tabeller ner till 7-8 nivåer för layout och ramar för att skapa layout. Och spacer-gif-bilder. (Om du inte vet vad jag pratar om är du en lyckans ost!)
- Man hade popups och popups och fler popups…
Resultatet var måttligt roande:
- Sidornas kod blev svår eller omöjlig att felsöka och underhålla.
- Koden var sällan robust och framtidssäker. Nya versioner av webbläsare kunde innebära att den slutade fungera.
- Mindre vanliga och nya webbläsare, som Opera och sedan Firefox och Safari exkluderades i onödan.
- Användarvänligheten på sidorna förbättrades sällan utan blev snarare sämre. Meningslösa animeringar och löjliga skrollande effekter irriterade användarna.
- Sidorna tog onödigt lång tid att ladda och blev tröga att använda.
- Sidornas tillgänglighet förstördes och sökmotorerna kom att indexera dem dåligt och ranka dem lågt.
Till utvecklarnas försvar skall det sägas att man inte hade mycket att jobba med. Webbläsarna hade groteska buggar,
ofullständiga implementeringar och lanserade proprietära tekniker i syfte att just tvinga utvecklarna att utveckla
för den egna webbläsaren. Men ärligt talat så berodde det främst på att sidorna utvecklades av utvecklare som saknade
nödvändig kompetens och att de som hade kompetensen inte tyckte webbutveckling var fint
nog.
Begreppet DHTML är namnet som användes för att beskriva katastrofen.
Standardernas segertåg
De fyra viktigaste standarderna som en webbsida bygger på är:
- HTML
- CSS
- EcmaScript
- DOM
Under slutet av 90-talet började äntligen medvetenheten om att följa standarder vinna ett visst fotfäste.
Från och med HTML 4 har vi haft en ganska stabil bas att stå på för HTML-koden. Under år 2003 kom det stora
genombrottet för CSS-baserad layout. Inte minst genom att Netscape Navigator försvunnit från marknaden.
Då slapp vi skilja mellan <layer>
och <div>
och kunde använda i vart fall merparten av CSS 1.
Att använda standarder
blev ofta en synonym för att använda CSS för designen, men i själva verket
var det tre saker som standardbaserad utveckling bestod av:
- Att inte använda proprietär kod.
- Att skriva validerande och semantisk HTML.
- Att separera designen från innehållet och använda CSS för den.
Men JavaScript förblev ett bekymmer. Skillnaderna mellan DOM-standarderna, som nu började implementeras i Opera och Firefox och Microsofts egen DOM i Internet Explorer förblev stora. Det var i den här situationen som bl.a. Web Standards Project DOM Scripting Task Force identifierade en möjlig väg att börja använda skript på ett vettigt sätt. Först behövdes ett nytt namn som signalerade det nya tänkandet.
(3) DOM-skript
Only the adoption of unobtrusive DOM scripting will do away with outdated, uninformed,
and inaccessible development methods. Only the adoption of unobtrusive DOM scripting will allow JavaScript, and thus web development in general, to attain its full potential.
Så som ordet här används handlar det om mer än att rent tekniskt använda DOM-funktioner. Det handlar
om att ha en helhetslösning för välskriven kod, god praxis, användbarhet, och tillgänglighet.
JavaScript skall användas för att förbättra en webbplats användbarhet, men med undantag för regelrätta
applikationer som Google Docs, så skall den fungera på en basnivå även om JavaScript inte har aktiverats i
webbläsaren. Precis som man kan se om HTML-koden är bra om man kör
naket
, så skall ingen funktionalitet vara omöjlig att använda utan skript.
Fler än man tror saknar JavaScript: Det kan vara användare som blockerar det av säkerhetsskäl, företag som strippar ut skript i sina proxies och mobilsurfare som använder Opera Mini pga hög kostnad för överförd data eller dålig bandbredd.
Däremot finns det ingen – absolut ingen – som använder en så gammal webbläsare att skripten måste döljas från dem med HTML-kommentarer. Det finns fortfarande guider som föreslår att du använder dem, trots att det inte behövts på snart 15 år. Det var ett av felen i kodexemplet ovan.
JavaScript bör infogas som progressive enhancement.
Då behövs ingen fallback med <noscript>
.
Noscript-koden ovan hade även ett dåligt innehåll, men rätt utfört behövs alltså inte noscript-taggarna alls!
Andra viktiga principer för DOM-skript
- Man bör koda för standarder först, och hantera enskilda webbläsares brister bara när det behövs.
- I stället för att browsersniffa så bör man kapacitetsdetektera eller bug-detektera. Kan Jquery kan du!
- All kod bör vara
self contained
och inte förpesta den globala namnrymden med globala symboler. Såväl funktionen hideme som variabeln the_link i koden ovan bryter mot denna princip.
(2) Diskreta = Unobtrusive
Det ord jag ville använda i kursplanen, men som definitivt inte finns på svenska är
unobtrusive
.
Jag skrev en uppsats (PDF)
om detta på Högskolan Väst för ett par år sedan och myntade då själv begreppet diskreta skript.
Ett skript som är diskret
tränger sig inte på (obtrude), utan är helt separerat från HTML och CSS-koden.
Det styr inte designen, men kan aktivera ändringar och animeringar. Detta kräver några saker:
- Allt bruk av
document.write
måste upphöra! Du vinner dessutom prestanda och en massa andra fördelar, så förlusten är inte tung att bära. - Alla inline event handlers måste bort. De har flera nackdelar. Dels så inkräktar de på HTML-koden och är alltså lika illa att använda som inline CSS. Dels så tolkas de som eval. Och eval is evil – av en mängd skäl, inte minst prestanda och scoping som kan lura de bästa. Dessutom förutsätter de ofta globala symboler för att fungera. Alla dessa problem finns i kodexemplet ovan. (target)
Var skall skripten placeras?
Först och främst gäller samma regel som för CSS: Skripten skall placeras i egna filer, externt, och laddas in via src-attributet. Det är grundregeln som bara får brytas om du arbetar på expertnivå och måste trycka ut några mikrosekunders bättre prestanda ur din webbplats.
När webbläsare ser en vanlig script-tagg med src-attribut, så avbryter de tolkningen av sidan, hämtar hem skriptet – vilket tar tid – och tolkar skriptet – vilket tar ännu mer tid. Sedan fortsätter de tolka resten av HTML-koden.
Av det här skälet är det bäst att placera skripten allra
sist i body-elementet,
precis före dess sluttagg. Då har man dessutom fördel av att hela DOM-strukturen hunnit laddas in i datorns
minne och är åtkomlig för skripten. Man kan ju inte göra en getElementById("a")
innan elementet med id="a" har lästs in.
Alternativet är att placera skripten i head-delen av dokumentet och sedan aktivera dem med en händelse, men det har några nackdelar:
- Man kan få parallell nedladdning av skripten genom attributen async eller defer, men de stöds inte ännu av alla webbläsare och måste betraktas som överkurs på en nybörjarkurs.
- Man kan använda händelsen
load
, men den triggas först när också alla bilder och all annan media laddats ner, vilket ofta är för sent. - Man kan använda händelsen DOMContentLoaded, men den stöds ännu bara i vissa webbläsare.
- Man kan trigga skripten genom
pollning
, vilket definitivt är överkurs på gymnasienivå, eller på grundläggande högskolenivå.
Däremot kan man använda sig av färdiggjorda expertlösningar i form av kodbibliotek som Jquery, Motools eller YUI. Vilket för oss till sista steget.
(1) Eleven skall infoga skript
För kursen Webbutveckling 1 förväntas inte eleverna skriva några egna längre skript. Däremot bör de kunna infoga väl valda skript som andra utvecklat. Kanske vill de ha en slideshow för sina bilder och då kan den JQuery baserade lösningen Nivo slider vara lösningen. Kanske vill de ha en enkel visa/dölj effekt, eller en rullgardinsmeny.
När elever väljer en lösning så måste de kunna bedöma kvalitén eller ställa rätt frågor. De måste i vart fall ha såpass mycket terminologi och förståelse med sig så att de kan söka på nätet eller ställa rätt frågor på ett forum. Dessutom bör de känna igen de viktigaste varningstecknen på dåliga DHTML-liknande lösningar.
Slutligen behöver de känna igen mönstret för hur man fäster händelser på objekt. Här visar jag hur man kan göra om koden från det dåliga exemplet ovan och lägger till en aning överkurs. Jag gör mitt skript självexekverande, så att inte en enda symbol läggs till den globala namnrymden.
Hur skall det då göras?
Så här kan man göra i ren JavaScript när man löser samma sak som i det dåliga exemplet:
<div id="a">Lorem ipsum dolor sit amet.</div> <!-- Knappen infogas med javascript --> <script> // Ja detta borde vara externt men ligger här // för att spara lite möda för dig kära läsare (function () { "use strict"; var the_div = document.getElementById("a"); // Med var-deklarationen görs variabeln lokal var btn = document.createElement("button"); btn.innerHTML = "Dölj texten"; btn.onclick = function () { // Anonym funktion för enstaka ad hoc bruk // DOM 0 event handler är enklast för nybörjare // Inre funktion kommer åt variabel från // yttre funktion the_div.style.display="none"; } // Av utrymmesskäl gör vi det osäkra antagandet // att the_div har efterföljande syskon the_div.parentNode .insertBefore(btn, the_div.nextSibling); })(); // self executing closure </script>
Några ytterligare kommentarer:
- Vi använder
use strict
för att hålla skriptet rent från somliga dåliga delar av JavaScript-standarden, som aldrig borde ha uppfunnits. - Knappen hoppar runt lite, men det kan lösas om detta exempel vore
på riktigt
. - HTML-koden validerar (nästan) för både den dåligt skrivna sidan. Men JSHint larmar om problem för den dåliga skriptkoden.
Så här kan man göra i JQuery – och detta är vad jag förväntar mig att elever skall kunna:
<div id="a">Lorem ipsum dolor sit amet.</div> <!-- Knappen infogas med javascript --> <script> (function () { "use strict"; var the_div = $("#a"); var btn = $("<button>Dölj/visa texten</button>") .click( function () { the_div.toggle("slow"); }); btn.insertAfter(the_div); })(); // self executing closure </script>
Felen i det dåliga exemplet
- Knappen skapades inte med JavaScript.
- Knappen hade en inline event handler.
- Inline event handlern har en underförstådd eval.
- Attributet language skall inte användas.
- Kommentarer för att dölja skriptet är så 1995.
- Variabeln the_div deklarerades inte med var och är därför global.
- (Funktionen hideme är också global, men på nybörjarnivå kan man leva med det.)
Bonustips
Attributet language är ett säkert tecken på att ett skript är föråldrat. Det var det sista felet som jag nämner i koden ovan. I HTML 4.01 och XHTML 1.x så krävdes attributet type, men i HTML5 så är det frivilligt och det har alltid varit onödigt. Jag har inte med det i min förbättrade kod.
P.S
Min egen webbplats har inte fått något designlyft på flera år. Jag har inte tid! Vill någon göra något åt detta så kontakta mig.
Publicerad: 2011-10-11 21:02
Uppdaterad: 2011-10-11 21:22