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

Come aumentare le performance client-side via HTML e Javascript

Alcuni utili consigli per migliorare le performance di caricamento e visualizzazione di una pagina web, sfruttando alcuni trucchi basati su Javascript.
Alcuni utili consigli per migliorare le performance di caricamento e visualizzazione di una pagina web, sfruttando alcuni trucchi basati su Javascript.
Link copiato negli appunti

Nell'ambito dello sviluppo Web, una delle caratteristiche che contraddistingue un team di produzione professionale ed esperto da uno che si limita semplicemente ad "ottenere il risultato finale", è rappresentato dal "come" il primo gruppo di sviluppatori ottiene i propri risultati. Oltre all'eleganza ed alla manutenibilità del codice, alla scelta di strumenti di sviluppo e di strutture fisiche idonee al progetto, uno dei punti fondamentali che spesso viene trascurato dagli sviluppatori meno preparati riguarda le performance dell'applicazione/sito realizzato, quando questo è posto in un ambiente di produzione.

In questo articolo vediamo quindi delle strategie che possiamo adottare per migliorare le performance del nostro sito Web utilizzando il linguaggio di markup HTML ed alcune tecniche Javascript.

Migliorare la gestione delle immagini

Nel contesto di una pagina Web, la presenza di immagini impatta negativamente sulla quantità di risorse utilizzate dal server, e dunque nei tempi di caricamento della pagina stessa, specialmente se queste sono di grandi dimensioni.

Come regola generale, è sempre meglio non esagerare con la quantità di immagini, sia per rispettare specifiche regole di design, sia per non ridurre le performance complessive della pagina. Esistono diversi metodi per automatizzare la riduzione del carico complessivo di MB necessari al caricamento delle immagini, ma nei casi in cui questo tipo di operazioni non sono disponibili, come in quelli delle pagine statiche o di applicazioni che non sono basate su CMS (WordPress ad esempio, possiede uno strumento che si occupa automaticamente di ridimensionare le immagini quando queste vengono caricate sul sever), occorre tornare alle origini della faccenda ed applicare metodi più spartani.

Una strategia molto nota per migliorare i tempi di caricamento, è quella di ridimensionarle, creando delle thumbnail che verranno mostrate all'utente finale al posto delle versioni originali. Queste saranno visualizzabili opzionalmente, nel caso in cui l'utente stesso decida di approfondire cliccando sopra alla thumbnail. In questo modo le risorse necessarie al caricamento saranno utilizzate dinamicamente a seconda delle azioni dell'utente, e non in modo statico.

Per svolgere questa operazione, una delle scelte migliori consiste nell'utilizzare strumenti di elaborazione grafica, come Adobe Photoshop. Ma esistono anche moltissimi strumenti online che si occupano egregiamente del medesimo scopo, come PicResize, Simple Image Resizer e I Love Img.

A questo punto ci sono altre cose da fare per ottimizzare ulteriormente le immagini in ambiente di produzione Web:

  • rimuovere eventuali metadata, che possono essere stati aggiunti automaticamente dal dispositivo che ha prodotto l'immagine
  • ottimizzare il JPEG per ridurre il numero di colori necessario a rappresentare l'immagine
  • convertire il file da PNG ad un diverso formato (come JPEG) se la trasparenza non è necessaria

Per risolvere i suddetti problemi, abbiamo a disposizione rispettivamente i seguenti strumenti:

Rendere le immagini responsive

La responsiveness è una caratteristica obbligata ed obbligatoria per le immagini nei siti Web moderni. Tuttavia, come tutte le feature più "recenti", rischia di essere utilizzata in maniera scorretta e controproducente. Per rendere un'immagine responsive, non basta scrivere:

img {
max-width: 100%;
height: auto;
}

Questa operazione ridimensiona le immagini in modo meramente meccanico, similmente ad utilizzare un foglio A4 per scrivere una piccola nota: uno spreco di risorse inutile.

Un approccio decisamente più serio riguarda l'utilizzo del tag HTML picture. Questo tag, facente parte della specifica HTML5, si occupa in effetti di fornire un'immagine all'utente finale in modo variabile e dinamico, fornendo una flessibilità decisamente migliorata, in base alla verifica di determinate condizioni.

L'elemento picture contiene più elementi figli source, ognuno indicante un'immagine differente. In questo modo il browser può scegliere quale immagine caricare e mostrare in base ad esempio alle attuali dimensioni del dispositivo che sta utilizzando la pagina.

