Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Position fixed performante su IE6

Implementare nel modo più opportuno il posizionamento fisso sul browser di Microsoft
Implementare nel modo più opportuno il posizionamento fisso sul browser di Microsoft
Link copiato negli appunti

Tra i vari tipi di posizionamento, quello che presenta più criticità a livello di crossbrowsing è sicuramente il position: fixed. Infatti, il valore fixed per questa proprietà è supportato da Internet Explorer solo a partire dalla versione 7.

Normalmente per emulare questo tipo di comportamento anche sulle versioni meno recenti di Internet Explorer vengono utilizzati alcuni workaround (in CSS e/o Javascript), ciascuno dei quali presenta diverse controindicazioni e che non dovrebbero essere quindi implementati: vediamone alcuni.

Modifica dell'overflow globale

Questa soluzione è realizzata mediante i soli CSS (ne esistono diverse varianti) e prevede di eliminare l'overflow sull'elemento root per assegnarlo ad un discendente con altezza al 100%, ad esempio:

html {
  _overflow-y  : hidden; (underscore hack per IE6 e precedenti)
}

body {
  _overflow    : auto;
  _height      : 100%;
}

In questo modo l'elemento deputato allo scrolling della pagina diventa diventa il <body> e, come conseguenza, gli elementi posizionati assolutamente restano in posizione fissa rispetto al viewport. Ciò comporta ovviamente l'impossibilità di utilizzare elementi in position: absolute nel modo consueto.

Oltre a questo problema, al ridimensionamento della finestra browser la scrollbar verticale potrebbe non essere più visibile (si verifica ad esempio in questa pagina non appena compare quella orizzontale).

CSS expressions

Il metodo in questione, di cui è disponibile un esempio approfondito, prevede di inserire delle espressioni Javascript tra le regole dei CSS. Questo tipo di soluzione, sebbene funzionante, è assolutamente da evitare poiché:

  1. per ovvi motivi legati alla manutenibilità e alla duplicazione del codice, Javascript (comportamento) non dovrebbe trovarsi insieme a codice CSS (presentazione). Inoltre le coordinate di partenza dell'elemento sono hardcoded nell'espressione;
  2. un uso scorretto delle espressioni Javascript nei CSS può causare pesanti rallentamenti nel rendering della pagina, nel reflow degli elementi (il loro riposizionamento dovuto allo scrolling) e in casi più estremi si può arrivare al crash del browser stesso.

Javascript

In questo caso il posizionamento fixed è realizzato attraverso dei setInterval() sul controllo delle proprietà scrollTop/scrollLeft del documento per determinare lo scroll della pagina e delle proprietà clientHeight/clientWidth per intercettare eventuali ridimensionamenti del viewport.

Tale metodo è tuttavia inefficiente e determina in certi casi la quasi paralisi del browser, dovuta ai controlli temporizzati che vengono eseguiti continuamente nell'arco di pochi millisecondi. Inoltre ciò comporta di dover comunque includere uno script aggiuntivo (seppure solo per IE6 e inferiori).

Un approccio alternativo

L'idea alla base della soluzione ottimale dovrà quindi tenere conto delle problematiche incontrate finora, ovvero dovremo evitare:

  • lo spostamento dell'overflow su body (o altri elementi);
  • l'impossibilità di usare altri tipi di posizionamento;
  • l'impossibilità di usare le scrollbar;
  • CSS expressions nei fogli di stile;
  • codice Javascript potenzialmente bloccante.

Come prima cosa definiamo allora una classe (ad es. fixed) con le seguenti regole:

.fixed {
    position        : fixed;
}

/* IE6 e precedenti */
* html .fixed {
	position	: absolute;
	behavior 	: url("ie-fixed.htc");
}

Oltre a specificare position: absolute definiamo un comportamento (behavior) attraverso un file .htc che eseguirà la funzione definita nell'handler (una sola per volta per elemento e al caricamento della sola struttura del nostro documento).

Ecco il codice del file .htc:

<public:component>
<attach event="ondocumentready" handler="fixedPosition" />
<script type="text/javascript">

