TP n°6 - Interfaces habillées en CSS avec Bootstrap
Table des matières
- 1. Introduction
- 2. Étape 1 : Intégration de Bootstrap dans l’application ToDo
- 2.1. Choix d’un thème Bootstrap
- 2.2. TODO Étape 1-a : Téléchargement de « Start Bootstrap - Bare »
- 2.3. TODO Étape 1-b : Consultation de la page d’exemple
- 2.4. TODO Étape 1-c : Examen de la structure du code HTML
- 2.5. Présentation d’un mécanisme simple d’intégration des ressources pour Symfony (assets)
- 2.6. Étape 1-d : Intégration de Bootstrap dans vos templates
- 3. Étape 2 : Intégration des menus pour Bootstrap
- 4. Étape 3 : Amélioration de la structure de la page d’affichage d’une tâche
- 5. TODO Étape 4 : Mise en place de Bootstrap dans votre projet
- 6. Évaluation
1. Introduction
Expérimenter la mise en place d’un
habillage graphique des pages de l’application « fil-rouge » ToDo en
utilisant les feuilles de style CSS.
Pour ce faire, on utilisera le framework Bootstrap, qui
permettra notamment de doter l’application d’une présentation réactive
compatible avec la consultation sur mobile.
Différents outils de mise au point seront mis à contribution pour ce faire, comme les outils du développeur de FireFox, et la barre d’outils Symfony.
2. Étape 1 : Intégration de Bootstrap dans l’application ToDo
Comprendre la façon dont le code des gabarits va être modifié pour intégrer Bootstrap, pour doter l’application d’une couche de présentation en CSS.
Nous allons modifier l’application fil-rouge todo-app
déjà étudiée dans la
séance précédente, pour la doter d’une couche de présentation avec
des feuilles de style CSS, en intégrant le framework
Bootstrap. L’application est
fonctionnellement équivalente au TP précédent,
toujours uniquement en mode consultation. Ce qui importe dans cette
nouvelle version est la façon de
mettre en forme avec du CSS nos pages HTML.
2.1. Choix d’un thème Bootstrap
Pour mettre en œuvre Bootstrap, nous allons intégrer une distribution provenant du projet « Start Bootstrap ».
Start Bootstrap propose différents modèles (templates) prêts à l’emploi, sous forme de distributions auto-suffisante de Bootstrap, à télécharger, incluant des exemples.
Nous vous suggérons de partir du template d’application « Bare » :
An unstlyed [ unstyled ?] starter template for Bootstrap 5 with predefined file paths - a great boilerplate for starting a new Bootstrap project
Figure 1 : template « Bare » de StartBootstrap (source : https://startbootstrap.com/templates)
Vous pourrez adapter la mise en forme ultérieurement selon vos goûts, en explorant d’autres variantes de mise en forme, de templates StartBootstrap, de thèmes Bootstrap…
Consultez les liens ci-dessus pour accéder à la documentation et aux exemples.
2.2. TODO Étape 1-a : Téléchargement de « Start Bootstrap - Bare »
Récupération dans le projet d’une distribution de BootStrap prête à l’emploi.
Positionnez-vous dans le répertoire du projet Symfony de l’application ToDo.
cd $HOME/CSC4101/tp-05/todo-app/
Récupérez la distribution Start Bootstrap Bare depuis le lien suivant, et extrayez le contenu dans le répertoire
public/
. Par exemple sous Linux :cd public wget https://github.com/startbootstrap/startbootstrap-bare/archive/gh-pages.zip unzip gh-pages.zip
Archive: gh-pages.zip e1b6c59cda92bed121c6785169c401b5810ee168 creating: startbootstrap-bare-gh-pages/ creating: startbootstrap-bare-gh-pages/assets/ inflating: startbootstrap-bare-gh-pages/assets/favicon.ico creating: startbootstrap-bare-gh-pages/css/ inflating: startbootstrap-bare-gh-pages/css/styles.css inflating: startbootstrap-bare-gh-pages/index.html creating: startbootstrap-bare-gh-pages/js/ inflating: startbootstrap-bare-gh-pages/js/scripts.js
ces ressources statiques ont été extraites dans le répertoire
public/startbootstrap-bare-gh-pages/
du projet.
2.3. TODO Étape 1-b : Consultation de la page d’exemple
Comprehension du principe d’adaptation responsive du contenu des pages Web
Vous avez installé les fichiers d’exemple de Bootstrap bare, dans la
partie publique du projet Symfony (le répertoire public/
), c’est à
dire que les fichiers qui s’y trouvent sont accessibles par HTTP comme
autant de ressources statiques qui sont servies par le serveur HTTP
directement, sans passer par l’exécution de l’application en PHP.
C’est tout à fait adapté à la transmission vers le navigateur Web (client HTTP) des images, feuilles de styles CSS et autres fichiers (contenant du code JavaScript), par exemple.
On va tester le résultat dans le navigateur.
Lancez le serveur Web Symfony depuis la racine du projet, comme d’habitude
cd .. symfony server:start
Consultez la page de démo de Bootstrap bare, que vous avez extraite dans
public/startbootstrap-bare-gh-pages/
, en la chargeant dans votre navigateur, par exemple sur l’URLhttp://localhost:8000/startbootstrap-bare-gh-pages/index.html
La page « A Bootstrap 5 Starter Template » s’affiche avec son menu sur fond noir affiché en haut de la page.
Utilisez l’outil « Vue adaptative » des outils du développeur de Firefox pour afficher une prévisualisation de ce que donnerait la consultation de cette page avec un ordiphone dont l’écran est plus petit.
Figure 2 : Accès au menu « Vue adaptative » de Firefox
Remarquez comme les menus sont masqués derrière un bouton « big mac » (à trois traits horizontaux) :
Figure 3 : Simulation d’écran d’ordiphone en mode portrait
Le contenu de la page est adaptatif, responsive : des éléments sont masqués dynamiquement, selon les besoins, pour s’adapter à la taille de l’écran de l’utilisateur.
Ça fonctionne, mais pas grâce à Symfony : tout ceci est du contenu statique, du point de vue de notre code PHP, comme en témoignent les logs qui restent silencieux.
Sous le capot, il y a plein de CSS et de Javascript à l’oeuvre. Voyons ça.
Utilisez le « Moniteur Réseau » des outils du développeur Firefox pour afficher le chargement des ressources
Figure 4 : Examen du chargement des ressources additionnelles
On voit que la page inclut le chargement d’une feuille de style CSS et 2 scripts JavaScript. Dans le moniteur réseau, on peut cliquer sur chaque ressource pour voir le chemin détaillé, respectivement dans les sous-répertoires
css/
etjs/
destartbootstrap-bare-gh-pages/
.On remarque qu’un des fichiers JavaScript est récupéré depuis le Web (depuis
cdn.jsdelivr.net
), alors que l’autre est local (localhost
).Il se peut que vous ne voyez pas exactement tous les fichiers apparaître comme dans la copie d’écran ci-dessus.
C’est probablement dû au cache du navigateur, qui permet d’économiser les transferts réseau, quand des ressources déjà connues sont inclues dans des pages. Plutôt que de redemander le transfert de la ressource avec une requête GET au serveur, le navigateur charge la copie qu’il a gardé dans son cache. Dans le moniteur réseau on voit la mention du cache dans la colonne « Transfert ».
Pour forcer le rechargement de toutes les ressources, appuyez sur la touche « SHIFT » (« Maj »), en même temps que vous rechargez la page avec le bouton de rechargement (ou « SHIFT » + « Ctrl-R »). Vous verrez alors les requêtes GET prendre plus de temps, et la taille du chargement dans la colonne « Transfert ».
Essayez, et vous devriez maintenant voir tous les scripts CSS chargés bien mentionnés dans le moniteur réseau.
Examinons maintenant le code de la page pour comprendre en détail comment ces ressources sont incluses.
2.4. TODO Étape 1-c : Examen de la structure du code HTML
Examen du source HTML des pages d’exemple de Bootstrap
On va voir le code HTML de cette page de démo, pour voir précisément comment les ressources sont incluses.
- Chargez le code source de
public/startbootstrap-bare-gh-pages/index.html
dans Eclipse (ou dans le navigateur : « voir le code source de la page » / Ctrl-U), - Identifiez où sont chargées les ressources de Bootstrap :
la feuille de style CSS (Bootstrap core CSS), référencée depuis l’entête HTML :
<head> ... <!-- Core theme CSS (includes Bootstrap)--> <link href="css/styles.css" rel="stylesheet" /> </head>
Quand le navigateur Web charge la page
public/startbootstrap-bare-gh-pages/index.html
qui contient<link href="css/styles.css" rel="stylesheet">
, deux requêtes HTTP se produisent :GET startbootstrap-bare-gh-pages/index.html
GET startbootstrap-bare-gh-pages/css/styles.css
L’URL de la ressource d’accès à la feuille de style est ici relative à la page (
href="css/styles.css"
indique le chargement de la ressourcestyles.css
depuis le sous-répertoire"css/"
).On verra ultérieurement comment le CSS s’applique au contenu… mais on doit d’abord terminer de cabler le chargement de ce fichier qui définit les règles CSS à appliquer à nos pages.
les scripts Javascript (Bootstrap core JavaScript) chargés à la fin du corps du HTML :
<!-- Bootstrap core JS--> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Core theme JS--> <script src="js/scripts.js"></script> </body> </html>
Nous étudierons le rôle du langage JavaScript dans une prochaine séance. Pour l’instant, il est juste utile de savoir que cela permet de déclencher des programmes qui s’exécutent dans le navigateur pour, par exemple, modifier l’affichage de la page. Comme on le voit ici, Bootstrap nécessite le chargement de scripts écrits en JavaScript, par exemple pour gérer le repositionnement des éléments de la page quand la largeur de l’écran change.
L’un des scripts (
scripts.js
) nous a été fourni dans l’archive de StartBootstrap Bare, puisqu’il est local (dans le sous-répertoirejs/
). L’autre (bootstrap.bundle.min.js
) fait référence à une version disponible en ligne sur un CDN (Content Delivery Network), qui héberge une copie de la version correspondante de la partie Javascript nécessaire à Bootstrap.Si vous êtes curieux, vous constaterez d’ailleurs qu’il n’y a pas grand chose d’intéressant dans
js/script.js
…
On va donc pouvoir s’inspirer du code HTML de cette page d’exemple, pour ajouter ce qu’il faut dans les gabarits de notre projet.
Ainsi, les mêmes ressources seront utilisables, pour autant qu’on
utilise le même chemin d’accès dans l’URL
(startbootstrap-bare-gh-pages/css/...
, etc.).
2.5. Présentation d’un mécanisme simple d’intégration des ressources pour Symfony (assets)
Nous allons présenter dans cette section un mécanisme qui peut être utilisé par
Symfony pour permettre l’inclusion de ressources statiques dans un
site, avec la fonction asset()
de Twig.
Nous détaillons le principe de ce mécanisme dans plusieurs sous-sections.
Lisez-les, et vous pourrez passer à la section suivante, qui vous guidera dans les différentes opérations à effectuer.
Comme on l’a vu en regardant le code HTML de la page d’exemple de Bootstrap bare, pour ajouter BootStrap dans une page HTML, il faut que celle-ci charge les ressources (statiques) correspondant aux feuilles de style CSS, et aux scripts JavaScript associés.
Si la page est dynamique, c’est à dire que son code HTML est généré par l’exécution de l’application Symfony, il faut agir sur la fabrication de la page, donc au niveau des gabarits Twig.
Dans ce qui suivra on s’inspirera du contenu du fichier HTML d’exemple
qui est fourni dans la distribution « Bare » de StartBoostrap (présent
dans public/startbootstrap-bare-gh-pages/index.html
), pour y reprendre des
bouts de code HTML, et les reporter dans les gabarits Twig de notre application.
Twig intègre une fonction, asset( )
qui permet de gérer l’inclusion de
telles CSS et JavaScript, mais aussi d’images.
Examinons donc tout d’abord le principe du fonctionnement de asset()
.
Lisez d’abord les explications de la section ci-dessous. Vous ne passerez aux modifications correspondantes, qu’après avoir tout lu.
2.5.1. Chemin d’accès aux ressources statiques
On souhaite modifier le gabarit Twig de base (base.html.twig
) pour y intégrer
les en-têtes HTML nécessaires, qui font référence aux
ressources des fichiers CSS.
Pas de mystère : on l’a vu ci-dessus, c’est réalisé via la balise standard de HTML : <link
rel="stylesheet" href="...
. On n’a qu’à l’ajouter dans le code HTML
dans base.html.twig
.
On va devoir indiquer, dans l’attribut href
de la balise <link>
, le chemin
d’accès Web à la ressource. Ce chemin (path) devra être exprimé du point de
vue du serveur Web de Symfony, pour qu’il trouve bien ces ressources
statiques là où elles sont présentes dans le projet.
Comme on a installé la distribution Start Bootstrap à l’intérieur du
répertoire public/
du projet (dans un sous-répertoire dédié :
startbootstrap-bare-gh-pages/
), la ressource peut être servie par
notre serveur Web (comme on l’a vu ci-dessus).
On peut donc spécifier le chargement des feuilles de style via l’ajout de ce code HTML dans notre gabarit de base :
<!-- Core theme CSS (includes Bootstrap)--> <link href="/startbootstrap-bare-gh-pages/css/styles.css" rel="stylesheet">
Dans notre environnement de développement Symfony, si on navigue sur
l’interface de l’application, cela aura donc pour conséquence que le
navigateur charge aussi la ressource présente à l’URL
http://localhost:8000/startbootstrap-base-gh-pages/css/styles.css
.
Cela se traduira bien par la requête auprès du serveur HTTP, du chemin
/startbootstrap-base-gh-pages/css/styles.css
. C’est correct, le
répertoire public/
du projet Symfony contient bien les fichiers
correspondants, dans un sous-répertoire startbootstrap-base-gh-pages/
,
là où nous avons recopié la distribution Boostrap provenant de « Start
Bootstrap ».
Le fichier de feuille de style devrait donc bien être chargé depuis le
répertoire où il a été installé
(public/startbootstrap-base-gh-pages/css/styles.css
).
Ça doit fonctionner. Mais il y a un petit inconvénient.
2.5.2. Inconvénient de la configuration des chemins « en dur »
En effet, dans la vie d’un site Web, il arrive souvent qu’on doive changer de jeu de feuilles de style.
Imaginons qu’est arrivée la saison des soldes. On pourrait vouloir pointer non-plus sur le style StartBootstrap bare mais sur StartBootstrap sales.
On pourrait ainsi souhaiter avoir plusieurs jeux de ressources statiques dans
différents sous-répertoires de public/
et vouloir les reconfigurer
simplement sans retoucher tout le code HTML des gabarits.
Si l’on souhaite changer de jeu de feuille de style, le fait de
mentionner startbootstrap-bare-gh-pages
« en dur » dans le code du
gabarit est assez peu élégant.
Le mécanisme asset()
permet d’y remédier simplement.
2.5.3. Principe de fonctionnement de asset()
Pour spécifier les chemins, on va donc préférer ajouter un degré de
flexibilité et utiliser la macro asset()
de Twig. Elle va faire le
lien avec l’emplacement dans lequel vous avez extrait la distribution
« Bare » de StartBoostrap (startbootstrap-bare-gh-pages/
), pour dire
où sont les « assets », les ressources du site.
On pourra ainsi configurer l’emplacement des ressources (assets
) de Symfony pour
pointer dans ce sous-répertoire. Cela reposera sur un fichier de
configuration du projet Symfony, config/packages/framework.yaml
(écrit en syntaxe YAML),
qui spécifiera la déclaration suivante :
framework: ... assets: base_path: '/startbootstrap-bare-gh-pages'
Ceci permettra d’utiliser la fonction asset()
de Twig dans les
gabarits, de façon à aller charger des ressources statiques présentes
à l’intérieur du sous-répertoire spécifié dans base_path
, startbootstrap-bare-gh-pages
.
On pourra alors utiliser asset()
pour spécifier les chemins dans nos gabarits Twig, toujours avec la balise
<link>
.
On aura juste à intercaler un appel à asset()
:
<!-- Core theme CSS (includes Bootstrap)--> <link href="{{ asset('css/styles.css') }}" rel="stylesheet">
Ce mécanisme nous permettra d’effectuer un changement de jeu de feuilles de style
par une simple reconfiguration de la déclaration de framework
/ assets
/ base_path
dans
le fichier de configuration du projet, sans rien à retoucher dans les
sources des gabarits Twig.
Si vous décidez d’ajouter des images dans votre projet, vous aurez à définir de la même façon leur emplacement pour qu’elles s’affichent correctement dans les pages.
Si tout ceci est clair, passons à la pratique pour modifier nos
gabarits dans Todo
afin d’utiliser asset()
pour inclure Bootstrap
dans nos gabarits.
2.6. Étape 1-d : Intégration de Bootstrap dans vos templates
Passons maintenant à la modification effective de l’application ToDo pour tester l’ajout des feuilles de style de Bootstrap.
Bootstrap est prêt à être intégré dans les gabarits pour que le HTML l’utilise, pourvu qu’on inclue le bon jeu de feuilles de style. C’est ce que nous allons faire maintenant.
2.6.1. TODO Intégration des feuilles de style CSS
Modifiez le contenu du fichier
config/packages/framework.yaml
pour ajouter la sectionassets
dansframework
(attention à respecter l’indentation faite par des espaces successifs) :framework: ... assets: base_path: '/startbootstrap-bare-gh-pages'
Attention, dans certains cas, Eclipse est susceptible de remplacer les caractères espace par des tabulations, dans le fichier yaml… ce qui posera des problèmes à l’exécution.
Attention à bien vérifier après le copier-coller au cas où des tabulations apparaîtraient.
Modifiez
templates/base.html.twig
pour remplacer tout le bloc Twigstylesheets
par le code ci-dessous :<!DOCTYPE html> <html> <head> ... {% block stylesheets %} <!-- Core theme CSS (includes Bootstrap)--> <link href="{{ asset('css/styles.css') }}" rel="stylesheet"> {% endblock %} {# stylesheets #} ...
Vous pouvez écraser l’ancien code qui était présent dans le bloc stylesheet.
Ce code, fourni initialement dans le squelette d’application, avait été inclus par défaut, lors de l’intégration d’EasyAdmin dans le squelette du projet Todo.
Il fonctionnait grâce à un autre mécanisme utilisable dans Symfony : « Webpack Encore ». Mais il s’avère plus lourd à mettre en oeuvre que les assets qui sont suffisants pour une application basique comme la notre.
De cette façon, pour la plupart des gabarits, ce block
stylesheets
par défaut contiendra la bonne valeur, incluant la feuille CSS de Bootstrap. Mais si une page particulière doit redéfinir d’autres feuilles de style, elle pourra toujours surcharger ce bloc pour créer une spécialisation locale.
2.6.2. TODO Ajout du chargement des scripts JavaScript
De façon similaire à ce que vous avez fait pour le bloc stylesheets
, intégrez le chargement des scripts JavaScript
nécessaires à Bootstrap.
Supprimez la déclaration du bloc Twig javascript
de l’en-tête <head>
,
qui utilisait « Webpack Encore ». Puis recopiez les balises <script
du fichier
d’exemple de Bootstrap bare, pour les intégrer via asset()
au bon endroit dans le
gabarit de base, dans un bloc javascripts
présent en fin de balise
<body>
.
Au final vous obtenez le contenu suivant pour templates/base.html.twig
:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{% block title %}Welcome!{% endblock %}</title> <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>"> {% block stylesheets %} <!-- Core theme CSS (includes Bootstrap)--> <link href="{{ asset('css/styles.css') }}" rel="stylesheet" /> {% endblock %} {# stylesheets #} </head> <body> {% block body %}{% endblock %} {% block javascripts %} <!-- Bootstrap core JS--> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Core theme JS--> <script src="{{ asset('js/scripts.js') }}"></script> {% endblock %} {# javascripts #} </body> </html>
Testez :
- Lancez l’exécution de l’application Symfony (
server:start
) dans un terminal.Si jamais vous avez une erreur sur la fonction
asset()
manquante, il est nécessaire d’installer le composant ad-hoc via une commande du type :symfony composer require symfony/asset
- Testez le chargement des pages, par exemple sur
http://localhost:8000/todo/
Observez les requêtes HTTP transmises par le navigateur dans l’outil Moniteur Réseau du développeur Web.
Vous devez constater qu’une ressource
styles.css
est bien chargée par le navigateur (200)Observez les traces d’exécution du serveur Web dans le terminal
Vous devez observer également un code de réponse 200, pour la ressource située dans
/startbootstrap-bare-gh-pages/css/styles.css
Ce « jeu de piste » paraît un peu compliqué, mais il nous montre que la macro
asset()
a bien fait le job.- Observez également comment les fichiers JS sont bien chargés via des requêtes HTTP supplémentaires.
2.6.3. TODO Observations du comportement de Bootstrap
Si vous rechargez les pages de l’application, elles incluent désormais la mise en forme par défaut de BootStrap.
Vous devriez voir immédiatement un impact sur la mise en forme des tableaux des pages de consultation des listes de tâches ou des attributs d’une tâche.
Si vous testez avec l’outil de vue adaptative, vous constaterez que certains contenu s’adaptent bien à la taille de l’écran.
Certains éléments de Bootstrap ont un effet immédiat sur le contenu
des pages Web… mais d’autres nécessitent de générer du HTML
contenant les bonnes balises ou des propriétés ad-hoc comme les class
utilisées par BootStrap.
On ne couvrira pas dans le cours comment tirer complètement parti de Bootstrap, mais sachez que certains composants de Symfony sauront (presque) automatiquement en tirer parti.
3. Étape 2 : Intégration des menus pour Bootstrap
Ajout dans l’application d’un composant de gestion de menus de navigation.
La plupart des applications Web intègrent des menus facilitant la navigation dans les grandes fonctions de l’application.
Nous allons ajouter un menu utilisant ces fonctionnalités de Bootstrap dans l’application ToDo.
Pour commencer, on va effectuer un ajout « manuel » du code gérant les menus.
3.1. TODO Étape 2.a : Test de menus codés « en dur »
Ajout du code HTML générant un menu avec Bootstrap, en recopiant le code HTML du fichier d’exemple.
La page d’exemple de Start BootStrap Bare contient un exemple de
menu intégré dans une section <nav>
du HTML.
Le principe d’organisation des menus à l’intérieur de cette section du HTML, est l’utilisation de listes à puces qui constituent une arborescence de liens, et que les feuilles de style de Bootstrap affichent sous forme de menus.
La documentation de Bootstrap explique comment on peut configurer les composants de navigation, mais plutôt que de lire toute la documentation, on va recopier l’exemple directement.
- Copiez le contenu de la section
<nav>
depublic/startbootstrap-bare-gh-pages/index.html
(à partir de<!-- Responsive navbar-->
) Collez-le dans le gabarit de base
templates/base.html.twig
, au bon endroit, à l’intérieur du block HTML<body>
.On va placer le contenu de la balise
<nav>
au début de la balise<body>
, avant l’inclusion du block Twigbody
destiné à contenir ce que fournissent les pages. Ainsi, le menu apparaîtra dans toutes les pages, en premier.Vous obtenez normalement quelque-chose du style :
... <body> <!-- Responsive navbar--> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="#">Start Bootstrap</a> ... </div> </nav> {% block body %}{% endblock %} {% block javascripts %} ... {% endblock %} {# javascripts #} </body>
- Observez le résultat dans la page
http://localhost:8000/todo/,
avec l’apparition d’un menu. Utilisez l’inspecteur HTML des outils du développeur dans le navigateur pour repérer les balises concernées (
<ul>
,<li>
,<a>
, …).Figure 5 : Inspection du contenu du HTML pour la barre de menu
Les liens des entrées de menu sont-elles actives ? Pourquoi ?
Indice : regardez la la valeur de l’attribut
href
des balises HTML<a
(liens) présentes dans les balises<li>
(entrées de menus). Ce ne sont pas des liens vers d’autres pages… juste des liens relatifs dans la page courante.Adaptez le code du gabarit pour faire fonctionner un menu « Todo », contenant des entrées de menus actives, qui renvoient vers les routes de votre contrôleur :
- « Tasks » :
todo_list
- « Tags » :
tag_list
Vous utiliserez pour ce faire l’instruction
path()
de Twig, pour spécifier les routes à intégrer dans les chemins des attributshref
.Vous devriez par exemple obtenir quelque-chose du genre :
<nav class=... <div class="container"> <a class="navbar-brand" href="{{ path('home') }}">Todo app</a> <button class="navbar-toggler" ... <div class="collapse navbar-collapse" ... <ul class=... <li class="nav-item"><a class="nav-link" href="{{ path('todo_list') }}">Tasks</a></li> <li class="nav-item"><a class="nav-link" href="{{ path('tag_list') }}">Tags</a></li> ... </ul> </div> </div> </nav>
- « Tasks » :
Testez que le menu est maintenant opérationnel.
Par contre, sa mise-à-jour au fur
et à mesure de l’ajout de nouvelles routes dans l’application est un
peu pénible : il faut se replonger dans la structure du HTML de cette
section <nav>
.
Voyons comment on peut configurer la structure de ces menus plus simplement.
3.2. TODO Étape 2-b : Intégration du composant de gestion de menus
Intégrer un nouveau composant permettant de générer le code des menus Bootstrap plutôt que d’avoir à le coder « en dur ».
Si on simplifie, les menus ne sont, après-tout qu’une arborescence de
balises <ul>
et <li>
contenant des liens vers les routes de
l’application.
On va utiliser le bundle « Bootstrap Menu » pour Symfony de Cameron Murphy, qui va faciliter la génération de cette arborescence de balises HTML.
Cette bibliothèque permet d’ajouter assez simplement une définition de
menus dans un fichier YAML, présent dans
config/packages/bootstrap_menu.yaml
et de les utiliser ensuite via la
macro render_bootstrap_menu()
disponible dans les gabarits Twig.
Cette macro générera une liste à puce (balises <li>
) qui seront mises
en forme par Bootstrap comme il faut sous forme d’entrées de menus.
Procédez aux étapes suivantes :
Installez le bundle correspondant :
symfony composer require camurphy/bootstrap-menu-bundle
Créez le fichier de configuration
config/packages/bootstrap_menu.yaml
, en y plaçant ceci, qui définit un menu ’main
’ composé d’un seul élément (’todos
’) :bootstrap_menu: menus: main: items: todos: label: 'Tasks' route: 'todo_list' tags: label: 'Tags' route: 'tag_list'
Modifiez le gabarit
templates/base.html.twig
pour que la structure des menus de la balise<nav>
soit incluse dans un nouveau bloc Twigmenu
.De cette façon, ce même code apparaîtra dans toutes les pages de l’application, sauf si une page surcharge le contenu du block
menu
.Supprimez les balises
<li>
pour les remplacer par l’appel à la macro Twigrender_bootstrap_menu()
.Vous devriez obtenir quelque chose du style :
<body> {% block menu %} <!-- Responsive navbar--> <nav class=... <div class="container"> <a class="navbar-brand" href="#">Todo App</a> <button class="navbar-toggler" ... <div class=... <ul class=... {{ render_bootstrap_menu('main') }} </ul> </div> </div> </nav> {% endblock %}{# menu #} {% block body %}{% endblock %} ...
On a repris ici les indications du README du bundle (installé par composer dans
vendor/camurphy/bootstrap-menu-bundle/README.md
), pour obtenir le code HTML souhaité.Exécutez un
cache:clear
:symfony console cache:clear
Vous pouvez maintenant tester et vérifier que le menu « Tasks » permet de naviguer vers la route
todo_list
.L’intégration de BootStrap avance bien. Avec son menu, l’application commence à avoir une expérience utilisateur (UX) proche des standards.
Il reste néanmoins à tirer parti de Bootstrap pour rendre le contenu des pages réellement adapatatif.
4. Étape 3 : Amélioration de la structure de la page d’affichage d’une tâche
Tirer parti des fonctionnalités de la grille Bootstrap pour mettre en œuvre les pages de l’application « fil-rouge ».
Bootstrap fournit des fonctions permettant notamment de modifier l’emplacement des éléments sur la page, pour s’adapter à la place disponible sur les petits écrans.
Vous avez déjà expérimenté cela dans l’étape précédente au niveau du menu de l’application. Nous allons maintenant modifier la structure des pages de l’application afin d’en tirer parti.
4.1. Étape 3-a : Mise en place d’une structure de grille Bootstrap
Modifier le corps des pages HTML de l’application pour intégrer la structure de conteneurs Bootstrap.
Nous allons utiliser la structure de grille de Bootstrap pour mettre en forme le contenu des pages, à la fois pour la présentation générale, mais aussi pour certains détails des propriétés d’une entité.
4.1.1. TODO Modification de la structure du gabarit de base
Vous allez modifier le gabarit de base templates/base.html.twig
pour
structurer le contenu du bloc Twig body
de façon à inclure deux
parties : main et footer qui seront deux lignes au sein d’un
conteneur Bootstrap.
Ces deux parties seront elles-mêmes des blocs Twig permettant une surcharge pour que chaque gabarit de page n’inclue finalement que la partie utile à insérer au sein de ces deux lignes.
Ces parties sont gérées via des
conteneurs
définis grâce aux balises HTML <div>
et à la classe container
de
Bootstrap.
Modifiez le gabarit de base pour reprendre la structure suivante, là
où auparavant on n’avait qu’un bloc Twig body
vide :
... {% block body %} <div class="container body-container"> <main> {# Ici la partie utile que les gabarits des pages vont surcharger #} {% block main %} <div class="row"> <div class="col-md-12"> <p> <i>MAIN</i> </p> </div> </div> {% endblock %} {# main #} </main> </div> <!-- /.body-container --> {% block footer %} <footer class="text-center text-lg-start bg-light text-muted"> <div class="text-center p-4" style="background-color: rgba(0, 0, 0, 0.05);"> FOOTER </div> </footer> {% endblock %}{# footer #} {% endblock %} {# body #}
4.1.2. TODO Test de la nouvelle structure
Testez que cela fonctionne : vous devez voir apparaître « FOOTER » en bas des pages.
Attention : pour que cela fonctionne, il faut que les gabarits des pages du site surchargent bien le
nouveau bloc Twig main
qu’on vient d’introduire dans le gabarit de base (et pas l’ensemble du block body
).
Modifiez par exemple templates/index.html
pour utiliser cette nouvelle
organisation de la page, en remplaçant le bloc body
par un bloc main
:
{% extends 'base.html.twig' %} {% block title %}Welcome!{% endblock %} {% block main %} <h1>Welcome</h1> <p>{{ welcome }}</p> {% endblock %} {# main #}
Testez, et vérifiez dans l’outil des gabarits Twig de la barre d’outils de symfony, que l’on a bien la bonne compilation
des gabarits, avec une surcharge de main
par index.html.twig
, à
l’intérieur du body
de base.html.twig
.
Rendering Call Graph main └ index.html.twig │ └ base.html.twig │ └ index.html.twig::block(title) │ └ base.html.twig::block(stylesheets) │ └ base.html.twig::block(menu) │ │ └ @BootstrapMenu/link.html.twig │ │ │ └ @BootstrapMenu/href.html.twig │ │ └ @BootstrapMenu/link.html.twig │ │ └ @BootstrapMenu/href.html.twig │ └ base.html.twig::block(body) │ │ └ index.html.twig::block(main) │ │ └ base.html.twig::block(footer) │ └ base.html.twig::block(javascripts) └ @WebProfiler/Profiler/toolbar_js.html.twig └ @WebProfiler/Profiler/toolbar.html.twig │ └ @WebProfiler/Profiler/cancel.html.twig::block(toolbar) │ └ @WebProfiler/Profiler/toolbar_item.html.twig └ @WebProfiler/Profiler/toolbar.css.twig
4.2. Étape 3-b : Application aux pages d’affichage des tâches
Modification des pages de l’application pour utiliser cette nouvelle structure.
4.2.1. TODO Modification de la page de liste des tâches
Remplacez le bloc body
par un bloc main
dans le gabarit de la page d’affichage de la liste des tâches, templates/todo/index.html
.
La différence d’affichage se voit principalement au niveau de l’occupation de toute la largeur de la page, ou de l’affichage seulement sur une portion de la largeur, et sur l’affichage du footer.
Jusque-là, rien de très difficile, mais vous constatez comment on peut relativement simplement modifier tout le contenu d’un site, à partir du moment où la structure d’imbrication des blocs et sous-blocs est bien conçue dans les gabarits de base.
En pratique, sur de « vraies » applications Web, cela nécessitera d’avoir bien réfléchi à l’avance à cette structure, sous peine de devoir retoucher de très nombreux gabarits.
4.2.2. TODO Modification de la page d’affichage d’une tâche
Vous allez maintenant ajuster le contenu de la page d’affichage des tâches, correspondant
aux URL de type .../show/N
, pour intégrer une structure de type
formulaire Bootstrap.
Dans cette page, on utilise la mise en page des formulaires, pour afficher des données en consultation uniquement (on verra les formulaires de saisie dans des séances ultérieures).
Modifiez maintenant le gabarit de la page d’affichage des détails d’une tâche
todo/show.html.twig
, de façon à ce que le coeur de la page (dans le blocmain
), contienne quelque chose du type de ce code Twig, au lieu de la balise<table>
:<div class="form-horizontal"> <div class="form-group row"> <label class="col-sm-2 col-form-label">Id</label> <div class="col-sm-10"> <div class="form-control form-control-plaintext"> {{ todo.id }} </div> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label-lg">Libellé</label> <div class="col-sm-10"> <div class="form-control form-control-plaintext form-control-lg"> {{ todo.title }} </div> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Terminé</label> <div class="col-sm-10"> <div class="form-control form-control-plaintext"> {{ todo.completed ? "oui" : "non" }} </div> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Created</label> <div class="col-sm-10"> <div class="form-control form-control-plaintext"> {{ todo.created ? todo.created|date('Y-m-d H:i:s') : '' }} </div> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Updated</label> <div class="col-sm-10"> <div class="form-control form-control-plaintext"> {{ todo.updated ? todo.updated|date('Y-m-d H:i:s') : '' }} </div> </div> </div> </div> <!-- form-horizontal -->
Examinez les détails de l’affichage de la « fiche » qui liste les propriétés d’une tâche. Notez comme on a utilisé une mise en place « tabulaire », avec un « formulaire » en lecture seule, au lieu d’une
table
HTML :- on utilise une section
<div>
, qui reproduit une présentation de formulaire avec les libellés et leurs valeurs sur la même ligne (cf. « Horizontal form »). - Les éléments de la fiche sont mis en page via des lignes
row
et des largeurs de colonne sur la grille (col-sm-...
) - Les valeurs des champs (
<div class="form-control">
) sont rendus en « lecture seule » au lieu d’être des champs de saisie de formulaires, via la classeform-control-plaintext
(cf. « Readonly plain text »).
On manipule différentes balises HTML et leurs propriétés utilisées par le CSS, notamment les classes (
class
) qui vont servir à Bootstrap à formatter la présentation « formulaire » dans sa grille.C’est plutôt complexe à apprendre, mais nous n’avons pas vraiment le temps de détailler tout ça, donc on va procéder par copier/coller, et espérer que ça fonctionne.
- on utilise une section
Testez le redimensionnement de l’écran, via l’outil de « Vue adaptative », qui permet de faire une prévisualisation en mode petit écran de smartphone, dans les outils du développeur de FireFox. Vous constatez que l’interface reste utilisable, et que la mise en forme initiale évolue, grâce à Bootstrap qui intègre des fonctions d’adaptation du rendu de l’interface.
Bien évidemment, nous n’avons fait que survoler beaucoup de détails, notamment la façon dont Bootstrap fonctionne « sous le capôt », au niveau CSS et JavaScript… nous n’avons pas le temps de rentrer beaucoup plus loin dans les détails.
Supprimez l’affichage des styles via le menu « Affichage / Style de la page / Aucun style » de Firefox.
Les infos apparaissent toujours… c’est mieux que rien, et avec un peu de chance, les infos utiles sont accessibles en premier aux utilisateurs de lecteurs d’écran ou d’autres dispositifs d’accessibilité.
L’essentiel à retenir, est que Bootstrap fonctionne sur la base d’une grille, et va prendre des décisions utiles pour gérer au mieux l’affichage du contenu, lorsqu’on devra utiliser l’application avec un navigateur sur un terminal à écran réduit.
Peaufiner l’interface requerrait encore des heures de travail, mais ce ne serait pas raisonable dans le contexte de notre module.
On a compris les grands principes, sur l’utilisation de Bootstrap dans nos gabarits pour intégrer du CSS et un comportement adaptatif. C’est déjà pas mal pour du copier/coller.
5. TODO Étape 4 : Mise en place de Bootstrap dans votre projet
Vous avez maintenant les connaissances nécessaires pour mettre en place Bootstrap dans votre projet, comme nous l’avons fait pour l’application « fil-rouge ».
Poursuivez la séance en déroulant les étapes du guide de réalisation du projet.
Les éléments pour vous guider sur cette étape d’habillage des pages sont identifiés par le label « Après_TP_6 » dans la section du guide de réalisation.
6. Évaluation
Vous avez expérimenté avec les éléments suivants :
- comment ajouter des feuilles de style CSS et scripts JavaScript dans le code des pages Web, en s’inspirant d’un exemple statique existant
- l’ajout de composantes de Boostrap avec les balises structurantes
<div>
pour rendre les pages adaptatives - la structure de la grille utilisée par Bootstrap
- la surcharge de blocs Twig dans les gabarits pour standardiser la structure des pages
- l’outil d’inspecteur HTML du navigateur, et l’outil de vue adaptative
- différents utilitaires pour Symfony :
asset()
, le générateur de menus BootStrap, etc.