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

Un layout in stile Pinterest

Tecniche diverse per realizzare griglie responsive (pure CSS e CSS+JavaScript) e superare i limiti dei float
Tecniche diverse per realizzare griglie responsive (pure CSS e CSS+JavaScript) e superare i limiti dei float
Link copiato negli appunti

Il layout del popolare social network Pinterest ha delle peculiarità che hanno immediatamente attirato l'attenzione di designer e sviluppatori, al punto che "layout in stile Pinterest" è diventata l'espressione d'uso più comune per indicare quella specifica soluzione.

Le caratteristiche di un "layout in stile Pinterest"

Ma quali sono le caratteristiche di un "layout in stile Pinterest"? Possiamo così sintetizzarle:

  • un elemento contenitore possibilmente adattabile a diverse risoluzioni di schermo;
  • al suo interno una serie di item ad altezza variabile e non prevedibile in partenza con una struttura identica, con immagini, testo o misti;
  • gli item sono disposti su righe e colonne dinamiche andando a formare una sorta di griglia in cui non vi siano gap irregolari in termini di spazio nella disposizione verticale, ovvero nelle colonne.

In questa breve descrizione il fattore chiave è rappresentato dal riferimento all'altezza variabile e non prevedibile in partenza degli item. Se gli elementi che compongono la griglia, infatti, avessero larghezza e soprattutto altezza fisse, basterebbe organizzare il layout con le tecniche più tradizionali, si tratti dei float o di inline-block, per ottenere il risultato desiderato. Vediamo con un esempio perché i float non funzionano in questo scenario.

Il markup HTML

In tutte le nostre demo useremo un identico markup HTML. Un elemento contenitore racchiude una serie di box con un'immagine e una breve didascalia. Le immagini hanno altezza variabile, fattore che va ad influenzare ovviamente l'altezza dei box stessi.

<div id="container">
  <div class="item">
	<img src="1.jpg" class="scala">
	<div class="titolo"><h6>Item 1</h6></div>
  </div>
  <div class="item">
	<img src="2.jpg" class="scala">
	<div class="titolo"><h6>Item 2</h6></div>
  </div>
  <div class="item">
	<img src="3.jpg" class="scala">
	<div class="titolo"><h6>Item 3</h6></div>
  </div>
  <!-- [...] -->
</div>

Soluzione con i float

Nel CSS della prima demo abbiamo così definito il contenitore e gli item al suo interno, che risultano semplicemente floattati a sinistra:

#container
{
	padding: 20px;
	max-width: 1350px;
	margin: 0 auto;
}
.item
{
	background: #fefefe;
	border: 2px solid #fafafa;
	box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4);
	width: 250px;
	margin-bottom: 10px;
	margin-right: 10px;
	float: left;
}

L'esito non corrisponde a quanto desideriamo ottenere, è evidente. La griglia è tutto tranne che regolare, si creano spazi tra i box che non è possibile controllare proprio per via dell'altezza variabile degli stessi.

Altre soluzioni con i CSS

Se la via dei float è chiaramente non percorribile, si può comunque provare a ricreare il layout alla Pinterest sfruttando altre tecniche basate solo sui CSS.

Flexbox

Una prima alternativa potrebbe essere quella del Flexbox. Questo modulo tanto promettente dei CSS3 sembra fornirci a prima vista tutto quello che ci serve, bastano di fatto pochissime dichiarazioni per sistemare una serie di item uno accanto all'altro su più righe in maniera flessibile, con una gestione ottimale dello spazio disponibile.

Ecco la seconda demo. Nel CSS collegato abbiamo innanzitutto dichiarato la proprietà display: flex sul contenitore, per poi fissare le modalità di configurazione degli item flessibili posti al suo interno (riportiamo qui per comodità solo le proprietà standard senza prefissi):

#container
{
	position: relative;
	padding: 20px;
	max-width: 1350px;
	margin: 0 auto;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	justify-content: space-around;
	align-items: flex-start;
}

Con flex-direction: row impostiamo l'asse principale del flexbox in orizzontale; con flex-wrap: wrap stabiliamo che gli item si disporranno su più righe; la dichiarazione justify-content: space-around imposta l'allineamento orizzontale dei box lasciando uno spazio equamente suddiviso sui lati; align-items: flex-start definisce l'allineamento sull'asse verticale, facendo anche sì che l'altezza degli item collassi adattandosi al contenuto invece che estendersi automaticamente rispetto all'altezza della riga.

Il codice CSS per gli item è pressoché invariato rispetto alla prima demo:

.item
{
	background: #fefefe;
	border: 2px solid #fafafa;
	box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4);
	width: 250px;
	margin-bottom: 10px;
}

In questo caso, non è stato necessario impostare margini a sinistra e destra perché la distanza è gestita in automatico dal flexbox.

