Logo Froglab Agenzia di Comunicazione

Tutorial: disegnare un feed slider in HTML e CSS

Scritto da francesco nella categoria   il giorno 1 Luglio 2021
Schede su sfondo nero

Questo tutorial è ispirato dal feed degli articoli del sito CSS tricks: ho voluto cercare di ricreare un feel simile utilizzando solo HTML e CSS (e solo una punta di Javascript) partendo da zero. In un futuro articolo ho in programma di utilizzare il codice che troverete qui sotto per implementarlo in WordPress e rendere a tutti gli effetti il feed dinamico.

Per quanto riguardo CSS invece, ho utilizzato flexbox per allineare gli elementi e ho fatto uso di variabili e media query oltre che applicare uno styling alla scrollbar.

Schermata con slideshow
Il risultato finale

Struttura HTML

Per prima cosa ho creato una struttura per il feed: si tratta solo di poche div a cui ho assegnato specifiche classi che ho utilizzato più tardi nel CSS.

<div class="main-container"> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 3, 2021</span> </div> <h3 class="main-container_tab_title">Quisque id mi</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 4, 2021</span> </div> <h3 class="main-container_tab_title">Nullam quis ante</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 5, 2021</span> </div> <h3 class="main-container_tab_title">Donec sodales</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 6, 2021</span> </div> <h3 class="main-container_tab_title">Quisque id mi</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 7, 2021</span> </div> <h3 class="main-container_tab_title">Nullam quis ante</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> <div class="main-container_tab"> <div class="main-container_tab_datetitle"> <div class="main-container_tab_date"> Article <span>Jun 8, 2021</span> </div> <h3 class="main-container_tab_title">Donec sodales</h3> </div> <div class="main-container_tab_photoauthor"> <img class="main-container_tab_photo" src="https://maretti.rocks/wp-content/uploads/2019/12/fav_152.png"> <p class="main-container_tab_author">Francesco Maretti</p> </div> </div> </div>
Code language: HTML, XML (xml)

La classe main-container indica il container del feed vero e proprio, mentre le singole schede hanno classe main-container_tab. Utilizzando questo tipo di nomenclatura ho cercato di mantenere ordine tra le mie classi, che riflettono la struttura dell'elemento e dei sui elementi figli.

Import dei font e variabili

Per quanto riguarda il CSS, per prima cosa ho importato i font da Google font utilizzando @import e creato le variabili che diventeranno i colori utilizzati per creare il feed. Inserirò i vendor prefixes alla fine, dando per quasi scontato che la gran parte delle persone che lavorino nel web design con browser webkit.

@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Roboto+Mono&display=swap'); :root { --black: #333; --blacker: #4b4b4b; --white: #ededed; --orange: #eea365; --orangest: #ec7456; }
Code language: CSS (css)

L'utilizzo delle variabili in CSS è ancora cosa poco sfruttata: se ne fa uso abbondante nei pre-processori, ma in vanilla CSS vengono spesso dimenticate. In questo caso ne ho fatto un utilizzo blando, limitando a dichiarare come variabili alcuni colori che useremo in seguito (black, blacker, white, orange, orangest). Avrei sicuramente potuto essere più professionale nel dare loro un nome, ma bisogna pur svagarsi ogni tanto. È interessante notare come le variabili, che vengono dichiarate sempre utilizzando lo schema --nomevariabile: valore; siano impostate utilizzando la pseudo-classe :root, che indica l'elemento base della pagina. In sostanza, :root equivale ad html, ma è ancora più specifico.

CSS container principale

Ho organizzato il contenuto del container principale utilizzando flexbox: nello specifico ho impostato la direzione dei suoi elementi figli su una riga (flex-direction: row). Ho anche fatto in modo che la barra di scroll fosse visibile solo in orizzontale (overflow-x: scroll e overflow-y: hidden).

.main-container { display: flex; flex-direction: row; flex-wrap: nowrap; width: 80%; height: auto; padding: 40px; margin: 0 auto; overflow-x: scroll; overflow-y: hidden; border-right: 5px solid var(--orangest); cursor: grab; }
Code language: CSS (css)

La scrollbar grigia di default di Chrome è sicuramente bruttina, ma possiamo darle uno stile con CSS. Questo codice CSS non è ancora supportato da Firefox, che sostituirà la nostra barra custom con quella di default: per evitare che ciò accada ho aggiunto le proprietà scrollbar-width e scrollbar-color che, pur non sortendo lo stesso medesimo effetto, ci si avvicinano abbastanza.

.main-container::-webkit-scrollbar { height: 10px; } .main-container::-webkit-scrollbar-track { background: var(--blacker); } .main-container::-webkit-scrollbar-thumb { background-color: var(--orange); } .main-container { scrollbar-width: thin; scrollbar-color: var(--orange) var(--white); }
Code language: CSS (css)

