CSS3

Tailwind

Il faut reconnaître que Tailwind connait un franc succès et mérite qu’on s’y intéresse de près. De quoi s’agit-il ? C’est une librairie qui propose des classes utilitaires avec comme objectif de se passer des feuilles de style et de gérer complètement ce style directement dans le HTML. Ces classes sont très proches du CSS et on est donc très loin de librairies comme Bootstrap qui proposent des composants tout prêts à l’emploi. Ici la proposition est tout autre. C’est une philosophie différente, au lieu de créer des feuilles de style en utilisant des noms de classe plus ou moins judicieux au niveau du HTML, on utilise des classes de bas niveau directement dans les balises.

Une couleur à préciser ? Une marge à fixer ? Un ombre à ajouter ? Il suffit d’utiliser l’une des classes à disposition. Le fait d’avoir des classes de bas niveau implique deux choses : de bien connaître le CSS et de ne pas rester piégé dans un certain conformisme comme c’est généralement le cas avec des librairies comme Bootstrap (même si on peut quand même facilement en sortir).

On doit donc faire le deuil du vieux principe de séparation entre la structure et l’apparence qu’on a respectée pendant si longtemps !

On peut aussi se demander si le fait d’avoir une multitude de classes de bas niveau n’implique pas une librairie obèse longue à charger. Mais il se trouve que le concepteur de Tailwind a prévu un système pour faire une cure d’amaigrissement a sa librairie en ne conservant que les classes effectivement utilisées.

Un autre souci récurrent : le caractère « responsive » de nos pages. Ici aussi la librairie a été bien pensée dans ce sens avec des classes dédiées.

Je vous propose d’explorer quelques possibilités de Tailwind…

Installation

Pour ce qui concerne l’installation je ne vais pas insister parce que les cas sont multiples. Comme on est dans un blog consacré à Laravel je vais partir d’une installation de base de ce framework complété du package Breeze qui utilise Tailwind.

Je résume les commandes à utiliser.

composer create-project laravel/laravel tailwind
composer require laravel/breeze --dev
php artisan breeze:install
npm install
npm run dev
php artisan migrate

Vous devez obtenir la page d’accueil avec les liens pour l’authentification :

Si on regarde le contenu de resources/css/app.css on voit le chargement de Tailwind :

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

Je n’insiste pas sur cet aspect de l’installation, je vais me focaliser sur l’utilisation.

On va juste remplacer le code de la vue welcome par celui-ci pour nos essais :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Tailwind</title>
        <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    </head>
    <body class="p-12 bg-gray-300">
        coucou
    </body>
</html>

Si vous voyez un « coucou » détaché des bords sur l’écran sur un fond gris, c’est bon, on peut continuer !

Une grille

Quand on utilise une librairie CSS on dispose en général d’un système de grille efficace pour la mise en page. Qu’en est-il de Tailwind ? Il se trouve qu’il est très bien équipé et prend totalement en charge aussi bien Flex que Grid. Plutôt que de faire appel à la documentation officielle, au demeurant très bien faite, mais qui nécessite de nombreux clics, il vaut mieux utiliser une Cheat Sheet.

On a ainsi un panneau complet consacré au layout :

On y trouve les breakpoints par défaut :

On peut facilement changer ça dans la configuration si on le veut, mais je vais garder les valeurs par défaut.

On peut faire en sorte que le contenu occupe toute la largeur ou se limite à ces breakpoints.

Je préfère cette deuxième solution. En plus je vais utiliser une classe (mx-auto) pour centrer le contenu :

<body class="container mx-auto">

Voyons à présent le panneau du Grid (on peut aussi utiliser Flex mais soyons modernes !) :

On peut déjà définir le nombre de colonnes qu’on désire :

Partons sur 4 colonnes :

<body class="container mx-auto">
    <div class="grid grid-cols-4">
        <div class="border-blue-600 border-2 text-center">Colonne 1</div>
        <div class="border-blue-600 border-2 text-center">Colonne 2</div>
        <div class="border-blue-600 border-2 text-center">Colonne 3</div>
        <div class="border-blue-600 border-2 text-center">Colonne 4</div>
    </div>          
</body>

J’ai ajouté des classes pour visualiser les bords et centrer les contenus pour mieux voir ce qui se passe.

Ce qui serait bien serait d’ajouter des espaces entre les colonnes (et aussi les lignes s’il y en a). Un coup d’œil à notre cheat sheet :