Il risultato è certamente migliore rispetto ai float, c'è più ordine, viene rispettata una struttura, il tutto è anche adattabile a larghezze diverse senza usare media query (provate a restringere e allargare la finestra del browser), ma non è esattamente quello che vogliamo. Il problema è che le righe della griglia che viene a formarsi assumono automaticamente come altezza quella dell'item più alto che ospitano, non c'è modo di sistemare i box in modo che riempiano automaticamente gli spazi in verticale in modo da ricreare l'effetto più tipico del layout alla Pinterest.

Layout multi-colonna

Volendo procedere con i soli CSS, la chiave di tutto sembrerebbe essere il modulo per i layout multi-colonna. Di fatto, si tratterebbe di disporre gli item su più colonne per risolvere il problema della spaziatura verticale. La demo più completa e riuscita di questa tecnica è stata presentata da Kushagra Agarwal su CSSDeck. Lo stesso autore ne sottolinea però i limiti: funziona su Internet Explorer solo a partire dalla versione 10, presenta tanti piccoli problemi a livello di resa cross-browser (tutti comunque risolvibili con un pizzico di pazienza), non rispetta in modo preciso l'ordine in cui i box sono dichiarati nel codice HTML.

Vista la completezza dell'esempio originale, ci limitiamo qui solo ad una segnalazione rispetto ad una soluzione certamente funzionante ma forse non troppo robusta.

Soluzioni Javascript

In realtà, per ricreare un layout come quello di Pinterest, le tante soluzioni oggi disponibili si fondano tutte su Javascript. In un modo o nell'altro, è solo con Javascript che il layout può essere impostato nei calcoli necessari per gestire al meglio l'aspetto più problematico: il posizionamento degli item in verticale.

Masonry

Non possiamo qui fare una rassegna completa degli script reperibili in rete. Ci limitiamo a due alternative che illustrano gli approcci possibili alla soluzione del problema. E iniziamo da quella che è per molti l'opzione più nota e solida, la libreria Masonry di David Desandro.

Già nel nome, che fa riferimento ad una struttura fatta di mattoni perfettamente combacianti, è chiaro come questo script faccia al caso nostro. Attraverso Javascript, gli item vengono prima individuati tramite un selettore comune e poi risistemati in forma di griglia sulla pagina con il posizionamento assoluto. Se il contenitore che ospita gli item ha una larghezza espressa in percentuale o comunque non assoluta (dunque anche con max-width), sarà in grado di adattarsi e adattare il suo contenuto al variare della larghezza della finestra ridisegnando ogni volta la struttura della griglia. In tutto questo processo, Masonry può in certi casi modificare l'ordine in cui gli item sono dichiarati nel codice HTML.

La libreria è molto completa e offre un set amplissimo di opzioni e metodi. Qui la useremo in quella che è la configurazione di base.

Ebbene, nella demo abbiamo strutturato come negli altri esempi fin qui visti il markup, con un contenitore e trenta item. Nel CSS li abbiamo così definiti:

#container
{
	padding: 20px;
	max-width: 1350px;
	margin: 0 auto;
}
.item
{
	background: #fefefe;
	border: 2px solid #fafafa;
	box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4);
	width: 250px;
	margin-bottom: 10px;
}

Nel documento HTML, prima di chiudere il body, abbiamo inserito la libreria e le poche righe necessarie all'inizializzazione dello script:

<script src="masonry.pkgd.js"></script>
<script>
var container = document.querySelector('#container');
var msnry = new Masonry( container, {
  // opzioni
  gutter: 10,
  itemSelector: '.item'
});
</script>

