ScrollPanHell

ScrollPanel est un composant PrimeVue (PrimeFaces) qui veut vous aider à faire défiler vos contenus dans un espace définit.

Démo PrimeVue de son composant ScrollPanel

La démo est sympa, ça donne envie. Mais ! D’une part, c’est fait en Javascript, positionné par calcul, sans proposer de moyen de définir le positionnement (pensez à un t’chat); d’une autre, les bar peuvent sortir de leur piste en débordement (cas du DataTable redécoré avec ScrollPanel), sans compter que sans survol de la zone, les bar ne s’initialisent pas et induisent l’utilisateur en erreur. Trop d’erreurs pour le garder sur un projet, ni même comprendre l’intérêt hors de leur usage type en démo.

Les tinybar, c’est pas nouveau, depuis que Webkit nous a donné la main sur le style on s’en donne à coeur joie, même si certains navigateurs d’époque ne voulaient pas suivre, ou comme Firefox, continuent de faire bande à part (Firefox propose une autre formule plus minimaliste). Du coup, si ScrollPanel ne veut pas faire correctement un job qui existe déjà, ni apporter un plus au fait de créer un composant qu’une simple classe CSS peut résoudre, on peut faire le nôtre.

<div class="scrollpanel">
  ...
</div>

Comme je le disais, une simple classe CSS. Ceci dit, n’oubliez pas qu’il faut restreindre votre contenu, donc vous définirez une hauteur et/ou largeur, même si notre composant aura des valeurs par défaut.

.scrollpanel {
  width: 100%;
  height: 100%;
  position: relative;
  overflow-y: scroll;
  overflow-x: auto;

  scrollbar-color: var(--blue-500) var(--blue-50);
  scrollbar-width: thin;

  &::-webkit-scrollbar {
    width: 9px;
    height: 9px;
  }

  &::-webkit-scrollbar-track {
    background: var(--blue-50);
  }

  &::-webkit-scrollbar-thumb {
    background-color: var(--blue-500);
    border-radius: 3px;

    &:hover {
      background-color: var(--blue-700);
    }
  }
}

Disséquons notre CSS. Déjà c’est écrit en SCSS car c’est plus cool 🙂 lisible, maintenable et organisé. Ensuite, j’ai utilisé des variables pour les couleurs comme on en trouve dans la plupart des librairies aujourd’hui, mais mettez ce que vous voulez : code hexadécimale, nom de couleur, rgb, … Enfin, il y a 2 solutions : on commence avec le préfixe scrollbar et on continue ensuite avec le préfixe -webkit.

scrollbar c’est la version Firefox de la solution, en mode minimaliste sans avoir toute la main sur ce que l’on veut avoir. Mais au moins on s’en approche et c’est toujours mieux que les scrollbar d’origine.

-webkit c’est la version webkit… bah oui, c’est comme le Port-Salut… Et là on profite de belles possibilités car les sélecteurs proposés nous laissent la main sur le CSS applicable sur la cible. ´Évidemment c’est non-standard, et en même temps c’est le moteur le plus répandu… allez comprendre. Du coup faites attention et n’hésitez pas à consulter caniuse ou MDN.

Au final vous aurez un système de scrollpanel, compatible et sans les erreurs de la version PrimeVue. Ceci dit, gardons un oeil dessus car PrimeFaces a un bon rythme de livraison et ils glissent souvent des correctifs intéressant dans leur livraisons mineures (ex: un fix virtual-scroll pour DataTable récemment), et ici, en préparant cet article, j’ai vu qu’ils ont ajouté une nouvelle mécanique pour permettre l’accès au style du DOM de leur composant avec une définition en paramètre (:pt pour Pass Through). Personnellement je préfère séparer mon CSS/SCSS (tel que leur thème et/ou une surcouche), surtout dans un esprit générique, car le passer en paramètre à chacun de nos usages générera une répétition de code, et ce n’est pas une bonne pratique (oui on peut faire un composant personnalisé qui englobe notre définition). Mais encore, le composant, bien qu’il évolue, ne propose toujours pas de fonctionnalité qui justifie son existence et cette façon de l’utiliser.

PrimeVue : un datatable qui scroll, mais en joli.

PrimeVue, c’est chouette mais c’est fait avec les pieds :/ Plus on explore un truc, plus on voit ce qui se cache derrière une belle apparence et un beau lot de composants. Personne n’est parfait et l’amélioration est continue, mais si vous regardez comment c’est codé, il y a dû y avoir quelques stagiaires au niveau architectural : des ponts de composants pas fait avec un réel impacte derrière (filtre de tableau (regardez la comparaison de date…) ou combinaison de solution des input), ou encore ici le scroll du tableau (datatable encore lui) qui ne peut pas être designé naturellement comme scrollpanel).

Qui dit problème, dit recherche de solution : mettons un scrollpanel autour d’un datatable, ça sera joli.

    <ScrollPanel class="w-100">
        <DataTable ...

Premièrement il faudra dire au DataTable d’être scrollable et avec une hauteur en flex, tout en le contredisant avec une belle injonction css. Et de l’autre, comme attendu, préciser au ScrollPanel sa hauteur.

    <ScrollPanel class="w-100 table-normal-height">
        <DataTable scrollable scroll-height="flex" ...
.p-datatable.p-datatable-scrollable .p-datatable-wrapper { overflow: inherit }

.table-normal-height {
    height: var(--content-height); /* La hauteur qu'il vous faut */
}
Pour rappel : en vert c’est le padding.

Outre le fait que ça fonctionne, vous aurez un effet de bord, dû au fait du code CSS ci-dessous qu’ils ont appliqué. Vous n’aurez pas la fin de la dernière ligne du tableau et vous pourrez danser sur votre tête, rien n’y fera.

Mais d’où vient ce 18px arbitraire et à quoi bon. Dans notre cas d’un tableau en flex : aucun. J’imagine donc qu’ils ont eu un cas nécessitant ce bricolage, mais nous ça nous emmerde. Du coup, on va reset localement.

.p-scrollpanel-wrapper .p-scrollpanel-content {
    width: 100%;
    height: 100%;
    padding: 0;
}

Plus de padding (en vert) visible et le contenu (en bleu) est complet avec la scrollbar également bien positionnée. Tadaaa.

En bonus, pour ceux dont le design importe, voici ma surcouche esthétique de la scrollbar. Basé sur TailwindCSS pour les couleurs.

.p-scrollpanel .p-scrollpanel-wrapper {
    border-right: 9px solid var(--gray-400)
}
.p-scrollpanel .p-scrollpanel-bar {
    background-color: var(--red-800);
    opacity: 1;
    transition: background-color .2s;
}
.p-scrollpanel .p-scrollpanel-bar:hover {
    background-color: var(--red-600);
}

En gros, en premier on définit la largeur de la zone de scroll et la couleur de fond. Ensuite, la couleur de la barre de défilement avec une transition pour le hover. Et donc enfin l’effet de survol (hover) avec une couleur de réaction plus vive.