On ajoute ça :

<div class="grid grid-cols-4 gap-2">

C’est parfait !

On peut aussi préciser le gap seulement pour les colonnes (gap-x) ou pour les lignes (gap-y).

Maintenant l’étape suivante est de rendre notre grille responsive pour s’adapter à toutes les largeurs d’écran. Là il faut savoir une chose : il suffit d’ajouter le préfixe d’un breakpoint à une classe pour limiter l’effet de celle-ci au breakpoint concerné. C’est pas clair ? Alors on passe à la pratique :

<div class="grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2">

Là je définis le nombre de colonnes que je veux pour chaque breakpoint. Pour les xl et au-delà j’ai mes 4 colonnes, mais ensuite pour les lg je n’ai plus que 3 colonnes :

Pour les ld j’en ai 2 :

Et en dessous je n’en ai plus qu’une :

Parfois on veut grouper des colonnes, le système Grid permet de le faire. Tailwind le prend aussi en charge :

On peut définir le nombre de colonnes occupées, le début et la fin. Voici un exemple :

<body class="container mx-auto">
    <div class="grid grid-cols-4 gap-2">
        <div class="border-blue-600 border-2 text-center">1</div>
        <div class="col-span-2 col-start-2 border-blue-600 border-2 text-center">2</div>
        <div class="border-blue-600 border-2 text-center">3</div>
        <div class="border-blue-600 border-2 text-center">4</div>
    </div>          
</body>

Le deuxième élément occupe deux colonnes et commence à la deuxième.

On voit donc qu’il est facile de créer une grille même sophistiquée…

Une barre de navigation

Je vais considérer à présent la création d’un composant très utile et répandu : une barre de navigation responsive. Cette fois on va utiliser Flex.

Voici le code :

<body>        
    <nav class="bg-red-500">            
        <div class="px-2 sm:px-4">            
            <div class="flex items-center justify-between h-14">
                <img class="h-8" src="https://svgsilh.com/svg/42527.svg" alt="rabbit">                
                <div class="hidden md:block space-x-2">
                    <a href="#" class="bg-red-800 text-white p-2 rounded-md">Accueil</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 p-2 rounded-md">Ventes</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 p-2 rounded-md">Clients</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 p-2 rounded-md">Produits</a>                 
                </div>
            </div>                          
            <div class="md:hidden">
                <div class="px-2 pb-2 space-y-1">
                    <a href="#" class="bg-red-800 text-white block p-2 rounded-md">Accueil</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 block p-2 rounded-md">Ventes</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 block p-2 rounded-md">Clients</a>
                    <a href="#" class="text-gray-100 hover:bg-red-800 block p-2 rounded-md">Produits</a>         
                </div>                    
            </div>
        </div>
    </nav>           
</body>

Sur écran large on a la barre étirée :

Et sur écran plus étroit (md) on a l’aspect vertical :

Plusieurs choses sont à noter. Le hover est facile à réaliser avec le suffixe hover. Par exemple là on change la couleur de fond d’un item au survol avec la syntaxe hover:bg-red-800.

Pour l’affichage ou la disparition on a la classe hidden et on peut utiliser les suffixes des breakpoints, par exemple ici md:block.

Je ne détaille pas toute la syntaxe qui est en fait très lisible.

Un composant

Toutefois, une chose me gêne, c’est la répétition du code. Tailwind propose plusieurs solutions à ce niveau. Mais avec Laravel le plus évident est d’utiliser des composants de Blade. On peut créer un composant item :

@props([
    'href' => '#', 
    'title', 
    'block' => false, 
    'active' => false
])

<a 
    href="{{ $href }}" 
    class="@if($active) bg-red-800 text-white @else text-gray-100 hover:bg-red-800 @endif p-2  @if($block) block @endif rounded-md"
>
    {{ $title }}
</a>

Ce qui simplifie d’autant la barre :

<nav class="bg-red-500">            
    <div class="px-2 sm:px-4">            
        <div class="flex items-center justify-between h-14">
            <img class="h-8" src="https://svgsilh.com/svg/42527.svg" alt="rabbit">                
            <div class="hidden md:block space-x-2">
                <x-item title="Accueil" active="true"/>
                <x-item title="Ventes"/>
                <x-item title="Clients"/>
                <x-item title="Produits"/>                
            </div>
        </div>                          
        <div class="md:hidden">
            <div class="px-2 pb-2 space-y-1">
                <x-item title="Accueil" active="true" block="true"/>          
                <x-item title="Ventes" block="true"/>
                <x-item title="Clients" block="true"/>
                <x-item title="Produits" block="true"/>     
            </div>                    
        </div>
    </div>