function fixedPosition() {

    var i, coord = '';
    var value, style = element.style;
    var currentStyle = element.currentStyle;

    if(currentStyle.position.toLowerCase() != 'absolute'){ return; };

    var position = {
        Top         : currentStyle.top,
        Right       : currentStyle.right,
        Bottom      : currentStyle.bottom,
        Left        : currentStyle.left
    };

    var offw = element.offsetWidth;
    var offh = element.offsetHeight;

    for (i in position) {
        value = position[i];
        coord = '';
        if(position[i] == 'auto'){ continue; };

        switch(i) {
            case 'Bottom':
                i = 'Top';
                value = '-' + position.Bottom;
                coord = 'parseInt(document.documentElement.clientHeight, 10) - ';
                coord += (parseInt(currentStyle.height, 10) || offh) + ' + ';
                break;

            case 'Right':
                i = 'Left';
                value = '-' + position.Right;
                coord = 'parseInt(document.documentElement.clientWidth, 10) - ';
                coord += (parseInt(currentStyle.width, 10) || offw) + ' + ';
                break;
        };

        style.setExpression(
            i.toLowerCase(),
            '(parseInt(document.documentElement.scroll'+ i + ', 10) + ' +
            coord + parseInt(value, 10) + ')' + ' + "px"'
        );

    };

};
</script>
</public:component>

La funzione fixedPosition() controlla che il posizionamento dell'elemento sia effettivamente 'absolute', legge i valori delle eventuali proprietà top, right, bottom e left (se definite) e le informazioni sulle dimensioni dell'elemento stesso:

    ...

    if(currentStyle.position.toLowerCase() != 'absolute'){ return; };

    var position = {
        Top         : currentStyle.top,
        Right       : currentStyle.right,
        Bottom      : currentStyle.bottom,
        Left        : currentStyle.left
    };

    var offw = element.offsetWidth;
    var offh = element.offsetHeight;

    ...

Se si definisce il posizionamento dell'elemento, usando left e top le coordinate di partenza saranno semplicemente date dalle coppia (left, top): ma se ad esempio volessimo posizionare un elemento alto 100px a 10px dal fondo (bottom: 10px) in un viewport alto 450px, la coordinata y in questo caso sarebbe definita da:

  • altezza della finestra;
  • altezza dell'elemento;
  • distanza dal bordo inferiore del viewport.

Questa somma algebrica tradotta in proprietà Javascript diventa:

    document.documentElement.clientHeight
    - currentStyle.height || offh /* (offh è l'offsetHeight dell'elemento) */
    - bottom

ovvero 450 - 100 - 10 = 340px. Il discorso è analogo per il calcolo della coordinata x usando la proprietà right. Così facendo il posizionamento degli elementi diventerà dipendente unicamente dalla distanza calcolata rispetto all'angolo (0, 0) del viewport.

    ...
    switch(i) {
        case 'Bottom':
            i = 'Top';
            value = '-' + position.Bottom;
            coord = 'parseInt(document.documentElement.clientHeight, 10) - ';
            coord += (parseInt(currentStyle.height, 10) || offh) + ' + ';
            break;
    ...

Una volta definite le coordinate di partenza di ciascun elemento con classe .fixed, sarà sufficiente definire un'espressione che tenga conto dello scrolling di pagina (scrollTop e scrollLeft) e che dinamicamente ricalcoli la posizione dell'elemento.

Inoltre l'espressione stessa considererà anche eventuali ridimensionamenti del viewport poiché la variabile coord, essendo definita attraverso le proprietà clientHeight e clientWidth (ed essendo all'interno di una setExpression), sarà costantemente ricalcolata.

 style.setExpression(
    i.toLowerCase(),
    '(parseInt(document.documentElement.scroll'+ i + ', 10) + ' +
    coord + parseInt(value, 10) + ')' + ' + "px"'
);

La prima pagina di demo così costruita presenta diversi elementi posizionati in modo differente. Si noti però che, scrollando il documento, gli elementi subiranno un lieve spostamento. Per evitare questo fastidioso effetto sarà sufficiente aggiungere questa regola css (valida per IE6 e precedenti):

* html {
	background	: url(0) fixed;
}

Come si può notare dall'ultima demo, gli elementi ora restano perfettamente fermi nella loro posizione. Per controllare la sovrapposizione è sufficiente agire sulla proprietà z-index su ciascun elemento ricordando che, di default, gli elementi definiti per primi nel codice XHTML si posizioneranno al di sotto di quelli definiti per ultimi.

Il componente è stato testato con successo in pagine XHTML 1.0 strict sia su IE6 di sistema che su quelli emulati (tredosoft e xenocode).

Il codice e gli esempi sono disponibili per il download.

Ti consigliamo anche