Si, comme moi, vous aimez triturer un peu la mise en page de vos histoires Twine, les grilles CSS ont toutes les chances de vous intéresser. Il s’agit d’un outil très polyvalent, qui permet de disposer des éléments sur une grille en deux dimensions et qui est pris en charge par la plupart des navigateurs récents. Pour mieux comprendre son fonctionnement et les possibilités qu’il apporte, je vous propose de le découvrir à l’aide de trois petits exemples.

Pour pouvoir suivre ce tutoriel, il est recommandé d’être un peu à l’aise avec les langages HTML et CSS. Si ce n’est pas votre cas, je ne peux que vous recommander d’aller en apprendre un peu plus ; les bases ne sont pas très compliquées, et ça ouvre les portes vers plein d’options pour personnaliser l’apparence de vos histoires. Par exemple, commencez par notre article d’introduction au CSS pour Twine, et enchaînez avec un tutoriel plus avancé !

En-tête, menu et pied de page

Pour commencer, créons une mise en page simple comprenant un en-tête, une barre de menu à gauche, un espace à droite pour le contenu et un pied de page. Comme ceci :

Mise en page réalisée avec une grille CSS.
Notre objectif.

Commençons par ouvrir un nouveau passage, et créons-y la structure de notre page : un bloc « contenant » à l’intérieur duquel on placera nos quatre autres blocs.

{
<div class="contenant">
<div class="entete"><h1>Titre</h1></div>
<div class="menu">Menu</div>
<div class="contenu">Contenu</div>
<div class="pieddepage">Pied de page</div>
</div>
}

Il nous faut ensuite modifier la feuille de style de l’histoire. Il faut tout d’abord indiquer au contenant de se comporter comme une grille. Pour cela, rien de plus simple, il suffit d’ajouter ces lignes :

.contenant {
display: grid;
}

Il faut ensuite définir le nombre, et la taille, des lignes et des colonnes de la grille. Pour notre modèle simple, nous n’avons besoin que de trois lignes, et de deux colonnes, que nous allons définir à l’aide des propriétés grid-template-rows et grid-template-columns, respectivement. On en profitera pour définir la hauteur et la largeur de notre grille, et lui assigner une couleur de fond. Notre code devient :

.contenant {
display: grid;
background-color: #7c8cbf;
width: 100%;
height: 100vh;
grid-template-rows: 2fr 5fr 1fr;
grid-template-columns: 1fr 2fr;
}

Pour la largeur, on ne s’est pas embêtés : 100%, ça veut dire qu’il va garder la même largeur que son parent (tw-story si on travaille avec Harlowe).

Pour la hauteur, ça se complique : par défaut, les éléments HTML n’ont pas de hauteur, et s’ajustent à leur contenu ; or, on souhaiterait ici que notre grille occupe toute la hauteur de la page, même lorsqu’elle est vide. C’est ce que permet l’unité vh : elle définit la hauteur d’un élément en proportion de la taille de la fenêtre : 20vh, c’est 20 % de la hauteur du viewport, 100vh correspond donc à la hauteur totale du viewport.

Pour les lignes et les colonnes, on a choisi l’unité fr, qui, si elle peut paraître un peu étrange, est en réalité très pratique. Examinons notre ligne grid-template-columns: 1fr 2fr;. Elle signifie que nous voulons diviser notre grille en deux colonnes, celle de droite étant deux fois plus large que celle de gauche. Le navigateur va s’occuper tout seul de calculer leur largeur en fonction de l’espace disponible.
Vous me direz : pourquoi ne pas avoir utilisé les % ? Il y a plusieurs raisons à cela. La première : imaginons que, plus tard, je change d’avis, et je décide d’ajouter une troisième colonne, de même taille que la première. Si j’avais utilisé les %, je devrais non seulement ajouter la taille de ma troisième colonne, mais aussi ajuster celles des deux premières colonnes. Avec les fr, il suffit d’ajouter 1fr à la suite de la ligne, et c’est le navigateur qui s’occupe de faire le calcul. Idem si je décide d’élargir la colonne de droite : avec les fr, je ne modifie que la valeur de la deuxième colonne, la largeur de la première s’ajustera automatiquement, alors qu’avec les %, j’aurais dû rectifier les deux valeurs. La deuxième raison n’est pas évidente dans cet exemple, on en reparlera plus tard. L’utilisation des fr n’est évidemment pas obligatoire, on peut utiliser toute autre unité de longueur acceptée par CSS.

Maintenant que notre grille est formée, il va falloir la remplir. Pour cela, ciblons les blocs que nous avons créés dans notre passage. Nous allons leur assigner la place qui leur convient dans la grille. Ajoutons ces lignes à notre feuille de style :

.entete {
background-color: #152866;
grid-area: 1 / 1 / span 1 / span 2;
padding: 20px;
}

.menu {
background-color: #4b61a8;
grid-area: 2 / 1;
padding: 20px;
}