CSS singole schede

Per quanto riguarda le singole schede, non ho fatto molto se non usare flexbox con le proprietà flex-direction: column e justify-content: space-between in modo da garantire che le due div figlie, quella che contiene data e titolo e quella che contiene foto e nome dell'autore, occupino tutto lo spazio in verticale della scheda. Nota sui gradienti in Firefox: necessitano, per essere supportati, del prefisso moz-linear-gradient e, anche utilizzandolo, il supporto è un po' debole. Personalmente non ritengo che conoscere tutti i prefissi dedicati sia un impiego utile di tempo, quindi preferisco lavorare su Chrome e lasciare il lavoro sporco di inserirli a siti come Autoprefixer. Tuttavia penso sia assolutamente dovuto sapere in anticipo almeno le principali carenze dei maggiori browser per diffusione.

.main-container_tab { min-width: 20%; height: 300px; padding: 20px; background: var(--black); background: linear-gradient(45deg, var(--blacker) 0%, var(--black) 100%); border-radius: 10px; transition: all .5s ease-in-out; display: flex; flex-direction: column; flex-wrap: nowrap; justify-content: space-between; cursor: grab; } .main-container_tab:not(:first-child) { transform: translateX(-80px); transform-origin: 100%; box-shadow: -5px 0 20px 0 rgba(0, 0, 0, 0.2); } .main-container_tab:hover:not(:first-child) { transform: rotate(5deg) translateX(-120px); } .main-container_tab:first-child:hover { margin-right: 80px; }
Code language: CSS (css)

Per chi si approcciasse per la prima volta all'utilizzo delle pseudo-classi, :first-child e :not sono due esempi classici: la prima consente di selezionare solo il primo elemento figlio, mentre la seconda consente di escludere dalla selezione uno specifico elemento; in questo caso l'istruzione è di non applicare lo stile al primo elemento con classe .main-container_tab, ovvero la prima tab. In questo caso avrei potuto utilizzare anche un'altra pseudo-classe al posto di :first-child, ovvero :nth-child(1), ma, in questo caso, :first-child risulta più elegante, a mio parere.

L'ultimo step per quanto riguarda le schede è quello di dare uno stile al contenuto testuale.

.main-container_tab_date { font-family: 'Roboto Mono', monospace; font-size: .8rem; font-weight: 900; color: var(--white); } .main-container_tab_date span { opacity: .5; font-weight: 500 } .main-container_tab_title { font-family: 'Open Sans', sans-serif; font-weight: 700; color: var(--orange); margin: 0; } .main-container_tab_photoauthor { display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center; } .main-container_tab_photo { width: 50px; height: 50px; } .main-container_tab_author { margin-left: 20px; font-family: 'Roboto Mono', monospace; color: var(--white); font-size: .8rem }
Code language: CSS (css)

Media queries

Il tocco finale sono le media queries, che consentono di rendere lo slider responsive. Dato che ho utilizzato percentuali per decidere quanto spazio occupasse ogni singola scheda, è solo questione di ritoccarle per le diverse viewport e il gioco è fatto.

@media screen and (max-width:1300px) { .main-container_tab { min-width: 33%; } } @media screen and (max-width:900px) { .main-container_tab { min-width: 50%; } } @media screen and (max-width:500px) { .main-container_tab { min-width: 100%; } }
Code language: CSS (css)

Fatto questo e testato lo slider su diverse dimensioni di schermo per verificarne il funzionamento, l'unica aggiunta, a parte l'aggiunta di tutti i prefissi dei vendor nel CSS (di nuovo, mi affido al sito Autoprefixer per questo compito), è l'inserimento del codice Javascript che mi ha consentito di rendere le schede "trascinabili" con un click del mouse.

const slider = document.querySelector('.main-container'); let isDown = false; let startX; let scrollLeft; slider.addEventListener('mousedown', (e) => { isDown = true; slider.classList.add('active'); startX = e.pageX - slider.offsetLeft; scrollLeft = slider.scrollLeft; }); slider.addEventListener('mouseleave', () => { isDown = false; slider.classList.remove('active'); }); slider.addEventListener('mouseup', () => { isDown = false; slider.classList.remove('active'); }); slider.addEventListener('mousemove', (e) => { if(!isDown) return; e.preventDefault(); const x = e.pageX - slider.offsetLeft; const walk = (x - startX) * 3; //scroll-fast slider.scrollLeft = scrollLeft - walk; console.log(walk); });
Code language: JavaScript (javascript)

Ed ecco, infine, il risultato finale.

Share