ReactJS – Créer un widget responsive

Faire un widget responsive (qui s’adapte en fonction de la taille de son conteneur) avec ReactJS peut être compliqué : ici on ne peut pas utiliser de media query car ce n’est pas la taille de l’écran qui importe mais bien la taille du bloc qui va l’accueillir. Le module react-responsive-widget permet de créer une application ReactJS responsive sans se soucier de son intégration et avec une syntaxe simple proche de celle de la grille Bootstrap.
Bootstrap
La grille Bootstrap
Bootstrap est le framework le plus utilisé pour créer des sites/applications responsives. Il intègre un système de grille qui permet de créer simplement et efficacement des layouts de pages web mobile first. Par défaut, cette grille est structurée en 12 colonnes, ce qui lui permet de diviser facilement la page en 2, 3, 4 ou 6 parties. On définit ainsi la taille de chaque colonne sur une échelle de 1 à 12. On utilise donc col-*-12
pour prendre toute la largeur (100%) du conteneur, col-*-6
pour la moitié (50%), etc.
La grille Bootstrap utilise des media query range
pour adapter la structure d’une page en fonction de la résolution de l’écran sur laquelle elle est affichée. La permutation se fait selon 4 configurations, par défaut les valeurs sont :
xs
les écrans très petits (eXtra Small pour les smartphones) d’une résolution inférieure à 768pxsm
les petits écrans (SMall pour les tablettes) d’une résolution entre 768px et 992pxmd
les écrans moyens (MeDium pour les écrans d’ordinateur un peu ancien) d’une résolution entre 992px et 1200pxlg
les grands écrans (LarGe pour les écrans d’ordinateur récent) d’une résolution supérieure à 1200px
Pour l’utiliser il faut ainsi ajouter des classes CSS spécifiques à vos balises HTML. Par exemple, un composant ReactJS avec le code suivant (utilisant JSX), possèdera :
- 1 colonne (12 divisé par 12) occupant toute la largeur de l’écran avec les blocs les uns en dessous des autres sur les smartphones et tablettes
- 3 colonnes (12 divisé par 4) occupant chacune un tiers de l’écran avec les blocs les uns à côté des autres sur les écrans moyens et les grands écrans.
<div className="row">
<div className="col-xs-12 col-md-4">.col-xs-12 .col-md-4</div>
<div className="col-xs-12 col-md-4">.col-xs-12 .col-md-4</div>
<div className="col-xs-12 col-md-4">.col-xs-12 .col-md-4</div>
</div>
Limites de la grille Boostrap
La grille Bootstrap est une solution facile à mettre en place pour créer un layout de page, mais le fait qu’elle se base sur les media query
est un problème lorsque l’on souhaite développer un widget réutilisable qui puisse être intégré dans n’importe quel container.
En effet si je crée un widget responsive pour une page web avec une structure similaire à l’exemple précédent.
<div className="row">
<div className="col-xs-6 col-md-3">
<div className="glyphicon glyphicon-camera"></div>
<div>Pictures</div>
</div>
<div className="col-xs-6 col-md-3">
<div className="glyphicon glyphicon-facetime-video"></div>
<div>Videos</div>
</div>
<div className="col-xs-6 col-md-3">
<div className="glyphicon glyphicon-headphones"></div>
<div>Music</div>
</div>
<div className="col-xs-6 col-md-3">
<div className="glyphicon glyphicon-book"></div>
<div>Books</div>
</div>
</div>
Jusque-là tout va bien, mais que se passe-t-il si quelqu’un décide d’importer mon widget dans la barre latérale d’une autre page ?
Et ça … c’est moche ! Le problème vient ici du fait que les éléments sont disposés en fonction de la largeur totale de la page/écran et non en fonction de la place disponible (largeur du conteneur du widget). Dans le cas présent, le layout mobile conviendrait et il serait simple de surcharger les styles pour corriger cette page, mais en tant que développeur, on préfèrerait créer des composants qui s’adaptent eux-même à l’espace qu’on leur alloue.
React Responsive Widget
Présentation
Le module react-responsive-widget est un composant ReactJS simple, également disponible sur npm, il permet à votre widget de s’organiser en fonction de la taille du bloc dans lequel il se trouve.
Il utilise une grille similaire à celle proposée par bootstrap 3.3.7, mais pour éviter les conflits avec Bootstrap, toutes les classes sont préfixées avec app-*
.
Les permutations entre les différents layouts de votre composant responsive se font désormais sur la largeur du conteneur de la manière suivante :
xs
d’une largeur inférieure à 768px (par défaut)sm
d’une largeur entre 768px et 992px (par défaut)md
d’une largeur entre 992px et 1200px (par défaut)lg
d’une largeur supérieure à 1200px (par défaut)
Installation
Pour l’installer avec npm :
$ npm install – save react-responsive-widget
Si vous utilisez un bundler qui supporte ES6 vous pouvez l’importer de la manière suivante :
import ResponsiveContainer from 'react-responsive-widget'
Vous pouvez désormais utiliser le composant et créer une grille responsive pour votre widget.
import React from "react";
import ResponsiveContainer from "react-responsive-widget";
export default class App extends React.Component {
render() {
return (
<ResponsiveContainer>
<div className="app-row">
<div className="app-col-xs-12 app-col-md-4">.app-col-xs-12 .app-col-md-4</div>
<div className="app-col-xs-12 app-col-md-4">.app-col-xs-12 .app-col-md-4</div>
<div className="app-col-xs-12 app-col-md-4">.app-col-xs-12 .app-col-md-4</div>
</div>
</ResponsiveContainer>
)
}
}
Exemple
Revenons au cas qui posait problème avec la grille bootstrap et modifions le pour utiliser notre ResponsiveContainer.
<ResponsiveContainer>
<div className="app-row">
<div className="app-col-xs-6 app-col-md-3">
<div className="glyphicon glyphicon-camera"></div>
<div>Pictures</div>
</div>
<div className="app-col-xs-6 app-col-md-3">
<div className="glyphicon glyphicon-facetime-video"></div>
<div>Videos</div>
</div>
<div className="app-col-xs-6 app-col-md-3">
<div className="glyphicon glyphicon-headphones"></div>
<div>Music</div>
</div>
<div className="app-col-xs-6 app-col-md-3">
<div className="glyphicon glyphicon-book"></div>
<div>Books</div>
</div>
</div>
</ResponsiveContainer>
Notre widget se comporte toujours comme prévu en pleine largeur sur desktop et sur mobile et s’adapte correctement si on l’intègre dans un espace restreint.
Customisation
Il est possible de choisir les largeurs auxquelles les permutations s’effectuent de la manière suivante :
<ResponsiveContainer sm="800" md="1000" lg="1400">
...
</ResponsiveContainer>
Cette définition donnera le comportement suivant :
xs
d’une largeur inférieure à 800pxsm
d’une largeur entre 800px et 1000pxmd
d’une largeur entre 1000px et 1400pxlg
d’une largeur supérieure à 1400px
Comment ça marche ?
Comme il n’est pas possible d’utiliser des media query
css pour changer les styles en fonction de la taille du composant, react-responsive-widget
utilise une approche différente de Bootstrap.
Le ResponsiveContainer
surveille les événements de redimensionnement du container, il modifie la classe de ce dernier en fonction de sa largeur. Par exemple si le composant a une taille inférieure à 768px (xs
), le container aura la classe app-xs
. S’il dépasse 768px de largeur (sur un écran plus grand ou après resize) on aura app-sm
.
En XS :
En SM :
Exemple d’utilisation :
Nous avons utiliser ce composant pour créer plusieurs widgets et formulaires, dont un permettant aux utilisateurs d’obtenir un « tarif express » :
Grace à une syntaxe simple et connue par la plupart des développeurs, nous pouvons donc créer rapidement des widgets proposant une plus grande variété d’intégration.
Discussion