Il browser utilizzerà l'immagine definita nel primo tag source che rispetta le condizioni imposte (comunemente chiamate "breakpoints") ed ignorerà gli altri. La sintassi è la seguente:

<picture>
<source media="(max-)" srcset="img_big.jpg">
<source media="(max-)" srcset="img_medium.jpg">
<img src="img_default.jpg" alt="def" style="width:auto;">
</picture>

Con l'attributo HTML media applicato al tag source, possiamo impostare le media query, che ci permettono di definire i nostri breakpoints. Nel nostro caso, l'immagine "img_big.jpg" verrà mostrata se le dimensioni della finestra saranno maggiori di 650px, l'immagine "img_medium.jpg" verrà mostrata se le dimensioni della finestra saranno maggiori di 465px, altrimenti verrà mostrata l'immagine "img_default.jpg". Ovviamente, è possibile invertire il procedimento ed impostare la visualizzazione di immagini se le grandezze sono crescenti, utilizzando la proprietà CSS max-width:

<picture>
<source media="(max-)" srcset="img_1.jpg">
<source media="(max-)" srcset="img_2.jpg">
<img src="img_default.jpg" alt="def" style="width:auto;">
</picture>

Nota: è bene ricordarsi di impostare sempre un tag img come ultimo figlio dell'elemento picture. Questo verrà utilizzato nel caso in cui il browser/dispositivo non supporti il tag picture, o nel caso in cui nessuna delle media query venga soddisfatta.

Con una tecnica differente, possiamo impostare la nostra configuazione direttaemente nel tag img utilizzando l'attributo HTML srcset in combinazione con l'attributo HTML sizes:

<img src="small.jpg"
srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
sizes="(min-width: 36em) 33.3vw, 100vw"
alt="Testo">

Con questo approccio possiamo controllare dinamicamente quali risorse mostrare a seconda del dispositivo in uso da parte dell'utente, che si traduce in un'esperienza migliorata ed in un utilizzo delle risorse ottimizzato ad hoc.

Lazy Loading

A questo punto abbiamo migliorato ed ottimizzato le nostre immagini, rendendole infine responsive. Tuttavia, non è garantito che l'utente debba visualizzare tutte le immagini che abbiamo collocato all'interno della pagina HTML, ne questa situazione è sempre necessaria. Ad esempio, prendiamo il caso di uno slideshow, in cui sono presenti molte immagini. Non è assolutamente detto che l'utente le debba visualizzare tutte, dunque caricarle indiscriminatamente rientra nell'arte di sprecare inutilmente risorse. Un approccio migliore consiste nel caricare le immagini solamente quando richiesto, al verificarsi di una determinata condizione, quale ad esempio:

  • l'azionamento di un particolare evento, gestito da attributi HTML come onlick, onmouseover, onmousemove o direttamente dal Javascript
  • il raggiungimento di un particolare punto della pagina tramite scrolling
  • l'apertura di una particolare slide di uno slideshow

ed altre ancora.

Per ovviare al problema, è stata creata la strategia denominata Lazy Loading, di cui abbiamo già parlato su HTML.it. Questa tecnica permette di caricare una determinata risorsa solo quando è veramente necessario. Esistono diverse implementazioni, tra cui Lazyestload.js (utilizzabile su qualsiasi pagina web), ma anche plugin per jQuery o per CMS quali WordPress e Joomla. Di seguito vediamo come utilizzare lo script LazyLoad.

Per installarlo nelle nostre pagine, usiamo la maniera classica:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-lazyload/8.15.2/lazyload.min.js"></script>

A questo punto, possiamo definire un tag img, che ad esempio punta a "myimage_1.jpg" tramite l'attributo data-src, e che possiede classe "lazy" (utile al nostro Javascript):

<img class="lazy" alt="..."
data-src="myimage_1.jpg"
width="220" height="280">

A questo punto possiamo utilizzare la classe LazyLoad per produrre il comportamento desiderato, passando l'attributo "elements_selector" impostato al valore che rappresenta il selettore su cui vogliamo applicare il procedimento, in questo caso la classe "lazy" (il selettore per le classi è "."):

var myLazyLoad = new LazyLoad({
elements_selector: ".lazy"
});

