Nel primo articolo di questa serie dedicata alla realizzazione di layout a griglia senza framework abbiamo impostato la base del nostro lavoro. Il risultato è stato un layout fisso, facilmente configurabile ed estendibile con pochi ritocchi.
>> Leggi come creare un layout fisso a griglia senza framework
Ora prenderemo l'esempio originario e ci lavoreremo per rendere il nostro layout adattabile alla più ampia gamma possibile di dispositivi e dimensioni dello schermo.
Responsive e adaptive, le differenze
Come qualcuno avrà notato, non abbiamo detto 'responsive', ma 'adattabile'. È una sottigliezza lessicale per certi versi, ma rispetta una tendenza in voga nell'ambiente dei web designer anglofoni, per cui è:
- responsive ('responsivo'), un design basato su layout fluidi, unità di misure relative e media query
- adaptive ('adattabile'), un design basato invece su layout fissi attivati tramite le media query.
A prescindere dal lessico, il risultato non cambia: potete testarlo sin da ora visualizzando la demo (come sempre in questi casi l'invito è quello di ridimensionare la finestra del browser per apprezzare dal vivo le modifiche al layout in concidenza dei breakpoint).
Il markup HTML
Mettiamo dunque mano all'esempio di base per adeguare il codice HTML al nuovo scenario.
La prima riga che aggiungiamo è questa, la base di ogni pagina che si voglia rendere responsiva e adattabile, il meta tag viewport:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
A differenza di quanto abbiamo fatto per la pagina demo della guida al responsive design, non usiamo le istruzioni user-scalable=no
e maximum-scale=1.0
che impediscono all'utente di ingrandire/zoomare la pagina e il testo, una salvaguardia per l'accessibilità insomma.
>>Leggi la guida al Responsive Design
Così facendo, però, lasciamo spazio ad un piccolo ma a volte fastidioso bug di iOS (almeno fino alla versione 5.0), per il quale modificando l'orientamento da portrait a landscape la pagina rimane zoomata, costringendo l'utente al tap per riportarla ad un livello di ingrandimento normale.
La soluzione per fortuna c'è. Un piccolo script di Scott Jehl che abbiamo così inserito nella head
del nostro documento:
<script src="script/ios-orientationchange-fix.js"></script>
Procedendo nella head
, troviamo il riferimento a jQuery. La libreria ci serve come base per realizzare lo script per la navigazione su dispositivi mobili:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
Segue una serie di librerie che serviamo alle versioni di IE inferiori alla 9:
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<script src="script/selectivizr-min.js"></script>
<script src="script/respond.min.js"></script>
<![endif]-->
Di HTML5shiv abbiamo già detto nello scorso appuntamento. Selectivizr la sfruttiamo per poter usare usare tutti i selettori CSS3. Con Respond.js estendiamo a IE6-8 il supporto per le media query.
>> Leggi la lezione sulle Media Query
Se darete un'occhiata al codice della demo, noterete subito dopo questo script:
<script type="text/javascript">
jQuery(document).ready(function($){
$("a.attiva-nav").click(function() {
$("nav").slideToggle();
$(this).toggleClass("active");
});
});
</script>
È quello che gestisce la navigazione sul mobile e ne parleremo estensivamente più avanti.
Per tutto il resto, il markup riflette in toto quello dell'esempio originario. Con poche eccezioni.
Subito prima dell'elemento nav
che racchiude il menu di navigazione principale, inseriamo un elemento a
che attiverà il menu di navigazione sui dispositivi mobili. Ecco come si presenta nel codice l'intera sezione header
:
<header>
<div id="logo">
<a href="#"><img src="img/logo.png"></a>
</div>
<a class="attiva-nav" href="#">Menu</a>
<nav>
<ul>
<li><a href="#">Chi siamo</a></li>
<li><a href="#">Dove siamo</a></li>
<li><a href="#">Servizi</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contatti</a></li>
</ul>
</nav>
</header>
Alle immagini che compaiono nel corpo del documento (ad eccezione del logo) abbiamo aggiunto una classe .scala
perché le renderemo fluide nel CSS.
Il codice CSS
Come abbiamo fatto per il markup, andiamo a vedere come il CSS è stato modificato per rendere il layout adattabile. Trovate entrambi i fogli di stile in allegato, per cui potrete facilmente verificare le differenze per conto vostro.
La premessa necessaria è che procederemo in senso opposto rispetto a quanto visto nella guida al responsive design. Lì gli stili di base erano quelli per il mobile e con le media query ci si adeguava a risoluzioni via via più ampie. Qui si parte dagli stili per la versione del sito adattata a schermi desktop per poi scendere con i vari breakpoint fino a coprire gli schermi più piccoli.
Iniziamo l'analisi da un aspetto cruciale. Dal momento che la pagina si adatterà a diverse risoluzioni di schermo, le immagini dovranno adeguarsi ed essere pertanto fluide (anche se sono inserite in un contesto di layout fisso). La regola è semplice. Creiamo una classe ad hoc per le immagini che vogliamo rendere adattabili e fissiamo max-width
al 100%, con gli aggiustamenti del caso per rendere tutto compatibile con le varie versioni di IE:
/* Immagini responsive */
img.scala {
max-width:100%;
height:auto;
width: auto;
}
La griglia di base, quella per il desktop diciamo, rimane invariata:
.contenitore {
width:960px;
margin:0 auto;
padding:0;
background: #fff;
}
.riga {
margin: 0 0 20px 0;
}
[class*='colonna-'] {
display: block;
float: left;
padding: 0 20px;
}
.colonna-1-3 {
width: 320px;
}
.colonna-1-2 {
width: 480px;
}
.colonna-1 {
width: 960px;
}
Una piccola aggiunta riguarda gli stili per l'elemento header
. Dato che successivamente posizioneremo rispetto ad esso la navigazione, dichiariamo un posizionamento relativo:
header {
height: 70px;
border-bottom: 1px solid #333;
position: relative;
}
Ricordate l'elemento a
che attiva la navigazione? Bene, vogliamo che sia nascosto nella configurazione di partenza, quella per schermi ampi, per cui:
a.attiva-nav {
display: none;
}
Giunti a questo punto, possiamo procedere nell'adattamento tramite i breakpoint e le media query.
Il primo breakpoint lo fissiamo così:
@media only screen and (min-width: 768px) and (max-width: 959px) {
.contenitore {
width: 768px;
}
.colonna-1-3 {
width: 256px;
}
.colonna-1-2 {
width: 384px;
}
.colonna-1 {
width: 768px;
}
}
Lavoriamo su un range che va da 768px (min-width
) a 959px (max-width
) di larghezza per lo schermo (meglio: per la finestra del browser!). La struttura del layout rimane invariata. L'unica cosa che cambia è che restringiamo il contenitore perché si adatti al meglio alle dimensioni fissate (provatelo, se possibile, su un iPad in orientamento portrait).
Modificando la larghezza del contenitore, dobbiamo anche adeguare quella delle colonne. Il calcolo è sempre lo stesso, la proporzionalità rimane. Per fissare la larghezza di .colonna-1-2
dividiamo 768 per 2. Per colonna-1-3
dividiamo per 3.
Passiamo al secondo breakpoint. Ecco la media query:
@media only screen and (min-width:480px) and (max-width:767px) {
}
Qui il range va da 480px a 767px. Basta fare un po' di test per verificare che:
- la navigazione è troppo estesa in larghezza per accomodarsi nell'header accanto al logo;
- le colonne tendono a diventare troppo compresse se rimangono nella configurazione di base.
Per prima cosa operiamo sulle colonne.
Quello che vogliamo ottenere è che appaiano come blocchi sovrapposti in un'unica colonna, senza essere e apparire floattate. In pratica, linearizziamo il layout. Otteniamo il risultato in modo semplicissimo, senza nemmeno agire sul float:
.contenitore {
width: 460px;
}
.colonna-1, .colonna-1-2, .colonna-1-3 {
width: 460px;
margin:0;
}
Restringiamo il contenitore fino a 460px. Impostiamo per tutti i tipi di colonna la stessa larghezza (sempre 460px), azzeriamo i margini. Finito. Fatto.
Ora la navigazione. Siamo partiti da una classica lista non ordinata resa orizzontale floattando i list item e contenuta in un elemento nav
floattato a destra per posizionarlo rispetto al logo:
nav {
float: right;
padding: 20px 20px 0 0;
}
nav ul, nav li {
margin: 0;
padding: 0;
}
nav ul li {
list-style: none;
float: left;
margin-right: 5px;
}
nav ul li a {
display: block;
padding: 5px;
}
Per adeguare il tutto seguiamo uno dei più comuni pattern di navigazione responsiva, quello detto 'toggle'. È infatti basato su un pulsante che attiva e disattiva (mostra e nasconde) il menu di navigazione.
Qual è il pulsante che attiverà la nostra navigazione lo sappiamo già:
<a class="attiva-nav" href="#">Menu</a>
È quello che prima abbiamo nascosto
a.attiva-nav {
display: none;
}
e che ora invece visualizziamo nel contesto di questo breakpoint posizionandolo comunque a destra rispetto al logo (riportiamo qui sotto solo le due proprietà essenziali della regola):
a.attiva-nav {
display: block;
float: right;
}
Bene, ora il pulsante è visibile. Ma non basta. Dobbiamo adeguare anche il menu di navigazione. Useremo una combinazione di CSS e Javascript.
Prima di tutto agiamo sull'elemento nav
che racchiude la lista/menu:
nav {
clear: both;
position: absolute;
top: 70px;
width: 100%;
z-index: 10000;
display: none;
}
Nell'ordine:
- annulliamo il float con
clear: both
in modo tale chenav
si collochi sotto il logo; - lo posizioniamo assolutamente;
- collochiamo l'elemento 70px in basso rispetto all'header (
top: 70px
); - assegniamo una larghezza pari al 100%;
- impostiamo uno
z-index
molto alto in modo che il menu si collochi sopra i contenuti sottostanti - nascondiamo inizialmente con
display: none
, visto che il menu sarà visualizzato solo agendo sul pulsante tramite Javascript.
È la volta della lista/menu. Sarà sufficiente annullare il float sui list item perché appaiano sovrapposti e dar qualche tocco di formattazione:
nav ul {
margin: 0;
padding: 0;
}
nav ul li {
list-style: none;
float: none;
}
nav ul li a {
padding: 5px;
display: block;
border-bottom: 1px solid #333;
}
Non ci rimane che costruire l'interazione con il nostro piccolo script:
jQuery(document).ready(function($){
$("a.attiva-nav").click(function() {
$("nav").slideToggle();
$(this).toggleClass("active");
});
Nulla di eclatante. Ricorriamo semplicemente al metodo jQuery .slideToogle per avere un'attivazione del contenuto accompagnato da un'animazione che rende più fluido il movimento di comparsa e scomparsa del menu.
Ancora un breakpoint per adeguare ulteriormente il layout. Questa volta fissiamo solo la larghezza massima su 479px:
@media only screen and (max-width:479px) {
.contenitore {
width: 310px;
}
.colonna-1, .colonna-1-2, .colonna-1-3 {
width: 310px;
margin: 0;
}
In questo scenario, il contenitore e le colonne sono fissati ad una larghezza di 310px. Nella media query andrà anche ricopiata la parte per la navigazione. Per tutti i dettagli rimandiamo allo studio dei file allegati.
Bene così. Credo che la lezione più importante che si possa imparare da questo articolo è che quando si vogliono rendere adattabili layout con dimensioni fisse si devono ricalcolare ogni volta, nel contesto dei breakpoint, le dimensioni del contenitore e degli elementi che contiene (nel nostro caso le colonne della griglia). Si può fare, ma vedremo nel prossimo appuntamento quanto tutto sia più semplice a partire da un layout fluido.
Link utili