Assoluto ma non vuoto, rendering bug CSS in Android legacy e come fixarlo

Cosa significa “Absolute”

Iniziamo con una premessa sul termine principale di quest’argomento, dato che come molte cose in ambito CSS i nomi possono essere ambigui in vari modi. Prima cosa  position: absolute;  non significa “assoluto” come lo si intende nel linguaggio naturale, ovvero non accade che un elemento con questa proprietà cessa di essere vincolata a qualsiasi cosa, conviene quindi guardare all’origine latina della parola:

ab + solutus = sciolto da

Quindi da cosa viene slegato esattamente l’elemento? Viene slegato dal contesto del flusso dei contenuti, quello che tutti gli elementi posseggono quando vengono renderizzati sulla pagina e non viene specificato un valore per la proprietà  position , il cui valore predefinito è  static, basato sul punto in cui i tag sono dichiarati nel sorgente HTML.

Ingombro e Coordinate di un elemento

Dato che l’origine delle coordinate di ogni elemento si generano dall’angolo in alto a sinistra del render-box e si espandono verso il basso a destra, le proprietà che regolano la posizione e spostano un elemento rispetto al suo box, così come le proprietà e valori dipendenti dal contesto come i valori in percentuale nella proprietà  height o simili, che sono  toprightbottom e left in base al valore applicato alla proprietà  position si riferiranno a:

  • static: nulla, l’emento non si sposterà
  • relative: i bordi esterni dell’elemento stesso, l’ingombro sulla pagina rimane inalterato
  • absolute: i bordi del primo antenato con valore  position diverso da  static
  • fixed: i bordi del viewport visibile

Sia con  absolute che  fixed l’elemento viene effettivamente rimosso dal normale flusso dei contenuti e tutti gli elementi circostanti a cui precede nel codice refluiscono come se l’elemento fosse stato cancellato e non produce più ingombro.

C’è tuttavia ancora un altro comportamento da constatare con  absolute, ovvero che se nessuna proprietà che modifica la posizione viene applicata, il render-box dell’elemento inizia a spostarsi verso l’alto, come un palloncino a cui viene tagliato il filo e inizia a volare via finché non viene fermato dal soffitto, e il punto d’origine delle sue coordinate andrà ad appoggiarsi al primo elemento che possiede un proprio ingombro sulla pagina, ovvero un elemento block-level non flottato, che potrebbe essere uno degli elementi fratelli oppure il bordo superiore del contenitore padre se incontra nulla sul suo cammino.

Quindi diciamo di avere quattro elementi block-level, tre dei quali hanno del contenuto, il secondo no e vogliamo spostare il terzo sopra il quarto:

quindi applichiamo  position: absolute; sul terzo elemento arancione spostandolo rispetto alla seconda riga invisibile che è spinta verso il basso dalla prima rossa, così da sovrapporlo al quarto elemento rosa.

A questo punto è possibile spostare l’elemento arancione rispetto alla sua posizione attuale con la proprietà  margin che lo sposterà rispetto all’origine delle sue coordinate, così come farebbe anche in casi di  position: static; solo che essendo ora al di fuori del normale flusso dei contenuti non influenzerà nient’altro che se stesso a partire dalla sua nuova posizione corrente.

Tutto ok, finché non provi la pagina sullo stock browser di Android

Purtroppo, molti dispositivi entry-level Android sia tablet che telefoni hanno ancora preinstallata la famigerata app Internet che utilizza delle versioni legacy di webkit, e la versione è diversa a seconda della data di messa in commercio, non viene mai aggiornato e in modo o nell’altro bisogna conviverci.

Su questi motori di rendering, se il prima menzionato parente block-level è vuoto, questo sarà ignorato e l’elemento spostato tramite margini risulterà mal posizionato, e nessun  force-repeaint tramite  display risolverà la situazione dato che è il punto di riferimento per calcolare il paint che è diverso, ma la situazione può essere risolta in due modi.

Bug in azione, il terzo elemento arancione invece di posizionare l’origine delle sue coordinate contro il secondo elemento invisibile, si aggancia al primo rosso

Applicare la posizione via JS

Se la proprietà  position: absolute; viene applicata a runtime via JS dopo il primo rendering all’atterraggio con un altro o nessun valore, in questo caso per qualche misterioso motivo prenderà di nuovo in considerazione anche l’elemento vuoto come in tutti gli altri motori di rendering, tuttavia utilizzare un hack JS per gestire un quirck CSS sembra un po eccessivo, sopratutto se esiste un alternativa CSS come in questo caso.

Generare dello pseudo contenuto sul parente vuoto

Dato che il problema è determinato dall’elemento completamente vuoto, possiamo fornirgli del contenuto temporaneo tramite pseudo selettore and pseudo contenuto per ingannare il motore di rendering:

sarebbe possibile usare il selettore universale  * per non doversi preoccupare di altre occorrenze ma potrebbe avere degli effetti collaterali sul layout, e dato che retro selettori non ne esistono l’unico modo è individuare gli elementi incriminati e trattarli in maniera puntuale.

Un altra variante della fix può essere l’uso del selettore direct-child o comunque restringere l’azione del selettore a categorie circoscritte di elementi in un contenitore, in modo da poter gestire situazioni con contenitori variabili o contenuti dinamici, oppure ancora nel caso in cui manchino degli ID a cui fare riferimento, in modo da ridurre potenziali effetti collaterali su altre parti della pagina il più possibile.

https://sresc.io/tMC

Lascia un commento

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.