Possiamo usarlo in combinazione con la responsiveness e l'attributo srcset:

<img class="lazyresponsive" data-src="image1.jpg"
data-srcset="image1.jpg 200w, image1@2x.jpg 400w"
data-sizes="(min-width: 20em) 35vw, 100vw">

Javascript:

var myLazyLoad = new LazyLoad({
elements_selector: ".lazyresponsive"
});

E ancora con l'elemento picture:

<picture>
<source media="(min-)" data-srcset="image1.jpg" />
<source media="(min-)" data-srcset="image2.jpg" />
<img class="lazypicture" alt="testo" data-src="image3.jpg">
</picture>

Sempre con la solita chiamata Javascript:

var myLazyLoad = new LazyLoad({
elements_selector: ".lazypicture"
});

Ovviamente la tecnica del Lazy Loading non è applicabile unicamente alle immagini. Div, pannelli, file audio e video, iframes ed immagini di background sono tutti configurabili tramite Lazy Loading, per migliorare le performance globali dell'applicazione.

Utilizzare un servizio CDN

Anziché caricare risorse quali fogli di stile CSS e script Javascript direttamente dal nostro server Web (o servizio di hosting), per velocizzare maggiormente i tempi di caricamento della pagina, in molti casi la soluzione migliore risulta quella di utilizzare i servizi di Content Delivery Network (CDN), che vengono forniti nella maggior parte dei casi dal fornitore stesso del framework o da servizi affiliati.

Questa strategia migliora le performance perchè la stessa risorsa potrebbe essere già stata linkata dal servizio CDN su altri siti, che magari abbiamo visitato in precedenza. Di conseguenza, tale risorsa potrebbe essere già stata scaricata e messa in cache.

Dunque, se ad esempio stiamo usando un framework CSS come ad esempio w3.css, anziché scrivere:

<link rel="stylesheet" href="local/w3.css">

punteremo al CDN scrivendo:

<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

Anche nel caso di un framework Javascript, accade la stessa cosa. Anziché optare per una versione locale di jQuery:

<script src="local/jquery"></script>

useremo il CDN:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

La maggior parte dei progetti di grandi dimensioni e abbastanza affermati offre la possibilità di includere le risorse offerte attraverso CDN.

Migliorare l'assetto dell'applicazione

Se nello sviluppo dell'applicazione non utilizziamo toolkit come webpack, Gulp o Parcel (e così via) per gestire le directory ed il workflow di dipendenze innestate, potremmo avere riduzioni nelle performance a causa delle richieste extra a cui è sottoposto il browser. È il caso, ad esempio, di pagine costruite con WordPress dove i plug-in scaricano tutte le loro dipendenze, quali stili e script, nella pagina. Se stiamo utilizzando WordPress, abbiamo svariati strumenti a disposizione per migliorare la situazione, come AutoptimizeW3 Total Cache.

Un'altra soluzione per ridurre il carico di lavoro del browser consiste nella compressione del codice Javascript. Per fare questo ci sono appositi tool online, come JSCompress e Javascript Minifier, ma è anche possibile svolgere tutto direttamente in locale.

Se ad esempio utilizziamo un gestore di pacchetti come npm, possiamo coordinarlo con il pacchetto UglifyJS, un parser Javascript che consente di minimizzare e comprimere gli script. Dopo aver avviato npm ed installato il secondo, possiamo aggiungere un nuovo script al file package.json:

"scripts": {
"build": "uglifyjs src/vendor/jquery.js src/main.js -o dist/bundle.min.js -c -m"
}

Il comando npm run build ti consente di combinare e minimizzare il tuo script.

Utilizzare i Service Worker

Un service worker è uno script che il browser utilizza in background, in modo "separato" rispetto alla pagina Web, contenento delle operazioni che non necessitano di una pagina Web o di un'interazione da parte dell'utente per essere svolte. Alcuni esempi riguardano le notifiche push e la sincronizzazione in background.

Usano i service worker possiamo intercettare le richieste e fornire assetti precedentemente memorizzati. Quando un utente visita il sito, possiamo mettere in cache svariate cose, come fogli di stile CSS, script, font e cosi via. Ogni richiesta successiva da parte dell'utente sarà dunque soddisfatta dalla cache, che sarà aggiornabile tramite appositi refresh.

Uno strumento utile allo scopo è ad esempio SW Precache per webpack, che genera un web service che, svolgendo i compiti elencati in precedenza, impatta positivamente sulle performance del sito.

Ad esempio, una configurazione di SW Precache permette di impostare le seguenti risorse:

new SWPrecacheWebpackPlugin({
cacheId: 'tj-ie-v3',
filename: 'service-worker.js',
minify: true,
stripPrefix: 'static',
staticFileGlobs: [
'static/fonts/*.name',
'static/fonts/*.name2',
'static/js/main.js',
'static/css/main.css',
'static/js/chunks/*.js',
]
})

Ricordarsi di VanillaJS

L'uso dei vari framework Javascript può semplificare lo sviluppo delle applicazioni web. Infatti, è sempre più comune osservare pagine ricche di framework (talvolta anche più di uno) ed un'abbondanza di plug-in e script vari. Tuttavia, con l'avvento dell'HTML 5 e delle nuove specifiche ECMA, per svolgere compiti che prima erano realmente ostici senza avvalersi di un framework, possiamo utilizzare il semplice ma potentissimo Javascript.

VanillaJS è infatti un termine "ironico" coniato dagli sviluppatori per definire il Javascript nativo e privo di qualsivoglia libreria aggiuntiva. Un altro fattore che rema a favore di questa scelta è il supporto sempre più completo da parte di tutti i maggiori browser verso gli standard ECMA, che si traduce in un minor numero di controlli e check di versione da effettuare all'interno del nostro codice.

Vediamo un esempio. Fino a qualche anno fa, era quasi obbligatorio affidarsi ad un framework, ad esempio jQuery, per lavorare dinamicamente con il DOM della pagina. Grazie al suo motore di selezione bastava scrivere:

var matches = $("p");

Tuttavia, possiamo utilizzare il potente querySelectorAll (nel caso del browser di casa Microsoft, la compatibilità inizia con la versione 8) del Javascript nativo:

var matches = document.querySelectorAll("p");
var matches2 = document.querySelectorAll("div.note, div.alert");

Con querySelectorAll possiamo selezionare elementi di tipo NodeList anche fornendo un contesto specifico differente dal document:

var container = document.querySelector("#test");
var matches = container.querySelectorAll("div.highlighted > p");

In questo caso selezioniamo tutti i paragrafi il cui genitore immediato sono elementi div con classe "highlighted", nel contesto di un elemento contenitore il cui ID è "test".

Nel VanillaJS abbiamo ora un metodo addEventListener stabile, oggetti per produrre richieste asincrone AJAX stabili ed una proprietà classList che permette di lavorare in modo egregio con le classi (attributo HTML "class") degli elementi:

const div = document.createElement('div');
div.className = 'myclass';
div.classList.remove("myclass");
div.classList.add("anotherclass");
div.classList.toggle("myclass");

Le animazioni inoltre, punto forte di quasi tutte le maggiori librerie Javascript (jQuery, Mootools, EXT, Dojo, e cosi via), possono ora essere prodotte direttamente attraverso il CSS, grazie alle nuove proprietà della specifica numero 3, ad esempio:

p {
animation-duration: 3s;
animation-name: slidein;
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}

In questo caso andremo a produrre un'animazione che abbiamo chiamato "slidein", di durata di 3 secondi, che altera le proprietà CSS "margin-left" e "width" facendole slittare da una coppia di valori iniziali ad una di valori finali. Tramite l'uso di un veloce Javascript nativo aggiuntivo, sarà possibile impostare questo tipo di animazioni in modo maggiormente dinamico ed interattivo, come accade con DOMmy.js.

È conveniente investire sullo studio del Javascript avanzato, piuttosto che affidarsi in modo cieco ai framework , e relegare questi ultimi a componente aggiuntivo, piuttosto che a componente obbligatorio.

Conclusione

Come abbiamo potuto vedere esistono molte strategie (tante da non poter entrare tutte in un unico articolo) che permettono di migliorare le performance di una pagina Web, attuabili dal lato client. Ad apparente parità di risultato esteriore, una pagina Web dalle performance più elevate permette di avvicinare maggiormente (e di non allontanare) gli utenti interessati ai contenuti del sito, e di comportarsi in maniera amichevole con i motori di ricerca. Feature come quelle presentate in questo articolo dovrebbero essere garantiti da tutti gli sviluppatori Web moderni.

Ti consigliamo anche