CSS: test e debugging nel 2007

CSS: test e debugging nel 2007

Quello che segue è un mio articolo sui test ed il debugging con i CSS pubblicato nel 2007. Rappresenta un esempio di come si doveva procedere in quei tempi.

Introduzione

Nella realizzazione di layout con i CSS molto spesso ci si imbatte in problemi di visualizzazione più o meno gravi sui browser. In questi casi è necesssario saper ricreare le condizioni iniziali in cui si è verificato il problema al fine di ottenere il layout desiderato, o comunque un compromesso accettabile. Prima di intraprendere qualsiasi tentativo in questo senso è bene assicurarsi che il nostro codice CSS e (X)HTML sia valido. Solo così saremo certi che il problema non deriva da errori sintattico-grammaticali. Fatto questo, possiamo procedere con la costruzione di test veri e propri.

Riconoscimento di proprietà, selettori e valori

Un test fondamentale riguarda il riconoscimento di selettori, proprietà e valori da parte dei browser. Per effettuare questo tipo di test occorre:

  1. conoscere l'esatta sintassi dei selettori
  2. conoscere l'àmbito di applicazione dei valori
  3. conoscere l'esatta sintassi delle proprietà e il loro àmbito di applicazione.

Cominciamo con un semplice esempio:


p + p {text-indent: 1em;}

Il selettore del fratello adiacente seleziona un elemento solo se questo segue immediatamente un altro elemento nel sorgente. Se tra i due paragrafi vi fosse stato un altro elemento, lo stile non sarebbe stato applicato.

Passiamo ad un esempio più complesso:


h1 + div.post > blockquote[cite] {font-style: italic;}

In questo caso vengono usati in successione un selettore del fratello adiacente, un selettore di classe, un selettore del figlio e un selettore di attributo semplice. Lo stile viene applicato solo se:

  1. l'elemento ha un attributo cite impostato
  2. l'elemento è figlio di un elemento div con classe .post
  3. l'elemento div con classe .post segue immediatamente l'elemento h1 nel sorgente.

Se una delle condizioni sopra elencate non viene soddisfatta, il test fallirà, anche se il browser supporta tutti i selettori usati. Si potrebbe a questo punto rendere ancor più complesso il nostro test scrivendo:


body[id="sito"] > h1 + div.post > blockquote[cite] + p[class~="nota"] {
color: #f00;
}

In questo caso vengono usati in successione un selettore di valore esatto di attributo, un selettore del figlio, un selettore del fratello adiacente, un selettore di classe, un secondo selettore del figlio, un selettore di attributo semplice, un secondo selettore del fratello adiacente e un selettore di valore parziale di attributo.

L'elemento riceverà lo stile assegnato solo se:

  1. uno dei valori dell'attributo class corrisponde a nota
  2. segue immediatamente un elemento blockquote con l'attributo cite impostato
  3. l'elemento blockquote è figlio di un elemento div con classe .post
  4. l'elemento div con classe .post segue immediatamente l'elemento h1
  5. l'elemento h1 è figlio dell'elemento body
  6. l'elemento body ha un attributo id il cui valore corrisponde a sito.

Se una delle condizioni sopra elencate non viene soddisfatta, il test fallirà, anche se il browser supporta tutti i selettori usati.

Un altro tipo di test richiede la conoscenza esatta dell'àmbito di applicazione dei valori. Esempio:


span.box {margin: 1em 0.5em;}

In questo caso vengono ignorati i valori dei margini verticali dell'elemento nel computo della sua altezza, in quanto tali valori non si applicano agli elementi inline.

Si può procedere in modo analogo anche per la sintassi e l'àmbito di applicazione delle proprietà. Esempio:


#box {
float: left;
width: 200px;
margin: 0;
vertical-align: middle;
}

L'ultima dichiarazione viene ignorata, in quanto la proprietà vertical-align si applica solo agli elementi inline e alle celle di tabella.

Infine, bisogna considerare il ruolo della cascata e della specificità nell'applicazione di uno stile. Ad esempio:


* {color: red}
p {color: green}
p:first-line {color: blue}
body p {color: navy}
body h1 + p {color: black}
body p.box {color: olive}
#item {color: purple}

In questo caso l'ultima dichiarazione vince sulle precedenti, in quanto ha la specificità maggiore (a=0, b=1, c=0, d=0).

Bug e anomalie

I problemi di visualizzazione nei browser si dividono sostanzialmente in due categorie: bug e anomalie. I bug sono interpretazioni errate, e non previste dalle specifiche, delle dichiarazioni dell'autore. Esempio:


.float {
float: left;
margin: 0 1em 0 2em;
width: 200px;
}

In questo caso Internet Explorer Windows (versioni 6 e 5) raddoppierà il margine sinistro del float. Le anomalie sono invece delle interpretazioni differenti, e previste dalle specifiche, delle dichiarazioni dell'autore. Esempio:


p:first-letter {
float: left;
width: 3em;
font-size: 3em;
padding: 5px;
margin: 0 0.1em 0 0;
border: 1px solid #000;
}