.contenu {
grid-area: 2 / 2;
padding: 20px;
}

.pieddepage {
background-color: #152866;
grid-area: 3 / 1 / span 1 / span 2;
padding: 20px;
}

La propriété qui nous intéresse, c’est grid-area. Elle permet de définir la cellule de départ et la taille de chacun de nos blocs. Analysons par exemple la ligne correspondante pour l’en-tête : grid-area: 1 / 1 / span 1 / span 2;. Les deux premiers nombres définissent le point de départ de notre zone : ici, la première ligne et la première colonne. Quant au span 1 et au span 2, ils signifient respectivement que notre zone doit occuper une seule ligne, et deux colonnes. Il est important de citer les valeurs dans cet ordre, et de les séparer par des « / ». Pour les blocs qui n’occupent qu’une seule cellule, on peut omettre les deux dernières valeurs : on se contente de spécifier la ligne et la colonne choisis, comme on l’a fait pour le menu et le contenu.

Si vous voulez réutiliser la même interface tout au long de votre histoire, vous pouvez bien sûr écrire le début du code HTML (jusqu’à <div class="contenu"> par exemple) dans un passage taggé header et la fin (à partir de </div> <div class="pieddepage">), dans un passage taggé footer ; seul le contenu sera modifié d’un passage à un autre, et ça vous épargne bien des copier-coller.

Il ne reste plus qu’à ajouter du contenu dans toutes ces zones ! À moins que vous ne préfériez en apprendre un peu plus sur les grilles avec un deuxième projet…

Retrouvez et téléchargez ce premier projet ici !

Un calendrier

Attelons-nous maintenant à un projet un peu plus compliqué, comportant bien plus de lignes et de colonnes : nous allons créer une page de calendrier.

Calendrier réalisé avec une grille CSS.
Notre objectif.

Nous avons donc besoin d’un tableau à 7 colonnes de même largeur (une par jour de la semaine) et à 6 lignes (une plus petite pour spécifier le jour de la semaine, 5 plus grandes pour les cases quotidiennes). On remarque que l’on veut trois types de cellules différentes : des cellules turquoise, d’autres gris clair et des gris foncé. Commençons par nous attaquer au passage Twine qui contiendra tout ça. On y ajoute le titre, notre bloc « contenant » et toutes les petites cases. Il y en a beaucoup, mais le code est très similaire, donc on peut allègrement copier-coller.

<h1>Juin 2018</h1>
{
<div class="calend">
<div class="jour">L</div>
<div class="jour">Ma</div>
<div class="jour">Me</div>
<div class="jour">J</div>
<div class="jour">V</div>
<div class="jour">S</div>
<div class="jour">D</div>
<div class="vide"></div>
<div class="vide"></div>
<div class="vide"></div>
<div class="vide"></div>
<div class="date">1</div>
<div class="date">2</div>
<div class="date">3</div>
<div class="date">4</div>
<div class="date">5</div>
<div class="date">6</div>
<div class="date">7</div>
<div class="date">8</div>
<div class="date">9</div>
<div class="date">10</div>
<div class="date">11</div>
<div class="date">12</div>
<div class="date">13</div>
<div class="date">14</div>
<div class="date">15</div>
<div class="date">16</div>
<div class="date">17</div>
<div class="date">18</div>
<div class="date">19</div>
<div class="date">20</div>
<div class="date">21</div>
<div class="date">22</div>
<div class="date">23</div>
<div class="date">24</div>
<div class="date">25</div>
<div class="date">26</div>
<div class="date">27</div>
<div class="date">28</div>
<div class="date">29</div>
<div class="date">30</div>
<div class="vide"></div>
</div>
}

On a bien nos trois classes de cases différentes, et on n’oublie pas les accolades qui font ignorer les sauts de ligne à Twine, sans quoi on risque d’avoir quelques surprises

On ouvre ensuite notre feuille de style pour mettre tout ça en forme ; commençons par le contenant :

.calend {
background-color: #212A2A;
width: 600px;
min-height: 400px;
padding: 10px;
display: grid;
grid-gap: 8px;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: 1fr repeat(5, 2fr);
grid-auto-flow: row;
overflow-x: hidden;
}

Outre les propriétés classiques qui définissent ses dimensions et sa couleur, on trouve bien sur le display : grid, et les grid-template-rows/columns. Pour ces derniers, la valeur de la propriété (la partie à droite des deux-points) est un peu différente de l’exemple précédent. En effet, plutôt que de déclarer une à une les largeurs (hauteurs) voulues pour chaque colonne (ligne), on a utilisé repeat pour pouvoir créer d’un seul coup un grand nombre de colonnes (lignes) de même dimension. Ainsi, repeat(7, 1fr) signifie « je veux 7 colonnes de même largeur », tandis que 1fr repeat(5, 2fr) signifie « je veux une première ligne d’une certaine hauteur, puis 5 autres qui sont toutes deux fois plus grosses que la première ».

On a aussi écrit une ligne grid-gap: 8px;, qui permet d’ajouter de l’espace entre les cellules, appelé gouttière, ce qui permet de les séparer sans leur ajouter de bordure. Cette petite ligne apparemment bien innocente va nous permettre d’aborder le deuxième avantage des fr sur les %. En effet, si on avait défini la largeur de nos colonnes en %, en s’arrangeant pour que la somme fasse 100 %, cet espace de 8 petits pixels entre les colonnes aurait fait déborder nos cellules à l’extérieur du contenant (et bien oui, 100 % de la largeur + 48 pixels, c’est strictement plus grand que 100 %). Plutôt que de devenir fou à essayer de tout recalculer par nous-même, on utilise les fr pour laisser le navigateur s’en occuper.

Enfin, dernière ligne consacrée à la grille :grid-auto-flow : row ;. C’est une propriété qui est très utile quand on a plein de cases à ajouter qui s’agencent de manière simple. Plutôt que de déclarer une par une la position de chaque case, on lui dit de commencer en haut à gauche, puis de remplir la première ligne. Une fois que toutes les colonnes de la première ligne sont remplies, on passe à la deuxième, en commençant à gauche, etc. Et ce jusqu’à avoir atteint la dernière case.

Comme on laisse toutes les cellules se placer automatiquement, pas besoin de spécifier leur position avec grid-area, les déclarations des classes jour, date et vide contiennent donc uniquement des propriétés de couleur ou de placement du texte très classiques.

Retrouvez et téléchargez ce calendrier ici !

Un plan

Pour finir, un projet encore un peu plus complexe : nous allons créer un plan avec des liens cliquables permettant de se déplacer dans diverses pièces d’un manoir.

Rez-de-chaussée du plan réalisé avec une grille CSS.
Notre objectif (rez-de-chaussée).
Étage du plan réalisé avec une grille CSS.
Notre objectif (étage).

Si vous remarquez quelques différences dans la présentation du plan, c’est normal : celui du rez-de-chaussée a été créé en utilisant des dimensions en % et des cases entourées de bordures noires, tandis que celui du premier étage utilise des dimensions en fr et grid-gap. Je vous laisse deviner lequel je préfère…

Cet exemple va permettre d’illustrer une autre manière de positionner les cellules dans la grille : en les nommant. On commence comme d’habitude, en créant la structure HTML dans un passage Twine.

<h2>Rez-de-chaussée</h2>
<div class="plan">\
<div class="smanger">[[Salle à Manger]]</div>\
<div class="bibli">[[Bibliothèque]]</div>\
<div class="cuisine">[[Cuisine]]</div>\
<div class="hall">[[Hall]]</div>\
<div class="salon">[[Salon]]</div>\
</div>
[[Monter à l'étage|Plan 1]]

La classe plan va nous servir de grille, et on crée une cellule pour chaque pièce de notre manoir. Dans la feuille de style, on va donc inscrire :

.plan {
display: grid;
grid-template-columns: 14.28% 14.28% 14.28% 14.28% 14.28% 14.28% 14.28%;
grid-template-rows: 16% 16% 16% 16% 16% 16% 4%;
}

.smanger {
grid-area: smanger;
}

.bibli {
grid-area: bibli;
}

.cuisine {
grid-area: cuisine;
}

.hall {
grid-area: hall;
}
.salon {
grid-area: salon;
}

La grille est donc bien définie, avec ses lignes et ses colonnes, et on a donné un nom à chacune des pièces à situer sur notre plan. Maintenant, on va pouvoir utiliser ces noms avec la propriété grid-template-areas pour expliquer où va quelle pièce sur le plan. Si on veut qu’une case de la grille reste vide, on inscrit juste un point à l’emplacement correspondant.

.plan {
display: grid;
grid-template-columns: 14.28% 14.28% 14.28% 14.28% 14.28% 14.28% 14.28%;
grid-template-rows: 16% 16% 16% 16% 16% 16% 4%;
grid-template-areas:
"smanger smanger bibli bibli bibli bibli bibli"
"smanger smanger bibli bibli bibli bibli bibli"
"smanger smanger hall hall hall salon salon"
"smanger smanger hall hall hall salon salon"
"cuisine cuisine hall hall hall salon salon"
"cuisine cuisine hall hall hall salon salon"
". . hall hall hall . . ";
}

On crée donc une sorte de tableau : les lignes sont délimitées par des guillemets et les colonnes, par au moins une espace. Je conseille toutefois d’an ajouter plus pour aligner vos colonnes, ça rend votre feuille de style bien plus lisible.

Il ne reste plus qu’à faire le même travail pour le premier étage, et bien sûr à créer une histoire mettant à profit cette interface !

Retrouvez et téléchargez ce dernier exemple ici !