Le barre di scorrimento personalizzate sono estremamente rare e questo è dovuto principalmente al fatto che le barre di scorrimento sono una delle parti restanti sul Web che sono praticamente non stilizzabile (ti guardo, selettore di date). Puoi usare JavaScript per crearne uno tuo, ma è costoso, economico fedeltà e possono sembrare in ritardo. In questo articolo, sfrutteremo alcuni matrici CSS non convenzionali per creare uno scorrimento personalizzato che non richiede alcuna JavaScript durante lo scorrimento, solo un codice di configurazione.
TL;DR
Non ti interessano le piccole cose? Devi solo esaminare Demo di Nyan Cat e ottenere la raccolta? Puoi trovare il codice della demo nel nostro Repository GitHub.
LAM;WRA (Lungo e matematica; leggerà comunque)
Qualche tempo fa, abbiamo creato uno scorrimento parallasse (Hai letto) l'articolo? È un'esperienza che vale davvero la pena. Respingendo gli elementi utilizzando CSS 3D trasformazioni, gli elementi sono stati spostati più lentamente della velocità di scorrimento effettiva.
Riepilogo
Iniziamo con un riassunto di come funzionava lo scorrimento parallasse.
Come mostrato nell'animazione, abbiamo ottenuto l'effetto parallasse spingendo gli elementi "indietro" nello spazio 3D, lungo l'asse Z. Lo scorrimento di un documento è di fatto una traslata lungo l'asse Y. Quindi se scorriamo verso il basso di 100 px, ogni verrà tradotto verso l'alto di 100 px. Questo vale per tutti gli elementi, anche quelle "più indietro". Ma perché sono più distanti la videocamera, il movimento osservato sullo schermo sarà inferiore a 100 px, generando l'effetto parallasse desiderato.
Naturalmente, anche se sposti un elemento di nuovo nello spazio, lo renderà più piccolo, che correggiamo scalando di nuovo l'elemento. Abbiamo capito il calcolo esatto quando abbiamo creato Scorrimento Parallasse quindi non ripeto tutti i dettagli.
Passaggio 0: cosa vogliamo fare?
Barre di scorrimento Ecco cosa realizzeremo. Ma hai mai pensato davvero di cosa fanno? Di sicuro non l'ho fatto. Le barre di scorrimento sono indicatori quanto dei contenuti disponibili sono attualmente visibili e quanto avanza come l'ha creato il lettore. Se scorri verso il basso, lo stesso accade con la barra di scorrimento indicano che stai facendo progressi verso la fine. Se tutti i contenuti sono adatti nell'area visibile la barra di scorrimento di solito è nascosta. Se i contenuti hanno il doppio dell'altezza dell'area visibile, la barra di scorrimento riempie metà dell'altezza dell'area visibile. Contenuti con un valore triplo dell'altezza di nell'area visibile la barra di scorrimento viene ridimensionata a 1⁄3 dell'area visibile e così via. Vedi il motivo. Invece di scorrere, puoi anche fare clic e trascinare la barra di scorrimento più velocemente il sito. È una quantità sorprendente di comportamento per una persona poco appariscente di questo tipo. Combattiamo una battaglia alla volta.
Passaggio 1: inversione
Ok, con CSS 3D possiamo far spostare gli elementi più lentamente della velocità di scorrimento si trasforma come descritto nell'articolo sullo scorrimento con parallasse. Possiamo anche invertire la direzione? E a quanto pare possiamo creare ed è così barra di scorrimento personalizzata per il frame perfetta. Per capire come funziona, dobbiamo affrontare una alcune nozioni di base su CSS 3D.
Per ottenere qualsiasi tipo di proiezione prospettica in senso matematico, dovrai soprattutto probabilmente finiranno per utilizzare coordinate omogenee. Non spiegherò nel dettaglio cosa sono e perché funzionano, ma puoi pensare come le coordinate 3D, con la quarta coordinata aggiuntiva chiamata w. Questo dovrebbe essere 1, a meno che non si voglia ottenere una distorsione della prospettiva. Me non devi preoccuparti dei dettagli di w perché non utilizzeremo alcuna diverso da 1. Perciò, d'ora in poi tutti i punti provengono da vettori a 4 dimensioni [x, y, z, w=1] e di conseguenza le matrici devono anche 4 x 4.
Un'occasione in cui puoi vedere che il CSS utilizza coordinate omogenee sotto il
"hood" è quando si definiscono le proprie matrici 4x4 in una proprietà di trasformazione utilizzando
Funzione matrix3d()
. matrix3d
accetta 16 argomenti (perché la matrice è
4 x 4), specificando una colonna dopo l'altra. Quindi possiamo utilizzare questa funzione
specificare manualmente rotazioni, traslazioni, ecc. Ma ciò che ci consente anche
è andare in giro con la coordinata w!
Prima di poter utilizzare matrix3d()
, abbiamo bisogno di un contesto 3D, perché senza un
Con un contesto 3D non ci sarebbe alcuna distorsione della prospettiva e non c'è bisogno di
coordinate omogenee. Per creare un contesto 3D, abbiamo bisogno di un container con
perspective
e alcuni elementi all'interno che possiamo trasformare nel nuovo
spazio 3D creato. Per
esempio:
![Una porzione di codice CSS che distorce un div utilizzando
.](https://developer.chrome.google.cn/static/docs/css-ui/custom-scrollbar/image/a-piece-css-code-distor-1ed892aadfd7c.png?authuser=0&hl=it)
Gli elementi all'interno di un container in prospettiva vengono elaborati dal motore CSS come segue:
- Convertire ogni angolo (vertice) di un elemento in coordinate omogenee
[x,y,z,w]
, rispetto al container in prospettiva. - Applica tutte le trasformazioni dell'elemento come matrici da destra a sinistra.
- Se l'elemento prospettico è scorrevole, applica una matrice di scorrimento.
- Applica la matrice prospettica.
La matrice di scorrimento è una traslazione lungo l'asse y. Se scorriamo verso il basso 400 px, tutti gli elementi devono essere spostati in alto di 400 px. La matrice prospettica è matrice che "tira" i punti più vicini al punto di fuga più indietro in 3D nello spazio in cui sono. In questo modo, entrambi gli elementi sono più piccoli quando sono più indietro e li "mossa più lentamente" durante la traduzione. Pertanto, se un elemento viene spostato indietro, una traslazione di 400 px lo causerà per spostare solo 300 px sullo schermo.
Se vuoi conoscere tutti i dettagli, devi leggere l' spec sul foglio di lavoro di trasformare il modello di rendering, ma ai fini di questo articolo ho semplificato dall'algoritmo riportato sopra.
Il riquadro si trova all'interno di un container in prospettiva con valore p per perspective
supponendo che il container sia scorrevole e fatto scorrere verso il basso
n pixel.
La prima matrice è la matrice prospettica, la seconda matrice è la pergamena . Ricapitolando, il compito della matrice di scorrimento è far spostare un elemento quando scorrono verso il basso, da cui deriva il segno negativo.
Per la barra di scorrimento, invece, vogliamo l'opposto, ovvero che l'elemento
Sposta verso il basso quando scorri verso il basso. Ecco dove possiamo usare un trucco:
Invertire la coordinata w degli angoli del rettangolo. Se la coordinata w è
-1, tutte le traduzioni avranno effetto nella direzione opposta. Come facciamo
che? Il motore CSS si occupa di convertire gli angoli della scatola in
omogenee e imposta w su 1. È arrivato il momento di far brillare matrix3d()
!
.box {
transform:
matrix3d(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, -1
);
}
Questa matrice non serve altro che negare w. Quindi, quando il motore CSS
trasformerà ogni angolo in un vettore della forma [x,y,z,1]
, la matrice
convertilo in [x,y,z,-1]
.
Ho elencato un passaggio intermedio per mostrare l'effetto della trasformazione dell'elemento . Se non hai dimestichezza con la matematica matriciale, va bene lo stesso. Eureka è che nell'ultima riga finiamo per aggiungere l'offset di scorrimento n alla colonna y per la coordinata, invece di sottrarla. L'elemento verrà tradotto verso il basso se scorriamo verso il basso.
Tuttavia, se inseriamo questa matrice esempio, l'elemento non verrà visualizzato. Questo perché la specifica CSS richiede che qualsiasi vertice con w < 0 blocca il rendering dell'elemento. E poiché i nostri la coordinata è attualmente 0 e p è 1, w sarà -1.
Fortunatamente, possiamo scegliere il valore di z! Per assicurarci di finire con w=1, dobbiamo per impostare z = -2.
.box {
transform:
matrix3d(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, -1
)
translateZ(-2px);
}
Ecco, le nostre è tornato il decoder!
Passaggio 2: fai muovere i primi passi
Ora la nostra scatola è lì ed ha lo stesso aspetto che avrebbe senza e piccole trasformazioni. Al momento il contenitore della prospettiva non è scorrevole, quindi non lo vediamo, ma sappiamo che il nostro elemento andrà nella direzione diversa quando hai fatto scorrere la pagina. Facciamo scorrere il container? Possiamo semplicemente aggiungere spazio che occupa spazio:
<div class="container">
<div class="box"></div>
<span class="spacer"></span>
</div>
<style>
/* … all the styles from the previous example … */
.container {
overflow: scroll;
}
.spacer {
display: block;
height: 500px;
}
</style>
E ora scorri il riquadro. La casella rossa si sposta verso il basso.
Passaggio 3: specifica una dimensione
Abbiamo un elemento che si sposta verso il basso quando la pagina scorre verso il basso. Questo è il problema un po' fuori strada, davvero. Ora dobbiamo definire lo stile in modo che abbia l'aspetto di una barra di scorrimento rendilo un po' più interattivo.
Una barra di scorrimento di solito è composta da un "pollice" e una "traccia", mentre la traccia non è sempre visibili. L'altezza del pollice è direttamente proporzionale a quanto siano visibili.
<script>
const scroller = document.querySelector('.container');
const thumb = document.querySelector('.box');
const scrollerHeight = scroller.getBoundingClientRect().height;
thumb.style.height = /* ??? */;
</script>
scrollerHeight
è l'altezza dell'elemento scorrevole, mentre
scroller.scrollHeight
è l'altezza totale dei contenuti scorrevoli.
scrollerHeight/scroller.scrollHeight
è la frazione dei contenuti che
visibile. Il rapporto tra lo spazio verticale in cui il coperchio per i pollici deve essere uguale
proporzione dei contenuti visibili:
<script>
// …
thumb.style.height =
scrollerHeight * scrollerHeight / scroller.scrollHeight + 'px';
// Accommodate for native scrollbars
thumb.style.right =
(scroller.clientWidth - scroller.getBoundingClientRect().width) + 'px';
</script>
La dimensione del pollice è che hanno un bell'aspetto, ma si sta muovendo troppo velocemente. Qui possiamo prendere la nostra tecnica scorrimento parallasse. Se spostiamo l'elemento più indietro, si sposterà più lentamente scorrere. Possiamo correggere le dimensioni scalandole verso l'alto. Ma quanto dobbiamo spingere a tornare esattamente? Facciamo un po' di matematica, come avrai indovinato. Questa è l'ultima volta la promessa.
L'informazione cruciale è che vogliamo che il bordo inferiore del pollice
allinealo con il bordo inferiore dell'elemento scorrevole quando l'hai fatto scorrere fino in fondo
verso il basso. In altre parole: se abbiamo fatto scorrere
scroller.scrollHeight - scroller.height
pixel, vogliamo che il pollice sia
tradotto da scroller.height - thumb.height
. Per ogni pixel di scorrimento,
vogliamo che il pollice sposti una frazione di pixel:
Questo è il nostro fattore di scala. Ora dobbiamo convertire il fattore di scala
traslante lungo l'asse z, come già fatto nello scorrimento del parallasse
. In base alle
sezione pertinente della specifica:
Il fattore di scala è uguale a p/(p - z). Possiamo risolvere questa equazione per z
dobbiamo capire quanto dobbiamo tradurre il pollice lungo l'asse z. Ma mantieni
ricorda che, a causa delle nostre truffe, dobbiamo tradurre
-2px
aggiuntivi in z. Nota anche che le trasformazioni di un elemento vengono applicate
da destra a sinistra, il che significa che tutte le traduzioni prima della nostra matrice speciale
essere invertita, tuttavia, tutte le traduzioni dopo la nostra matrice speciale lo faranno! Iniziamo
codificalo.
<script>
// ... code from above...
const factor =
(scrollerHeight - thumbHeight)/(scroller.scrollHeight - scrollerHeight);
thumb.style.transform = `
matrix3d(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, -1
)
scale(${1/factor})
translateZ(${1 - 1/factor}px)
translateZ(-2px)
`;
</script>
Abbiamo un barra di scorrimento. È solo un elemento DOM a cui possiamo applicare lo stile desiderato. Una cosa è importante in termini di accessibilità è far sì che il pollice risponda fare clic e trascinare, poiché molti utenti sono abituati a interagire in questo modo con una barra di scorrimento. Per non allungare ulteriormente questo post, non vi spiegherò i dettagli di quella parte. Dai un'occhiata codice libreria per maggiori dettagli, se vuoi vedere come si fa.
E iOS?
Ah, il mio vecchio amico Safari iOS. Come con lo scorrimento in parallasse, ci imbattiamo in un
problema. Poiché stiamo scorrendo un elemento, dobbiamo specificare
-webkit-overflow-scrolling: touch
, ma questo causa l'appiattimento 3D e l'intera
l'effetto di scorrimento smette di funzionare. Abbiamo risolto il problema nello scorrimento di parallasse
rilevando Safari in iOS e affidandosi a position: sticky
come soluzione alternativa.
faremo esattamente la stessa cosa. Dai un'occhiata
articolo sul parallasse
per rinfrescarti la memoria.
E la barra di scorrimento del browser?
In alcuni sistemi, dovremo fare i conti con una barra di scorrimento nativa permanente.
In passato, la barra di scorrimento non può essere nascosta (tranne con un
pseudo-selettore non standard).
Per nasconderlo, dobbiamo ricorrere ad hacker che non usano i fondamenti matematici. Concludiamo
elemento di scorrimento in un contenitore con overflow-x: hidden
e rende
dell'elemento di scorrimento più ampio del contenitore. La barra di scorrimento nativa del browser
ora non visibili.
Fin
Combinando tutto, ora possiamo creare una configurazione perfetta barra di scorrimento, come quella della finestra Demo di Nyan Cat.
Se non vedi Nyan cat, significa che stai un bug che abbiamo trovato e segnalato durante la creazione della demo (fai clic sul pollice per far apparire Nyan cat). Chrome è davvero bravo a evitare di lavorare inutilmente come dipingere o animare elementi fuori schermo. La cattiva notizia è che i nostri matrix fanno pensare a Chrome che la GIF del gatto Nyan sia in realtà fuori dallo schermo. Speriamo che il problema venga risolto a breve.
Ecco fatto. È stato un bel po' di lavoro. Ti faccio i complimenti per aver letto tutto cosa. Ecco alcuni esempi un vero inganno per far funzionare tutto questo e probabilmente raramente vale la pena fare lo sforzo, tranne nei casi in cui una barra di scorrimento personalizzata è una parte essenziale dell'esperienza. Ma bello sapere che è possibile, no? Il fatto che sia difficile la barra di scorrimento personalizzata mostra che il CSS sta svolgendo attività. Ma non temere! In futuro, Houdini AnimationWorklet renderà effetti di scorrimento perfetti come questo è molto più semplice.