</nav>

On pourrait traiter le code de façon encore différente, par exemple avec un composant pour l’ensemble des items, mais on va en rester là pour l’exemple.

Interactivité

Ce qui manque dans notre barre de navigation c’est l’interactivité. Lorsqu’on est en mode écran étroit on devrait pouvoir ouvrir à la demande le menu. Pour réaliser ça il nous faut un peu de Javascript. Comme on utilise Tailwind autant aussi utiliser Alpine qui a été conçu par le même auteur et qui est pensé à la base pour seconder tailwind. On peut même avoir la documentation en français.

On y apprend qu’on peut charger la librairie avec un CDN :

<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>

On pourrait aussi évidemment utiliser mix.

On trouve aussi un exemple intéressant de menu déroulant :

<div x-data="{ open: false }">
    <button @click="open = true">Ouvrir le menu</button>

    <ul
        x-show="open"
        @click.away="open = false"
    >
        Elément de menu
    </ul>
</div>

On voit qu’on peut mémoriser des données avec x-data. Je vais l’utiliser dans la barre :

<nav x-data="{open : false}" class="bg-red-500">

On a aussi besoin d’un bouton qui ne doit apparaître que sur écran étroit :

<div class="flex items-center justify-between h-14">
    <img class="h-8" src="https://svgsilh.com/svg/42527.svg" alt="rabbit"> 
    <button class="md:hidden w-8 h-8 bg-red-700 text-gray-300 p-1 rounded-md focus:outline-none">
        <svg fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
            <path d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z">
            </path>
        </svg>
    </button>

Quand on clique sur le bouton il faut changer la valeur de open :

<button @click="open = !open"

Il ne reste plus qu’à faire agir cette variable sur le menu déroulant :

<div :class="{'hidden' : !open}" @click.away="open = false" class="md:hidden">

Et maintenant ça fonctionne !

Voici le code complet si vous vous êtes perdu en route :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Tailwind</title>
        <link rel="stylesheet" href="{{ asset('css/app.css') }}">
        <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
    </head>
    <body>        
        <nav x-data="{open : false}" class="bg-red-500">            
            <div class="px-2 sm:px-4">            
                <div class="flex items-center justify-between h-14">
                    <img class="h-8" src="https://svgsilh.com/svg/42527.svg" alt="rabbit"> 
                    <button @click="open = !open" class="md:hidden w-8 h-8 bg-red-700 text-gray-300 p-1 rounded-md focus:outline-none">
                        <svg fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
                            <path d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z">
                            </path>
                        </svg>
                    </button>                  
                    <div class="hidden md:block space-x-2">
                        <x-item title="Accueil" active="true"/>
                        <x-item title="Ventes"/>
                        <x-item title="Clients"/>
                        <x-item title="Produits"/> 
                    </div>
                </div>                          
                <div :class="{'hidden' : !open}" @click.away="open = false" class="md:hidden">
                    <div class="px-2 pb-2 space-y-1">
                        <x-item title="Accueil" active="true" block="true"/>          
                        <x-item title="Ventes" block="true"/>
                        <x-item title="Clients" block="true"/>
                        <x-item title="Produits" block="true"/>     
                    </div>
                </div>
            </div>
        </nav>           
    </body>
</html>

Conclusion

On a ainsi vu deux exemples d’utilisation de Tailwind et dans les deux cas il s’en sort fort bien ! Il existe une multitude de ressources en ligne. Voici une bonne page qui résume bien la situation. J’aime bien ce site qui propose une foule de composants tout prêts. Il existe aussi de plus en plus d’outils en ligne, pratiquement tous payants, pour générer de façon graphique et automatique des pages. D’ailleurs j’ai l’impression que Tailwind, qui est à la base un outil destiné à éviter d’acrire des feuilles de style en utilisant des classes de bas niveau, devient en fait un moteur de base pour des proposition de plus haut niveau. Du coup l’argument de l’absence d’homogénéité tombe un peu à l’eau…

 

Print Friendly, PDF & Email

Un commentaire

Laisser un commentaire