Maîtriser Grid et Flexbox en overflow pour afficher un nombre fixe d’items visibles

Author:

En développement front-end, il est parfois nécessaire de gérer l’affichage d’une grille ou d’un conteneur flexbox contenant plus d’éléments que l’espace disponible à l’écran. L’objectif ? Garder un nombre fixe d’items visibles selon la taille du conteneur tout en permettant à l’utilisateur de « scroller » pour accéder aux items restants.

maitriser-grid-et-flexbox-en-overflow

C’est une problématique classique pour les carrousels, galeries d’images ou encore les sliders d’articles. Aujourd’hui, je vous propose une solution propre et responsive à base de CSS Grid ou Flexbox en SCSS.

Problématique : afficher 4 items sur 9 disponibles

Prenons un cas concret : vous souhaitez afficher une grille ou flexbox contenant 9 éléments, mais que seulement 4 soient visibles sur les grands écrans, 3 sur tablette et 2 sur mobile. Le tout avec un comportement fluide et des colonnes qui respectent un gap uniforme, sans que la taille des items varie selon le nombre total d’éléments.

Solution : Grid et Flexbox en overflow

HTML

<div class="grid" style="--nb-items:9">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>

SCSS : version Grid (mise à jour)

@function grid-slider($nbItems_grid: 9, $nbVisibleItems: 4, $gap_grid: 20px) {
  $total-gap: ($nbVisibleItems - 1) * $gap_grid;
  @return repeat($nbItems_grid, calc((100% - #{$total-gap}) / #{$nbVisibleItems}));
}

* {
  box-sizing: border-box;
}

.grid {
  $gap: 20px;
  $nbItems: var(--nb-items);
  padding: 10px;
  background: red;
  display: grid;
  gap: $gap;
  grid-template-columns: grid-slider($nbItems_grid: $nbItems, $nbVisibleItems: 2, $gap_grid: $gap);
  overflow: auto;

  @media (min-width: 768px) {
    grid-template-columns: grid-slider($nbItems_grid: $nbItems, $nbVisibleItems: 3, $gap_grid: $gap);
  }

  @media (min-width: 1024px) {
    grid-template-columns: grid-slider($nbItems_grid: $nbItems, $nbVisibleItems: 4, $gap_grid: $gap);
  }

  .item {
    background: lighten(blue, 20%);
    border: 4px solid blue;
    height: 50px;
  }
}

SCSS : version Flexbox (mise à jour)

@function flex-slider($nbVisibleItems, $gap) {
  $total-gap: ($nbVisibleItems - 1) * $gap;
  @return calc((100% - #{$total-gap}) / #{$nbVisibleItems});
}

* {
  box-sizing: border-box;
}

.flex {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  padding: 10px;
  background: red;

  .item {
    background: lighten(blue, 20%);
    border: 4px solid blue;
    height: 50px;
    flex: 0 0 flex-slider($nbVisibleItems: 4, $gap: 20px);
  }

  @media (max-width: 1024px) {
    .item {
      flex: 0 0 flex-slider($nbVisibleItems: 3, $gap: 20px);
    }
  }

  @media (max-width: 768px) {
    .item {
      flex: 0 0 flex-slider($nbVisibleItems: 2, $gap: 20px);
    }
  }
}

Comment ça marche ?

Principe commun

Dans les deux approches (Grid et Flexbox), l’objectif est de limiter le nombre d’éléments visibles et de laisser les éléments restants accessibles via un scroll horizontal grâce à overflow: auto ou overflow-x: auto sur le conteneur.


Cas Grid : pilotage via le conteneur

  • Le nombre d’items visibles est défini au niveau du conteneur via grid-template-columns.
  • Nécessite d’indiquer le nombre total d’items via la variable CSS --nb-items.
  • Le scroll est activé sur la grille entière.

Exemple d’attribut :

<div class="grid" style="--nb-items:9">

Cas Flexbox : pilotage via les items

  • Ici, chaque item porte l’information sur sa largeur via le flex-basis.
  • Aucune variable globale n’est nécessaire, tout se passe directement sur les enfants.
  • Le scroll est activé via overflow-x: auto sur le conteneur flex.

Détail des calculs

Pour Grid

  1. (nbVisibleItems - 1) * gap : calcule l’espace pris par les gaps.
  2. (100% - total-gap) / nbVisibleItems : détermine la largeur de chaque colonne.
  3. La largeur est répétée sur tous les éléments grâce à repeat().

Pour Flexbox

  1. Même logique sur les gaps : (nbVisibleItems - 1) * gap.
  2. Mais ici, le résultat est appliqué sur chaque item via flex: 0 0 calc(...).

Responsive par design

Les media queries ajustent dynamiquement le nombre d’items visibles selon la taille d’écran sans jamais modifier manuellement la taille des colonnes.

Grid ou Flexbox : que choisir ?

Critère CSS Grid Flexbox
Mise en place Requiert --nb-items et calcul Grid Pas de variable supplémentaire nécessaire
Performance de rendu Plus lourd au rendu Meilleures performances de rendu dans tous les cas
Adapté à Grilles complexes ou multi-lignes Layouts horizontaux simples ou carrousels
Déclaration Déclaratif (grid-template-columns) Plus contrôlé via flex-basis sur chaque item
Maintenabilité Très clair pour les structures complexes Plus souple et rapide pour des cas simples

Les deux solutions aboutissent à un résultat similaire en matière d’overflow horizontal avec un nombre fixe d’items visibles.

Cependant :

  • Flexbox est plus léger en termes de performances de rendu, et ne nécessite pas de calcul externe comme --nb-items.
  • Grid, quant à lui, est plus déclaratif quand il s’agit de travailler avec des grilles complexes ou plusieurs lignes.

Si vous cherchez une solution rapide et performante pour un simple carrousel horizontal, Flexbox est souvent préférable. Pour des mises en page plus riches ou multi-dimensionnelles, CSS Grid reste une excellente option.

Cas d’usage : optimisation CLS avec Swiper JS

Lorsque vous travaillez avec Swiper JS, l’optimisation du CLS (Cumulative Layout Shift) est cruciale pour éviter des sauts de mise en page visibles avant l’initialisation du slider.

Dans ce cas précis, l’approche Flexbox est idéale pour précharger le layout.

Exemple SCSS : précharger avec Flexbox avant l’initialisation de Swiper

.flex:not(.swiper-initialized) {
  display: flex;
  overflow: hidden;
  gap: 20px;

  .item {
    flex: 0 0 flex-slider(4, 20px); // Nombre d’items visibles avant l’init Swiper
  }

  @media (max-width: 1024px) {
    .item {
      flex: 0 0 flex-slider(3, 20px);
    }
  }

  @media (max-width: 768px) {
    .item {
      flex: 0 0 flex-slider(2, 20px);
    }
  }
}

De cette façon, tant que Swiper n’est pas encore chargé, votre conteneur Flex conserve exactement la même mise en page que celle prévue par slidesPerView et spaceBetween. Le résultat est un layout stable dès le chargement initial.

À retenir : veillez toujours à ce que la configuration CSS (gap, nombre d’items visibles) soit identique à celle définie côté Swiper JS pour garantir l’alignement parfait entre CSS et JS.

Exemple en ligne

Pour voir cette solution en action, vous pouvez tester l’exemple complet ici :

➡️ Voir la démo sur JSFiddle

Conclusion

Au final, Grid et Flexbox sont deux outils puissants pour gérer l’overflow horizontal et afficher un nombre limité d’éléments visibles dans un conteneur scrollable.

  • Flexbox s’impose comme la solution la plus performante et la plus simple à mettre en place pour des cas classiques de sliders ou de carrousels, tout en optimisant les performances de rendu.
  • CSS Grid, quant à lui, est à privilégier lorsque vous devez gérer des mises en page complexes ou des systèmes multi-lignes où le positionnement fin de chaque élément est crucial.

Dans tous les cas, la logique reste la même : afficher un nombre fixe d’éléments visibles et permettre à l’utilisateur de scroller pour consulter les autres contenus hors viewport.

Cette double approche vous offre une flexibilité maximale selon la complexité et les exigences de votre projet.

Pour aller plus loin sur l’adaptation des layouts en fonction des écrans et renforcer la maîtrise du responsive, je vous recommande également de lire cet article complémentaire : Optimiser le placement des éléments sur mobile et PC tout en gardant la résponsivité.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *