Bon. j'ai fait un Pen en simplifiant au passage le code, en enlevant notamment l'appel aux Container Queries, et donc les fallbaks associés :
CodePen, masonry.
Notons qu'ici j'ai fait une grille sur 2 colonnes avec ".grid2". Le style prévoyant de 1 à 4 colonnes, je vous laisse deviner ce qu'il faut faire pour obtenir 3 ou 4 colonnes.
Et comme je ne laisserais pas ce Pen éternellement en ligne je poste le code ici pour ceux qui lirons le topic à l'avenir :
<main>
<div class="grid2 gap masonry">
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
<div>Du contenu...</div>
</div>
</main>
[class^=grid] {
display: grid;
grid-auto-flow: dense;
grid-template-columns: repeat(var(--n, 1), minmax(0, 1fr));
}
[class^=grid].row-defines { /* @note Option ; permet aux spans de la propriété grid-row de se caler sur les lignes. */
grid-auto-rows: minmax(0, 1fr);
}
[class^=grid].gap { /* @note Option ; les espacements */
gap: 1em;
}
[class^=grid].gap-bottom { /* @note Option ; espace en bas du conteneur principal */
padding-bottom: 1em;
}
[class^=grid].vertical-gap { /* @note Option ; espace vertical uniquement */
gap: 0 1em;
}
@media (min-width: 35em) {
.grid2,
.grid3,
.grid4 {
--n: 2;
}
.c2,
.c3,
.c4 {
grid-column: span 2;
}
}
/* for démo : */
html {
background-color: #333;
}
body {
margin: 0;
}
main {
max-width: 90em;
margin: 0 auto;
}
[class^=grid] * {
padding: 1em;
background-color: tan;
}
// masonry :
class VGrid {
// En attendant un support masonry natif pour le module CSS Grid layout.
// @see https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/
// @credit Vikram Soni @see https://codepen.io/vikramsoni/pen/gOvOKNz
// @note Le script fait appel à une redistribution des lignes pour la grille
// @bugfix @affected Chrome @see https://github.com/rachelandrew/gridbugs/issues/28 @note Une limitation à 999 lignes semble avoir été corrigée, nous avons testé avec 600 items sans bugs.
constructor (container) {
this.grid = container instanceof HTMLElement ? container : document.querySelector(container) // Initialise la grille et les éléments enfants.
this.gridItems = [].slice.call(this.grid.children) // Récupère tous les enfants directs.
}
resizeGridItem(item) {
const rowHeight = 1 // précision de la grille, ici la plus grande précision possible.
const rowGap = parseInt(window.getComputedStyle(this.grid).getPropertyValue('grid-row-gap')) // Récupère les propriétés d'espacement des lignes de la grille, afin que nous puissions l'ajouter aux enfants pour ajouter de l'espace supplémentaire afin d'éviter le débordement de contenu.
const rowSpan = Math.ceil((item.clientHeight + rowGap) / (rowHeight + rowGap))// clientheight représente la hauteur du conteneur avec le contenu. Nous le divisons par la ligne Height+row Gap pour calculer le nombre de lignes dont il a besoin.
item.style.gridRowEnd = 'span ' + rowSpan // Définit la propriété CSS span numRow pour cet enfant avec celle calculée.
}
resizeAllGridItems() { // @bugfix Un premier calcul peut s'avérer insufisant, causant des bugs de rendu sur la longeur des items.
this.grid.style.alignItems = 'start' // modification temporaire de la propriété css slign-items pour calculer la hauteur du contenu.
this.gridItems.forEach(item => this.resizeGridItem(item)) // Appeler la fonction pour calculer le nombre de lignes dont elle a besoin.
this.grid.style.alignItems = 'stretch' // Remettre les align-items à étirer.
}
}
for (const masonry of document.querySelectorAll('.masonry')) {
const grid = new VGrid(masonry)
//window.onload = grid.resizeAllGridItems() // Lancement du calcul de la grille au chargement de la page.
window.addEventListener('load', () => { // Lancement du calcul de la grille si resize
grid.resizeAllGridItems()
setTimeout(() => {grid.resizeAllGridItems()}, 200)
})
window.addEventListener('resize', () => { // Lancement du calcul de la grille si resize
let resizeTimeout
clearTimeout(resizeTimeout)
resizeTimeout = setTimeout(() => {grid.resizeAllGridItems()}, 200) // Limitation du nombre de calculs @see https://stackoverflow.com/questions/5836779/
})
}
Modifié par Olivier C (18 Mar 2023 - 18:32)