Jesper Tverskov, 12. december 2002
Det er misforstået dyd at designe for alle browsere. Det er til skade for brugerne, for producenterne af browsere og for forfatterne af websider. Artiklen er en ressourcefil, der tester din browser, og som afdækker de grundlæggende problemer ved browser-sniffing.
Bilag: Din browser detektet server-side og client-side
Browser-sniffing foregår "server-side", dvs. på web-serveren før websiden sendes til browseren, eller "client-side", dvs. efter at websiden er ankommet til browseren. Hvad sker der, når du skriver en URL i browserens adresselinje eller klikker på et link, der peger på en webside? Der sker det, at browseren sender en forespørgsel til en web-server: vis mig denne webside.
Hvis den efterspurgte webside blot er en simpel html-fil, sender web-serveren den uden videre til browseren. HTML-siden kan evt. indeholde browser-sniffing typisk lavet med JavaScript. Når websiden ankommer til browseren, kan siden i teorien med det rette script detekte, hvad det er for en browser og hvad den kan, og websiden kan derefter tilpasse sig browseren.
Er der tale om en mere avanceret webside, f.eks. af typen aspx, asp, php, jsp, cfm, eller andre bogstavkombinationer, der signalerer, at websiden indeholder scripts eller tilsvarende, der skal udføres "server-side", læser web-serveren scriptene og følger deres anvisninger, før websiden sendes til browseren. Disse scripts kan også indeholde browser-sniffing, der identificerer browseren, finder ud af hvad browseren kan, og som tilpasser websiden før den sendes til browseren.
Browser-sniffing kan altså ske både før websiden sendes til browseren, og efter at websiden er ankommet til browseren. "Server-side" kan browser-sniffing kun identificere browseren, og denne identifikation kan så bruges til at slå oplysninger om browseren op i en tabel. Browser-sniffing efter at websiden er ankommet til browseren kan også indsamle oplysninger i en række objekter i browseren og f.eks. teste på tilstedeværelsen af objekter. Det er meget almindeligt at begge typer browser-sniffing anvendes af den samme webside, fordi visse ting er bedst tjent med at foregå på serveren og andre ting klares bedst direkte i browseren.
Dynamiske menuer bør f.eks. foregå interaktivt i browseren uden at hvert museklik sender tidskrævende forespørgsler til web-serveren om at genloade websiden. Dynamiske menuer kan være lavet med Flash men vil typisk være lavet med DHTML, der understøttes vidt forskelligt i diverse browsere. Derfor vil det normalt være bedst at integrere browser-sniffing i scriptet, der genererer den dynamiske menu på websiden, efter at websiden er ankommet til browseren.
Som eksempel på browser-sniffing "server-side", kan vi bruge websiden "Indhold" på www.klapmusen.dk. Websidens layout er ikke lavet med tabeller men med avanceret CSS, som jeg kun kan få til at virke i Internet Explorer. Derfor tester websiden for browser "server-side". Er det en IE-browser, vises websiden med ét IE-optimeret XSLT-stylesheet. I alle andre browsere vises websiden med et XSLT-stylesheet, der fjerner ramme og baggrundsfarve.
Grundlaget for alt traditionel browser-sniffing ligger i HTTP, dvs. i "Hyper Text Transfer Protocol", der gør kommunikation over Internettet mulig. Når browseren requester en webside, medsendes såkaldte "headers" og tilsvarende medsender web-serveren "headers" til browseren, når den requestede webside sendes til browseren. "Headers" er blot tekststrenge.
I tabellen "Din browser detektet server-side og client-side", som der linkes til i artiklens indholdsfortegnelse, vises en enkelt af de "headers", som din browser sender til webserveren. HTTP_USER_AGENT er grundlaget for alt browser-sniffing, der fokuserer på browserfabrikat og versionsnummer.
Oplysningerne i "User Agent" ser fornuftige ud, hvis du bruger en version af en af de store kendte browsere, f.eks. Internet Explorer eller Netscape. Men detektion af browseren er problematisk, når vi begynder at gå i detaljer.
I HTTP 1.0 havde browseren ikke pligt til at medsende én eneste "header" i udfyldt tilstand. I HTTP 1.1, der anvendes i dag, har browseren kun pligt til at medsende én oplysning, nemlig REMOTE_HOST.
Det er altså fuldt ud lovligt for en browser ikke at identificere sig eller f.eks. at glemme at oplyse versionsnummer, platform, osv. Det er også lovligt for en browser at udgive sig for en anden browser.
Da Microsofts Internet Explorer blev lanceret identificerede den sig som Netscape for ikke at blive udelukket fra websites, der var optimeret til brug for Netscape. Heldigvis indeholdt tekststrengen i "headeren" bogstaverne MSIE, der gjorde det muligt for programmører at lave kode, der kunne finde ud af, at der var tale om Internet Explorer.
I de første versioner udgav browseren Opera sig også for at være Netscape, men i dag hvor Internet Explorer er den helt dominerende browser, er det selvfølgelig denne browser andre browsere foregiver at være. I f.eks. Opera 6.0 kan brugeren selv bestemme, om Opera skal identificere sig som Opera eller som Internet Explorer!
Jeg har netop testet Beta-versionen af Opera 7.0. Her er Opera rigtig smart. I "User-agent" identificerer Opera sig således:
"Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows XP) Opera 7.0 [en]"
Opera identificerer sig altså både som IE 6.0, IE 5.5 og som Opera 7. "Mozilla/4.0" er blot den klassiske betegnelse for en browser kompatibel med "Netscape". Det betyder, at hvis websidens browser-sniffing spørger, om det er Internet Explorer , svarer Opera: "Ja det er mig". Spørges der om Opera, svarer Opera: "Ja det er også mig".
Det er svært at bebrejde Opera denne praksis, fordi det er programmørerne bag browser-sniffing, der ofte ikke tænker sig om. Det meste browser-sniffing på Internettet diskriminerer mindre kendte browsere. Det er meget almindeligt, at browser-sniffing blot skelner mellem Microsoft og Netscape, og at alle andre browsere enten ikke får adgang eller må tage til takke med en fortyndet udgave af websiden.
Det er også et problem, at fabrikanterne af browsere stort set selv bestemmer, hvordan de medsendte oplysninger i "User agent" ser ud. Der er derfor umuligt, for en forfatter af hjemmesider at bruge de detektede oplysninger til noget som helst, hvis den pågældende browsers måde at identificere sig på ikke er kendt i forvejen.
Strengt taget er hver eneste forfatter af hjemmesider nødt til at anskaffe sig hver eneste version af alle browsere på markedet, teste hvordan de identificerer sig, og så lave noget kode, der kan trække de relevante oplysninger om browserfabrikat og versionsnummer ud af "headeren" næste gang en tilsvarende browser kommer forbi.
Det er selvfølgelig i praksis umuligt for den enkelte forfatter af hjemmesider at teste alverdens browsere blot for at finde ud af, hvordan de identificerer sig. Derfor har nogle programmører oploadet scripts til nettet, der kan identificere de mest udbredte browsere. Denne scriptkode skal selvfølgelig vedligeholdes i hvert fald et par gange om året, og som alt anden kode indeholder den fejl eller tvivlsomme elementer. Andre webudviklere kan så downloade denne kode, modificere den eller lade sig inspirere til at skrive egne scripts til browser-sniffing.
Det berømteste script til browser-sniffing hedder The Ultimate JavaScript Client Sniffer. Det interessante er, at forfatterne til scriptet i dag er kommet på bedre tanker. De tvivler nu på deres eget scripts anvendelighed. Det er gået op for forfatterne, at scriptet måske endog har gjort mere skade end gavn. I dag er scriptet stemplet: "This document is outdated and the information in it should not be relied upon. It may no longer represent web authoring best practice."
Bob Clary har skrevet en glimrende artikel om problemerne ved traditionel browser-sniffing: Browser Detection and Cross Browser Support. Bob er god, hvad angår overblik, detaljer og anbefalinger men lidt for meget med udgangspunkt i marginale browsere og ekstrem browser-sniffing.
Når en browser er identificeret med producentnavn og versionsnummer, er det egentligt blot at slå browseren op i en tabel for at finde ud af, hvad den kan. Problemet er selvfølgelig, at det er ressourcekrævende og upraktisk, hvis alle webudviklere hver især skal teste alle browsere og systematisere testresultaterne i en tabel. Derfor har bl.a. Microsoft stillet en sådan tabel til rådighed til brug for Microsofts web-servere.
Hvis du benytter Microsofts "Internet Information Services", bliver en sådan tabel ved navn "Browser Capabilities" automatisk installeret. I ASP.NET har Microsoft placeret tabellen med oplysningerne om de mest kendte browsere i en XML-fil med navnet "machine.config", en XML-fil der også bruges til meget andet. På min egen web-server, "local host", på min private computer med Windows XP Professionel, ligger den pågældende XML-fil som default i mappen:
C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\CONFIG\
I ASP.NET er der en såkaldt "klasse", et "objekt", der giver programmøren adgang til alle oplysningerne om de kendteste browsere i XML-filen "machine.config". Anvendes "klassen" bliver browseren først automatisk identificeret ved hjælp af "User agent", og derefter slås browserens egenskaber op i "Browser Capabilites".
Jeg har lavet noget kode, der udskriver oplysningerne om din browser i en tabel, som der linkes til i artiklens indholdsfortegnelse.
Det gode ved oplysningerne i "Browser Capabilities" er, at hver gang web-serveren bliver opgraderet, f.eks. når der kommer en ny udgave af ASP.NET, så bliver oplysningerne om browserne samtidigt opdateret med rettelser og med oplysninger om nye browsere. En computer-nørd kan selvfølgelig også selv opdatere xml-filen efter behov og lægge oplysninger om nye browsere ind i xml-filen.
Det problematiske ved "Browser Capabilities" er, for det første, at den som default kun indeholder oplysninger om de mest brugte browsere: Internet Explorer, Netscape, Opera, WebTv, PIE (Microsoft Pocket Internet Explorer) og PowerBrowser. Alle andre browsere er ukendte og returnerer "false" i den viste tabel, dvs. at den pågældende funktionalitet ikke er i browseren!
Www.evolt.org har registreret over 100 browsere. Mange af dem er kommet i flere udgaver og til flere platforme eller styresystemer: browsers.evolt.org/.
Det er et endnu større problem, at "Browser Capabilities" kun er en liste over, hvad en browser kan. Listen fortæller ikke, om brugeren af browseren har slået funktionen til eller fra. Selv om en browser understøtter f.eks. JavaScripts, cookies eller frames, kan brugeren slå understøttelsen fra i browseren.
Det er derfor meget vigtigt at understrege, at "Browser Capabilites", dvs. oplysningerne om, hvad en browser kan på papiret, selvfølgelig er bedre end ingen ting, men at oplysningerne må tages med forbehold. Dels fordi kun de mest udbredte browsere er registreret, dels fordi brugeren af browseren kan slå funktionaliteten til og fra.
Alle nyere browsere har en række browser-objekter, der indgår i en såkaldt "BOM", "Browser Object Model", der desværre er unik for de enkelte browserfabrikater, og som løbende udvikles fra version til version. Objekterne har værdier, der kan aflæses eller metoder, der kan bruges af scriptene "client-side" på websiden i browseren. Heldigvis hedder de fleste objekter det samme og anvendes på samme måde på tværs af browserne.
I tabellen "Din browser detektet server-side og client-side", som der linkes til fra artiklens indholdsfortegnelse, vises eksempler på browser-objekter. Navigator-objektet indeholder de samme oplysninger som http-headeren "User agent". Mere interessant er objekter, der kan fortælle os (dvs. websiden) om skærmens opløsning og browservinduets højde og bredde. Disse værdier skifter selvfølgelig, mens websiden befinder sig i browseren, hvis brugeren skifter skærmopløsning, eller forandrer browservinduets størrelse. Prøv!
Netop browservinduets størrelse er et godt eksempel på forskelligheder i browserne. I Internet Explorer hedder objektet for browservinduets bredde f.eks. "document.body.offsetWidth", og i Netscape hedder objektet "window.innerWidth".
Selv om browser-sniffing altid har og stadig fokuserer på browser-fabrikat og versionsnummer, så har der altid været mange forfattere af websider, der supplerede testning for browserfabrikat og versionsnummer med testning for objekter i browseren. Denne metode byder på mange fordele, men den er ofte utilstrækkelig og kan ikke løse alle problemer.
Lad os illustrere metoden med et eksempel. Lad os antage at et website ønsker at anvende cookies. Hvis browseren ikke forstår cookies, ønsker vi at vise en lidt mindre avanceret webside i browseren. Hvordan griber vi dette problem an?
Den traditionelle metode er at teste på hele rækken af nuværende og mere eller mindre forhistoriske browsere, hvad de hedder, versionsnummer, osv., og derefter at slå dem op i "Browser Capabilities" for at se, om de understøtter cookies, og så krydse fingeren for at brugeren ikke har slået understøttelsen fra. Det er langt lettere at teste om websiden kan gemme og læse cookies på browserens computer.
Det geniale ved at teste på et objekt er, at browser-fabrikat, versionsnummer, og hvad browseren i teorien er i stand til, er irrelevant. Vi interesserer os kun for hvilke objekter, der er slået til, og som er klar til brug i browseren. Problemet med at teste på objekt er, at det ofte kræver stor kreativitet at finde den rette kombination af objekter at teste for, da de skal hedde det samme og fungere på samme måde i de relevante browsere, hvis du ikke vil rode dig ud i yderligere browser-sniffing!
Et af de første objekter, der blev brugt til testning, var "document.images". Hvis testen "if{document.images}" returnerer værdien "true", understøtter browseren grafik. Version 4 af Internet Explorer og af Netscape introducerede hver især mange nye muligheder i browserne. Derfor var det vigtigt at finde objekter, der kunne identificere disse browsere.
I IE4 var objektet "all" med for første gang. Objektet "all" indeholder blot en liste over alle objekter, en liste der mig bekendt ikke kan bruges til noget som helst. Derfor har ingen andre browsere et tilsvarende objekt. Men fordi objektet "all" kun anvendes af Microsoft og kun er med fra og med IE4, er objektet blevet anvendt til at skille nye IE-browsere fra gamle IE-browsere. "All"-objektet er også blevet anvendt til at sortere Opera fra, selv om Opera har identificeret sig som en Microsoft-browser.
Til skræk og advarsel understøtter Opera 7 nu også "ALL"-objektet, udelukkende for ikke at blive uretfærdigt bortvist!
I Netscape 4 var objektet "layer" med for første gang, bl.a. til brug for DHTML Microsoft og W3C satsede på en ren CSS-løsning til DHTML. Det har Netscape nu bøjet sig for, og fra og med Netscape 6 understøttes i stedet "W3C DOM" (Document Object Model) til brug for DHTML. Netscape understøtter ikke længere "layer". Det betyder, at vi kan bruge "layer"-objektet til at identificere en Netscape 4. Hvis testen "if{document.layers} returnerer "true", er der tale om Netscape 4.
Testning for objekter er selvfølgelig mest interessant, når den som i eksemplet med cookies kan anvendes i stedet for at teste på browserfabrikat og versionsnummer. Men det kræver kreativitet fra programmørens side, og det er ikke altid muligt at finde en brugbar løsning. Det er objektet "W3C DOM" et eksempel på.
Det hævdes ofte fejlagtigt, at hvis web-programmørerne blot følger W3C's standarder og f.eks. validerer websiderne i W3C's validator online, og kun bruger f.eks. "W3C DOM", hvad angår DHTML, så vises websiderne perfekt i alle browsere, der også følger standarderne. Problemet er, at standarder altid skal fortolkes og implementeres, og at der kan gå mange år før browserne fortolker og implementerer standarderne på samme måde.
Dynamiske menuer er et godt eksempel. De blev først mulige fra og med IE4 og NC4, der brugte hver sin metode til at understøtte dem. Man er i praksis nødt til at lave to forskellige menuer, teste om browseren er IE4+ eller NC4 eller noget helt tredje. Det er dog muligt at lave en dynamisk menu som både IE4+ og NC4 kan anvende, men det kræver klodset og usund programmering, hvor man skjuler de lukkede menuer ved at positionere dem uden for skærmen!
Både IE6, NC6 og Opera7 påstår, at de understøtter "standarderne", f.eks. "W3C DOM". Det gør det muligt at teste på f.eks. if(document.getElementById), der returnerer "true" eller rettere "object", hvis "W3C DOM" understøttes. I praksis vil der dog gå mange år, før en sådan testning kan bruges til noget for alvor. Lad os prøve at illustrere, hvor meget detektion af browser, der er nødvendig, hvis vi laver en dynamisk menu i DHTML.
Bruger vi "W3C DOM" virker den dynamiske menu ikke i tidligere udgaver af Internet Explorer, Netscape og Opera eller for den sag skyld i nogen anden browser. Metoderne fra IE4, IE5 og IE5.5 virker stadig i IE6, der endog accepterer, at de gamle og de nye metoder blandes sammen! IE6 accepterer endog, at den ny "W3C"-syntaks forkortes, så den fylder lidt mindre. NC6 forstår ikke længere den gamle metode fra forrige udgave af Netscape, og "W3C DOM" skal være 100 pct. striks for at virke i NC6.
Det bliver ikke bedre af, at Microsoft har udvidet "W3C DOM" på et par punkter, som næsten alle programmører er enige om er så fornuftigt, at "W3C" bør tage det med i standarden, og som det er fristende allerede nu at anvende, fordi det virker i IE6, der har en stor markedsandel. Der er også det problem, at Microsoft og Netscape stadig er uenige om fortolkningen af dele af standarden. De dele af standarden skal altså stadig kombineres med browser-sniffing. Opera 7 understøtter som sagt også "W3C DOM", men vi bliver sikkert alligevel nødt til yderligere noget Opera-relateret browser-sniffing for også at få denne browser med på vognen. Og hvad stiller vi op med browsere, der er ældre end IE4 og NC4, eller som er af andet fabrikat end de nævnte?
Som sagt er browsernes erklæringer om at ville understøtte W3C-standarderne et kæmpe skridt fremad, men på kort sigt løser det ingen problemer.
Det er problematisk at identificere browsere, at finde ud af hvad de kan, om funktionaliteten er slået til eller fra, og i praksis at optimere websiderne til den identificerede browsers formåen. Browser-sniffing vil dog altid være nødvendig. Selv hvis der kun eksisterede én platform, ét styresystem og én browser, vil styresystem og browser fortsat udvikle sig og komme i nye versioner, der introducerer ny eller forbedret funktionalitet.
Specielt er browser-sniffing med det formål at supportere browsere med marginale markedsandele dybt problematisk. Det er ressourcekrævende og frustrerende for webudviklere. For hver ny marginal browser, der serviceres, bliver websiderne mere komplekse og vanskeligere at vedligeholde og videreudvikle.
Det ironiske er, at browser-sniffing for at supportere marginale browsere ofte fører til udelukkelse af andre browsere, og at browser-sniffing i den virkelige verden i langt højere grad end f.eks. Microsoft har lagt en dæmper på konkurrencen. Opera og andre marginale browsere kæmper stadig en hård kamp for overhovedet at komme ind på websites på grund af vidt udbredte forkerte strategier for browser-sniffing, der diskriminerer mod nye eller sjældne browsere.
Browseren Opera er et interessant case. Det er fantastisk hvad denne browser bruger at tricks for kunne snige sig uden om diskriminerende browser-sniffing. Vi har tidligere nævnt, at Opera 7 identificerer sig både som IE 5.5, IE6 og som Opera 7 for at være på den sikre side. Opera 7 understøtter nu også på skrømt Microsofts "all"-objekt, så det ikke længere kan anvendes til at diskriminere imod Opera.
Enhver seriøs alternativ browser er imod browser-sniffing, fordi browser-sniffing i stedet for at hjælpe nye browsere tværtimod stiller dem ringere end Internet Explorer eller Netscape. Opera og andre alternative browsere nærmest tikker og beder os om at blive behandlet som følger (mine formuleringer):
"Vis mig de samme sider, som I viser til den nyeste Microsoft-browser! Hvis der er småfejl i visningen, så er det min pligt at rette fejlene. Jeg vil rette fejlene, og jeg vil sørge for, at mine kunder får en opgraderet browser. Hvis nogle af mine kunder bruger en ældre udgave af browseren, så skal disse kunder også se de websider, som I sender til den nyeste Microsoft-browser. Hvis resultatet i browseren er en katastrofe, er det mit problem og ansvar. Jeg skal nok sørge for, at kunden bliver opgraderet til den nyeste browser."
Sådan skal holdningen til browserne være, hvis vi ønsker af fremme konkurrencen på browsermarkedet, hvis vi ønsker at holde konkurrencen åben for nye browsere. Browser-sniffing er kontra-produktiv i enhver henseende, fordi den i praksis styrker tendensen til monopolisering.
Browser-sniffing er godt til mange ædle formål, f.eks. til at skelne mellem WebTV, traditionelle computere og trådløse enheder. Browser-sniffing kan også bidrage til at optimere websiderne til forskellige skærmopløsninger og vinduesbredder. Men browser-sniffing med det formål at skelne mellen browserfabrikater og versionsnumre gør ofte mere skade end gavn. Den ideelle løsning er helt at undlade denne type browser-sniffing.
Det er dog urealistisk helt at droppe detektion af browsere for at kunne supportere flere browserfabrikater og versionsnumre. Ofte må vi tage til takke med næstbedste eller tredjebedste løsning, fordi det er for ressourcekrævende at overbevise flertallet om sandheden. Offentligheden har det svært med komplekse problemstillinger, når man uden videre kan få opbakning til letfattelige slagord.
Hvis du derfor bliver tvunget til proprietær browser-sniffing, fordi du ikke har tilstrækkeligt med is i maven, så gør det på en måde, der er til mindst mulig skade for brugerne, for browser-fabrikanterne, og for dig selv som forfatter af websider.
Som tommelfingerregel er browser-sniffing kun rationel til en vis grænse, der i dag synes at ligge på ca. 90-95 pct. af markedet. Bevæger vi os ud over denne grænse bliver det ressourcemæssigt urealistisk at optimere visningen til yderligere et par procentpoint marginale browsere, der uundgåeligt bliver spist af med en mindste fællesnævner, som hverken brugerne, browserfabrikanterne eller forfatterne af websider kan være tjent med.
Det er altid i alles interesse at opmuntre brugerne til hurtigst muligt at opgradere til nyeste browser. Brugerne får en bedre oplevelse, og opgraderingen lukker kendte sikkerhedshuller i browseren. Browserfabrikanterne undgår at skulle servicere forældet teknologi, som ingen interesserer sig for eller ikke burde interessere sig for. Forfatterne af websider sparer udviklingsressourcer på bagudkompatibilitet og browser-sniffing. I betragtning af at de fleste browsere er gratis og kun koster tiden, det tager at installere dem, findes der ikke ét eneste argument for holde liv i forældede browsere fra forrige årgang.
Det er i længden et helt uacceptabelt spild af ressourcer, at tusinder af webudviklere over hele verdenen bruger millioner af arbejdstimer på at tilpasse uendeligt mange websider til et par marginale browsere. Det er smartere, at et par browserproducenter i stedet bruger et par timer på at rette et par bugs eller på at forandre lidt ved et browserobjekt.
Det skal være slut med at bruge sparsomme udviklingsressourcer på selv-marginaliserede pseudo-minoriteters luksusproblemer. De har uhindret adgang til Internettet. Overalt på træerne hænger der gratis browsere, der giver adgang. Browsere kan downloades gratis fra nettet eller installeres fra CD'en i et computerblad.
Lad os satse de sparsomme udviklingsressourcer på de reelle problemer med tilgængelighed. Lad os åbne nettet op for vore medmennesker med funktionsnedsættelser, der i dag ikke har adgang eller kun vanskeligt har adgang, og som ikke har noget alternativ. Blinde med skærmlæsere, folk der har brug for at kunne sætte tekststørrelsen op i browseren, folk der skal kunne navigere med tastaturet alene på grund af problemer med musen.
Mange mennesker har brug for mere brugervenlige og tilgængelige hjemmesider for at kunne anvende Internettet. Her har vi et reelt adgangsproblem. Forældede browsere og marginaliserede browsere er derimod ligyldigt som adgangsproblem, fordi disse browseres brugere stadig har fri adgang med mange andre browsere.
Copyright © 2002 Klapmusen.dk
The document is made to be a resource. Use it. Link to it. The document will be maintained, the URL is stable.
Opdateret: 15-01-2003 14:53
Status:
Revision:
Debatten er lukket. Send mig en mail.