La visualizzazione del capolettera sarà diversa da browser a browser, in particolare in Opera. Sia nel caso dei bug che delle anomalie, è possibile risolvere i problemi usando delle soluzioni esistenti o aggirando l'ostacolo tramite un approccio diverso. Nel caso del bug di Explorer è sufficiente aggiungere la dichiarazione display: inline al float, mentre nel caso del capolettera possiamo usare un elemento span in luogo dello pseudo-elemento :first-letter.

Quando invece ci troviamo di fronte ad un layout complesso, la prima cosa da fare è effettuare un test sul posizionamento:


* {border: 1px solid red}

Assegnando ad ogni elemento della pagina un bordo visibile verifichiamo lo spazio esistente tra gli elementi, al fine di fugare ogni dubbio su possibili sovrapposizioni. A questo punto controlliamo il risultato nei vari browser. Se il risultato non è uniforme, il bordo che abbiamo impostato ci aiuterà a quantificare il divario esistente. Dovremo quindi tenere in considerazione le seguenti proprietà e i loro valori:

  • margin
  • border
  • padding
  • width
  • height
  • float
  • top|right|bottom|left

Ora dobbiamo stabilire se le dimensioni sono corrette, ricordando le due formule standard per il calcolo della larghezza e dell'altezza di un blocco contenitore e tenendo sempre presente le debite differenze tra elementi inline, di blocco e rimpiazzati:

  • larghezza = 'right' + 'margin-right' + 'border-right-width' + 'padding-right' + 'width' + 'padding-left' + 'border-left-width' + 'margin-left' + 'left'
  • altezza = 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom'

Ovviamente se stiamo lavorando con Internet Explorer 5 ed Internet Explorer 6 in quirks mode dobbiamo tenere presente che il loro box model è errato, in quanto ogni dichiarazione di larghezza/altezza comprenderà anche le eventuali dichiarazioni di margine, bordo o padding.

Un altro fattore è rappresentato dal collassamento dei margini verticali degli elementi di blocco. Explorer 6 e 5 presentano dei problemi nel computo di tali margini, specie quando gli elementi si trovano all'interno di un contenitore privo di dimensioni. Di solito Explorer tende a contrarre lo spazio verticale, quindi si è spesso costretti ad usare il padding in luogo dei margini o a dare un valore superiore solo ad Explorer tramite i commenti condizionali. Esempio:


body {margin: 0; padding: 0;}
#box {width: 50%; margin: 2em 0;}

Per ottenere lo spazio voluto ed impedire che Explorer visualizzi l'elemento senza uno spazio inferiore dovremo scrivere:


body {margin: 2em 0; padding: 0;}
#box {width: 50%; margin: 0;}

ossia sfruttare i margini verticali dell'elemento genitore. Anche la teoria sugli schemi di posizionamento gioca un ruolo determinante nel debugging e nei test. Per esempio, ci si potrebbe stupire del comportamento prodotto da un codice come questo:


#header {border-top: 0.5em solid #333; border-bottom: 1em solid #333;}

#nav {
float: left;
width: 50%;
margin: 0;
}

#search {
float: right;
width: 40%;
margin: 0;
}

In questo esempio vedremo collassare lo spazio verticale all'interno di #header, i cui bordi verticali si troveranno sopra gli elementi #nav e #search al suo interno. Questo avviene perché l'elemento contenitore non ha un'altezza esplicita, e quindi non riesce a contenere i float.

Ci si potrebbe anche stupire, data la seguente struttura (X)HTML:


<div id="header">...</div>
<div id="nav">...</div>

e il seguente CSS:


#header {height: 2em; margin: 0;}

#nav {
position: absolute;
top: auto;
left: 0;
width: 20%;
margin: 0;
}

di veder comparire il secondo elemento esattamente sotto al primo. Il valore auto dato alla proprietà top fa si che l'elemento posizionato si comporti in modo statico, seguendo l'elemento che lo precede nel sorgente. Tutte queste peculiarità devono esserci note prima di affrontare il debugging di un layout, evitando così di perdere tempo dietro problemi banali. A volte (o spesso) purtroppo anche queste conoscenze si rivelano insufficienti e occorre quindi procedere per tentativi, escludendo via via quelle proprietà e quei valori che non sortiscono effetto.

Mi è capitato di recente di dovermi occupare del fastidioso problema del supporto di Internet Explorer alle immagini di sfondo per gli elementi inline. Anche se le specifiche non definiscono il problema, i browser hanno assunto come punto di riferimento l'area di padding dell'elemento. Ma Internet Explorer in molti casi non visualizza affatto queste immagini, specie quando gli elementi si trovano all'interno di righe di un blocco di testo. Poichè so che Explorer ha spesso bisogno di una dimensione per gli elementi, ho usato la seguente soluzione:


a.ext:link, a.ext:visited {display: inline-block; height: 10px;}

Il valore inline-block ci permette di mantenere la formattazione inline e al contempo di dare una dimensione all'elemento. In questo caso l'altezza corrisponde all'altezza dell'immagine di sfondo. Usando i commenti condizionali ci assicuriamo che solo Explorer legga queste dichiarazioni.

Concludendo, l'uso dei test ai fini di debugging è un ottimo modo per (1) aumentare le nostre conoscenze e (2) risolvere in modo autonomo i problemi nel layout con i fogli di stile.

Torna su