Per prima cosa si crea una variabile container che valorizziamo con l'identificativo dell'elemento contenitore (#container); poi si passa alle opzioni che, nel nostro caso, sono appena due. gutter: 10 serve a definire lo spazio tra le colonne, e quindi il margine che separerà gli item a destra e sinistra. Non si tratta di un'unità di misura, non sono 10px, si badi. È solo un numero che imposta un fattore che nella realtà della pagina è destinato a essere dinamico e variabile. Comunque, se si vuole una griglia con tutti gli item uniti, non staccati o separati, si usi gutter: 0.

Con la seconda opzione, itemSelector: '.item', stabiliamo quale debba essere la classe che identifica gli item della griglia. Tutto qui. Visualizzate la demo provando a ridimensionare il browser. Se non volete che la griglia si adatti, basterà usare per il contenitore una larghezza fissa.

La libreria Salvattore

Rimanendo nell'ambito delle soluzioni Javascript, ci soffermiamo in conclusione di questo articolo sulla libreria Salvattore. È un'alternativa valida e basata su un approccio diverso rispetto a Masonry. Vediamo come funziona.

La differenza principale tra le due librerie consiste nel fatto che la configurazione di Salvattore avviene di fatto tramite i CSS, anche se a Javascript spetta il compito di preparare il terreno, se così si può dire. Lo script infatti provvede a creare dinamicamente una serie di colonne all'interno delle quali sistemare e distribuire gli item. Usando le media query possiamo anche far sì che il layout si adatti facilmente a diverse risoluzioni di schermo. Molto più facile far parlare il codice. Ecco la prima demo.

Nel documento HTML dobbiamo compiere due operazioni. Prima di tutto inserire il richiamo alla libreria prima della chiusura del body:

<script src="salvattore.min.js"></script>

Poi, aggiungiamo a livello del tag che definisce l'elemento contenitore l'attributo data-columns, così:

<div id="container" data-columns>

Il resto della configurazione avviene nel foglio di stile. Per prima cosa inseriamo questa regola:

.column { float: left; }

Con essa floattiamo a sinistra gli elementi con classe .column. Questi elementi non esistono in partenza nel nostro markup HTML. Sono le colonne aggiunte dinamicamente dallo script.

Procediamo aggiungendo una serie di classi con cui impostare la larghezza delle colonne (ci serve per perché lavoriamo in una prospettiva responsive). Abbiamo usato il principio di denominazione proposto dagli autori, ma nulla ci impedisce di adottare nomi a nostra scelta:

.size-1of1 { width: 100%; }
.size-1of2 { width: 50%; }
.size-1of3 { width: 33.333%; }
.size-1of4 { width: 25%; }
.size-1of5 { width: 20%; }

Nell'esempio, .size-1of1 {width: 100%;} designa una colonna larga il 100%, che occupa quindi l'intera laghezza del contenitore; .size-1of2 {width: 50%;} indica che le colonne sono larghe il 50%, e saranno di fatto due; .size-1of3 {width: 33.333%;} definisce tre colonne larghe ciascuna 1/3 dell'intera larghezza e così via.

Se non si usano le media query basterà impostare una sola regola per le misure, usando quella che si desidera per la propria configurazione, in base cioè al numero di colonne che vogliamo.

Subito dopo si deve inserire questa regola con cui nascondiamo il contenuto generato con lo pseudo-elemento ::before:

[data-columns]::before
{
	display: none;
}

Infine, passiamo alla parte cruciale, quella con cui passiamo allo script i parametri di configurazione. Essi sono passati come contenuto dello pseudo-elemento ::before, così:

#container[data-columns]::before
{
	content: '1 .column.size-1of1';
}

Specifichiamo come selettore di base l'identificativo del contenitore (#container); valorizziamo poi la proprietà content spacificando il numero di colonne che vogliamo (1) e la classe con cui impostiamo la misura.

Operando con un approccio mobile-first, partiamo con una sola colonna larga il 100%. Poi, usiamo le media query a crescere adattando il contenuto a larghezze di schermo sempre maggiori. Le media query vanno impostate usando valori compresi tra una larghezza minima (min-width) e una massima (max-width):

@media screen and (min-width: 560px) and (max-width: 799px)
{
	#container[data-columns]::before
	{
		content: '2 .column.size-1of2';
	}
}
@media screen and (min-width: 800px) and (max-width: 1199px)
{
	#container[data-columns]::before
	{
		content: '3 .column.size-1of3';
	}
}
@media screen and (min-width: 1200px) and (max-width: 1299px)
{
	#container[data-columns]::before
	{
		content: '4 .column.size-1of4';
	}
}
@media screen and (min-width: 1300px)
{
	#container[data-columns]::before
	{
		content: '5 .column.size-1of5';
	}
}

Come si vede, nel nostro esempio passiamo da una configurazione a una colonna ad una a cinque colonne che scatta quando la larghezza minima della finestra è di 1300px.

La demo funziona perfettamente. Rispetto a Masonry, viene anche rispettato sempre l'ordine degli item per come sono dichiarati nel markup HTML. La tecnica è supportata da tutti i browser recenti; non da IE8, anche se gli autori stanno lavorando su questo aspetto. Un unico piccolo difetto potrebbe essere rappresentato dal fatto che il container, al variare della larghezza e della configurazione non appare perfettamente centrato. Ciò è dovuto al fatto che abbiamo usato per gli item una larghezza fissa di 250px:

.item
{
	background: #fefefe;
	border: 2px solid #fafafa;
	box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4);
	width: 250px;
	margin-bottom: 10px;
}

È chiaro che, dovendo ogni volta riadattare la configurazione e il numero di colonne, la somma delle larghezze degli item possa lasciare un margine più o meno ampio sulla destra che restituisce questo effetto di 'non centrato'.

La soluzione è comunque a portata di mano. Basterà non dichiarare esplicitamente la larghezze degli item, come abbiamo fatto nella seconda demo:

.item
{
	background: #fefefe;
	border: 2px solid #fafafa;
	box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4);
	margin: 0 10px 20px;
}

In questo caso, dato che non è lo script a calcolare automaticamente il margine destro e sinistro, dobbiamo farlo nel CSS (è uguale a 10px). Gli item sono così fluidi e il problema della centratura risolto brillantemente. Naturalmente, in questo caso sarà necessario stare attenti alle immagini, rendendole scalabili con la regola del max-width: 100%. Si provi a ridimensionare la finestra nelle due demo per verificare la diversità di comportamento delle due soluzioni.

Tutti gli esempi sono come sempre disponibili per il download.

Ti consigliamo anche