Guide de style

Gestion des fichiers de style

Les feuilles de style sont basées sur des sources SASS situées dans le répertoire css_sources. On peut les compiler à la demande avec la commande make css ou automatiquement à chaque modification avec la commande make css_watch. Les fichiers .sass sont structurés en fragments correspondant aux diverses parties structurelles du site (mise en forme générale, menu, tableaux, etc… ).

Règles générales

Quand on signale l’absence de contenu (« Pas de produit », « Aucun contenu n’a été ajouté », « Pas de devis »…), mettre le texte correspondant en italique au moyen d’un élément <em>.

Colonnes

2 à 4 Colonnes

Pour structurer le contenu d’une <div> en deux à quatre colonnes, appliquer les classes layout et flex, et une des classes two_cols three_cols ou four_cols. Cela répartit tous les éléments directement contenus dans cette <div> en 2, 3 ou 4 colonnes de largeur égale.

Pour les structures en 2 colonnes, 4 classes à ajouter à layout flex two_cols permettent d’obtenir deux colonnes de largeurs différentes :

  • third colonne de gauche 1/3, colonne de droite 2/3 (<div class="layout flex two_cols third">)

  • third_reverse colonne de gauche 2/3, colonne de droite 1/3 (<div class="layout flex two_cols third_reverse">)

  • quarter colonne de gauche 1/4, colonne de droite 3/4 (<div class="layout flex two_cols quarter">)

  • quarter_reverse colonne de gauche 3/4, colonne de droite 1/4 (<div class="layout flex two_cols quarter_reverse">)

Rangs divisés en colonnes

Une <div> considérée comme un rang (particulièrement dans les formulaires) est structurée en colonnes en utilisant les classes col-md-1 (1/12ème) à col-md-12 (12/12èmes, 100%) sur chaque élément du rang. La gestion responsive de la largeur des colonnes dispense d’utiliser les classes de type col-xs ou autre, qui n’ont pas d’effet et n’espacent pas les colonnes de formulaires.

Espacement

Des classes permettent de créer de l’espacement entre blocs en ajoutant du padding : Quand un bloc n’est pas séparé visuellement des blocs voisins, on privilégie l’espacement vertical seul pour éviter de perdre les alignements verticaux.

  • content_vertical_padding ajoute une unité d’espacement sur les 2 côtés au-dessus et au-dessous du bloc

  • content_vertical_double_padding ajoute deux unités d’espacement sur les 2 côtés au-dessus et au-dessous du bloc

On peut ajouter une séparation visuelle horizontale :

  • separate_top ajoute une ligne au-dessus du bloc

  • separate_bottom ajoute une ligne au-dessous du bloc

  • separate_top_dashed ajoute une ligne pointillée au-dessus du bloc

  • separate_bottom_dashed ajoute une ligne pointillée au-dessous du bloc

Pour les blocs séparés visuellement par une bordure ou un fond de couleur :

  • content_padding ajoute une unité d’espacement sur les 4 côtés du bloc

  • content_double_padding ajoute deux unités d’espacement sur les 4 côtés du bloc

  • content_horizontal_padding ajoute une unité d’espacement sur les 2 côtés latéraux du bloc

  • content_horizontal_double_padding ajoute deux unités d’espacement sur les 2 côtés latéraux du bloc

Vues mobile et tablette

Il est possible de masquer certains contenus en fonction de la taille de l’écran, par exemple pour préciser un libellé sur les grands écrans, ou ne pas afficher une colonne de tableau sur mobile.

En ce qui concerne les libellés, ne pas oublier une info-bulle avec le texte complet (les mises en page « petits écrans » et « très petits écrans » sont aussi utilisées par les déficients visuels utilisant l’agrandissement du texte sur écran d’ordinateur).

  • Les éléments portant la classe no_mobile ne seront pas affichés sur les très petits écrans (moins de 31.25rem de large)

  • Les éléments portant la classe no_tablet ne seront pas affichés sur les petits écrans (moins de 50rem de large)

Exemple pour un bouton :

<button class="btn btn-primary" title="Programmer un nouveau rendez-vous" onclick="toggleModal('next_activity_form'); return false;">
        <svg><use href="${request.static_url('endi:static/icons/endi.svg')}#plus"></use></svg>
        Nouveau<span class="no_mobile">&nbsp;rendez-vous</span>
</button>

En ce qui concerne les boutons, on peut aussi plus simplement les marquer pour qu’ils se transforment en bouton à icône seule pour les petits et très petits écrans en ajoutant la classe icon_only_tablet ou pour les très petits écrans seulement avec icon_only_mobile.

<button class="btn btn-primary icon_only_mobile" title="Programmer un nouveau rendez-vous" onclick="toggleModal('next_activity_form'); return false;">
        <svg><use href="${request.static_url('endi:static/icons/endi.svg')}#plus"></use></svg>
        Nouveau rendez-vous
</button>

Chargement de contenu

On peut matérialiser le chargement de contenu pour faire patienter en attendant qu’il soit disponible à trois niveaux :

  • au niveau de tout l’écran en insérant une <div class="loading_box"> en fin de la <div class="base_layout layout flex screen">.

  • en superposition d’une modale en insérant une <div class="loading_box"> en fin de la <div class="modal_layout">.

  • en superposition d’un bouton en ajoutant la classe loader au <button> et en insérant un <span class="loading_box"> en fin du <button>.

<div class="loading_box">${api.icon('circle-notch')}</div>
<button class="btn icon loader">
        ${api.icon('check')}
        Libellé du bouton
        <span class="loading_box">${api.icon('circle-notch')}</span>
</button>

Impression

Il est possible de masquer certains éléments lors de l’impression en leur ajoutant la classe hidden-print.

Inversement, il est possible d’ajouter des éléments qui ne seront visibles qu’à l’impression en leur ajoutant la classe print-only.

Titre d’écran

Le titre de l’écran (contenu dans le <h1> dans l’en-tête de l’écran) peut-être précisé par du texte inséré dans une balise <small>.

<h1>Devis « titre du devis » <small>pour le client Prénom Nom</small></h1>

Quand le titre passe sur deux lignes, le texte de la deuxième ligne est automatiquement affiché dans une police plus petite.

Le titre <h1> peut être précédé d’une icône qui sera visible sur les écrans plus grands que les mobiles. Elle est insérée par une balise <svg> qui peut au besoin prendre les classes valid, invalid ou caution.

Le bloc de notifications est inséré à la fin de l’en-tête de l’écran. Il comprend soit une icône (pas de notifications) ou un bouton avec un compteur (qui ouvre les notifications).

Sans notifications :

<ul class="layout flex tools">
        <li aria-live="polite">
                <span title="Pas de notification" class="icon">
                        ${api.icon('bell')}
                        <span class="screen-reader-text">Pas de notification</span>
                </span>
        </li>
</ul>

Avec notifications :

<ul class="layout flex tools">
        <li aria-live="polite">
                <button class="icon unstyled" onclick="demoSW_showNotifs();" title="Afficher 1 notification" aria-label="Afficher 1 notification">
                        ${api.icon('bell')}
                        <span class="bubble">1</span>
                </button>
        </li>
</ul>

Fil d’Ariane

Le fil d’Ariane décrit le chemin parcouru pour accéder à l’écran en cours.

Il est contenu dans une liste <ul class="breadcrumb">.

Le premier lien de la liste permet de remonter d’un niveau. Les liens suivants décrivent l’arborescence compléte. Le dernier élément de la liste n’est pas un lien mais le titre de l’écran en cours.

<ul class="breadcrumb">
        <li class="back_link">
                <a href="chemin-ecran-parent" class="icon" title="Remonter d’un niveau">${api.icon('arrow-left')}</a>
                <span class="screen-reader-text">Remonter d’un niveau</span>
        </li><li>
                <a href="chemin-ecran-grand-parent">Écran grand parent</a>
        </li>
        <li>
                <a href="chemin-ecran-parent">Écran parent</a>
        </li>
        <li class="active">
                <span>Écran en cours</span>
        </li>
</ul>

Tableaux

Tableaux <table>

  • Les tableaux <table> sont contenus dans une <div class="table_container"> qui permet de gérer les débordements horizontaux des tableaux sur petits écrans (scroll horizontal plutôt que débordement de page)

  • On peut permettre un défilement horizontal sur les grands écrans en ajoutant <div class="table_container scroll_hor">. Attention ceci n’est pas compatible avec les boutons d’action à sous-menus (qui seraient coupés à la fin du tableau si le défilement horizontal est activé).

  • La classe top_align_table permet d’aligner verticalement le contenu de chaque case du tbody en haut de case. À utiliser pour les tableaux dont certaines cases ont des contenus très longs, pour faciliter la lecture ligne à ligne. Sans cette classe, l’alignement vertical dans les cases est centré par défaut.

  • La classe hover_table permet d’ajouter une couleur au survol à chaque ligne du tableau. À utiliser quand une ou plusieurs actions peuvent être réalisées en cliquant sur une ligne ou sur le contenu des cases autres que col_actions. Cf. Navigation au clic sur les lignes de tableaux

  • La classe spaced_table permet d’ajouter de l’espace au-dessus et au-dessous du tableau.

  • La classe full_width permet de forcer la largeur du tableau à 100% de son contenant.

Quand un tableau est vide, ne pas afficher son en-tête, mais un <td class="col_text"> de toute la largeur du tableau contenant du texte dans un <em> précisant qu’il n’y a rien à afficher (par exemple « Aucun fichier disponible »)

En-tête <thead>

L’en-tête du tableau reste visible quand on fait défiler le tableau sur les écrans moyens et grands.

En plus d’un <tr> contenant les titres des colonnes, il peut contenir une ligne de récapitulatif, d’actions ou d’informations sur les colonnes. Comme il reste visible quand on fait défiler le tableau, il est recommandé de ne pas multiplier le nombre de lignes.

En-têtes <th>

  • Utiliser l’attribut scope pour définir si l’en-tête est un en-tête de colonne (scope="col") ou un en-tête de ligne (scope="row")

  • Les titres d’en-tête peuvent être abrégés tout en conservant une bonne accessibilité en ajoutant un title avec le texte complet sur le <th> et en plaçant le contenu abrégé dans un <span class="screen-reader-text">.

<th scope="col" class="col_number" title="Taux de TVA"><span class="screen-reader-text">Taux de </span>TVA</th>

Rangs <tr>

  • La classe top_align permet d’aligner verticalement le contenu de chaque case du rang en haut de case. Cf. top_align_table pour l’utilisation.

  • La classe strong permet de mettre en gras toutes les cellules d’une ligne.

  • La classe row_recap permet de faire une ligne de synthèse, qui va par exemple contenir les totaux ou sous-totaux des lignes précédentes.

  • Dans les tableaux de listes qui contiennent plus de 10-15 lignes, il est conseillé de répéter le rang affichant les totaux généraux en début et en fin de tableau, pour faciliter la lecture des totaux sans avoir à faire un défilement vertical jusqu’en bas du tableau.

  • La classe row_main permet de faire une ligne mise en avant.

  • Pour obtenir un meilleur rendu des lignes alternées, on peut fermer le <tbody> après un row_recap ou un row_main et en ouvrir un autre aussitôt.

Cases <td>

  • La classe top_align permet d’aligner verticalement le contenu de la case en haut de case. Cf. top_align_table pour l’utilisation.

  • La classe archive permet de signaler une information concernant un événement passé ou modifié par d’autres cases du tableau.

Types de données

Des classes permettent de gérer automatiquement la largeur et l’alignement des colonnes en fonction du type de contenu. Elles sont placées à la fois sur les <th> et les <td> de la colonne :

  • col_text pour du contenu textuel, aligné par défaut à gauche. Il est possible d’aligner à droite avec col_text align_right

  • col_text rich_text pour du contenu textuel issu d’un champ de texte mis en forme (TinyMCE).

  • col_icon pour du contenu comprenant une icône suivie par un libellé texte

  • col_status pour du contenu ne comprenant qu’une icône qui reflète un statut Cf. Statuts pour le contenu

  • col_number pour des nombres (alignés à droite)

  • col_number positive pour des nombres positifs (à préfixer par « + « )

  • col_number negative pour des nombres négatifs (à préfixer par « - « )

  • col_date pour une date (jour, mois, année)

  • col_datetime pour une date et heure

  • col_text phone pour un numéro de téléphone

  • col_select pour les colonnes contenant une case à cocher ou un bouton radio permettant de sélectionner une ligne

  • col_percentage_graphic pour un widget permettant de définir un pourcentage à appliquer à la ligne

  • col_actions pour les boutons d’action Cf. Boutons d’action dans les lignes de tableaux

La classe archive peut être ajoutée à tout <th> ou <td> pour signaler une donnée ancienne.

Les classes min4, min6, min8, min10, min12, min14 peuvent être ajoutées à col_text pour donner des largeurs minimales de colonnes de 4, 6, 8, 10, 12 et 14em respectivement.

Une ligne de tableau qui ne contient que des nombres (ou un <th> et des nombres) peut être signalée avec <tr class="col_number"> sans avoir à marquer tous les <td> avec col_number.

Ajout de ligne au tableau

Quand on peut ajouter une ligne au tableau, le bouton correspondant est un bouton majeur (btn-primary) placé :

  • Pour un tableau qui est le seul contenu de l’écran, dans la barre de boutons principale.

  • Pour un tableau qui n’est pas le seul contenu de l’écran, et tout particulièrement s’il y a plusieurs tableaux dans l’écran :

    • soit dans le <thead> du tableau dans une ligne de récapitulatif (row_recap) dans un un <td class="col_actions">. Il s’affiche donc avant les données et reste visible quand on fait défiler le tableau.

    • soit dans une ligne de récapitulatif au début du <tbody> dans un un <td class="col_actions">. Il s’affiche donc avant les données et n’est plus accessible quand on fait défiler l’écran.

    • on peut le répéter dams le <tfoot> du tableau, dans un un <td class="col_actions"> de toute la largeur du tableau. Il s’affiche donc sous le tableau.

Boutons d’action dans les lignes de tableaux

  • Ces boutons sont toujours des boutons simples (pas de class="btn-primary)

  • Quand au maximum 4 actions faciles à différencier graphiquement sont réalisables sur une ligne, les boutons d’action sont insérés directement dans la colonne col_actions sous forme de boutons icônes.

  • Quand il y a plus d’actions où qu’elles ne sont pas différenciables graphiquement, les boutons sont insérés dans un sous-menu qui s’ouvre au clic sur un bouton (icône #dots)

  • On peut choisir d’afficher 1 à 3 boutons pour les actions principales puis un sous-menu comprenant les actions secondaires.

  • Les boutons ont la classe btn icon only sauf dans le cas d’une action destructive où on ajoute la classe negative

Pour éviter que les cases d’actions s’élargissent trop quand l’écran est large, ajouter sur le <td class="col_actions"> une classe correspondant au nombre de boutons présents dans la case :

  • width_one pour 1 bouton ( <td class="col_actions width_one">)

  • width_two pour 2 boutons ( <td class="col_actions width_two">)

  • width_three pour 3 boutons ( <td class="col_actions width_three">)

  • width_four pour 4 boutons ( <td class="col_actions width_four">)

Réordonner des lignes de tableaux

  • Quand on peut réordonner des lignes de tableau, on utilise des boutons avec flèches vers le haut et vers le bas.

  • Ces boutons sont placés dans une colonne séparée en fin de ligne (après les actions). Les cases de cette colonne ont la classe <td class="col_actions row_ordering sort">.

  • Le bouton pour déplacer vers le bas : <button class="btn icon only down">…

  • Le bouton pour déplacer vers le haut : <button class="btn icon only up">…

Indentation des lignes de tableaux

Pour hiérarchiser des lignes de tableau en les indentant, on positionne en début de ligne un ou plusieurs <td class="level_spacer"></td>.

<tr>
        <td colspan="3"><h3>Information de niveau 0</h3></td>
</tr>
<tr>
        <td class="level_spacer"></td>
        <td colspan="2">Information de niveau 1</td>
</tr>
<tr>
        <td class="level_spacer"></td>
        <td class="level_spacer"></td>
        <td colspan="2">Information de niveau 2</td>
</tr>

Filtres de recherche

Dans les formulaires de filtres de recherche, on groupe les divers champs suivant le type de données sur lequel ils portent :

  • Informations temporelles (année, début, fin, durée…)

  • Types, numéros et statuts de document

  • Informations financières (montant, mode de paiement…)

  • Informations client (client, statut client…)

  • Auteur (enseigne, accompagnateur…)

Quand ces filtres portent sur une liste, on uniformise autant que possible l’ordre des filtres et des colonnes de la liste pour que le lien entre les deux soit facile à établir.

Pagination et affichage des listes

Un widget d’information et de pagination permet d’informer l’utilisateur·trice sur le nombre de résultats (résultats) et le nombre total de pages (pages), de choisir combien d’éléments afficher par page (afficheur), et de naviguer de page en page (pagination).

  • Quand une liste ne comprend pas d’éléments, on affiche la partie résultats seule au-dessus de la liste.

  • Quand une liste comprend des éléments, on affiche résultats et afficheur au-dessus et au-dessous de la liste.

  • Si la liste est paginée, on ajoute pages et pagination après résultats.

Onglets

Pour créer des onglets, il faut créer une liste <ul class="nav nav-tabs" role="tablist"> qui contient les titres des onglets, et une <div class="tab-content"> qui comprend le contenu des onglets.

  • L’onglet actif et son contenu sont marqués par une classe active sur le <li> et aria-selected="true" sur le <a>.

  • Les onglets inactifs sont marqués par tabindex="-1" sur le <a>.

  • Le libellé des titres des onglets est placé dans un <span>.

  • L’icône des titres des onglets est placée dans un <span class="icon">.

  • On relie les titres au contenu avec les propriétés croisées aria-controls et aria-labelledby

<ul class="nav nav-tabs" role="tablist">
        <li role="presentation" class="active">
                <a href="#tab1Form" aria-controls="tab1Form" role="tab" id="tab1" aria-selected="true">
                        <span class="icon">${api.icon('file-alt')}</span>
                        <span>Onglet 1</span>
                </a>
        </li>
        <li role="presentation">
                <a href="#tab2Form" aria-controls="tab2Form" role="tab" id="tab2" tabindex="-1">
                        <span class="icon">${api.icon('file-spreadsheet')}</span>
                        <span>Onglet 2</span>
                </a>
        </li>
</ul>
<div class='tab-content'>
        <div role="tabpanel" id="tab1Form" aria-labelledby="tab1" class="tab-pane active">
                Contenu de l’onglet 1
        </div>
        <div role="tabpanel" id="tab2Form" aria-labelledby="tab2" class="tab-pane">
                Contenu de l’onglet 2
        </div>
</div>

On ajoute la classe modal-tabs à la liste (<ul class="nav nav-tabs modal-tabs" role="tablist">) si les onglets sont dans une modale.

La classe icon-tabs (<ul class="nav nav-tabs icon-tabs" role="tablist">) permet d’éviter un défilement horizontal des onglets sur petits écrans. Elle ne fonctionne qu’avec les onglets dont les titres ont des icônes.

  • en vue mobile, seul le libellé de l’onglet actif est visible. Les autres onglets ne comportent que l’icône.

  • en vue tablette, seul le libellé de l’onglet actif est visible. Le libellé des autres onglets est affiché au survol sur les écrans qui le supportent.

On ajoute la classe vertical-tabs à la liste (<ul class="nav nav-tabs vertical-tabs" role="tablist">) si les onglets sont verticaux dans une colonne à gauche du contenu. Dans ce cas il faut mettre en place les colonnes avec par exemple <div class="layout flex two_cols quarter"> Cf. 2 à 4 Colonnes

Blocs repliables

Les blocs repliables sont contenus dans une <div class="collapsible">, chaque bloc est dans une <div>.

Le titre du bloc est un lien <a> ou un <button> dans une balise <h2> (ou <h3>, <h4>) avec la classe collapse_title. Le lien ou le bouton portent la propriété aria-expanded qui définit si le bloc est ouvert ou fermé.

Le contenu du bloc est dans une <div class="collapse_content"> qui suit la balise <h…>. On ajoute la propriété hidden à un bloc de contenu masqué. On peut omettre la classe collapse_content si on ne veut pas indenter le contenu repliable.

<div class="collapsible">
        <div>
                <h2 class="collapse_title">
                        <a href="javascript:void(0);" aria-expanded="true" title="Masquer les …" aria-label="Masquer les …">
                                <svg class="arrow">
                                        <use href="../static/icons/endi.svg#chevron-down"></use>
                                </svg>
                                Titre du bloc
                        </a>
                </h2>
                <div class="collapse_content">
                        <div class="content">
                        </div>
                </div>
        </div>
</div>

Tableaux repliables

Les tableaux repliables sont marqués par la classe collapsible, les titres et contenus sont dans des <tbody>.

Le titre du bloc est un lien <a class="collapse_button"> ou un <button class="collapse_button"> dans une balise <h2> (ou <h3>, <h4>). Le lien ou le bouton portent la propriété aria-expanded qui définit si le bloc est ouvert ou fermé. Ils portent aussi la propriété data-collapse-target qui pointe vers le ou les blocs de contenu qui seront repliés ou dépliés.

Le contenu du bloc est dans un <tbody class="collapse_content"> qui porte la propriété data-collapse-trigger qui a la même valeur que la propriété data-collapse-target du bouton de repli-dépli. On ajoute la propriété hidden à un contenu masqué.

<tbody class="collapse_title">
        <tr>
                <td>
                        <h4>
                                <a href="javascript:void(0);" class="collapse_button" aria-expanded="true" data-collapse-target="block_001" title="Masquer les …" aria-label="Masquer les …">
                                <svg class="arrow"><use href="../static/icons/endi.svg#chevron-down"></use></svg>
                                Titre du bloc</a>
                        </h4>
                </td>
        </tr>
</tbody>
<tbody class="collapse_content" data-collapse-trigger="block_001">
        <tr>
                <td>
                </td>
        </tr>
</tbody>

Si on veut obtenir un bloc repliable imbriqué dans un autre, on ajoute une propriété data-collapse-parent au bloc de contenu pour désigner le titre imbriqué.

Comme il est replié par le titre de niveau 1, le titre de niveau 2 porte aussi la propriété data-collapse-trigger qui désigne le titre de niveau 1.

<tbody class="collapse_title">
        <tr>
                <td>
                        <h4>
                                <a href="javascript:void(0);" class="collapse_button" aria-expanded="false" data-collapse-target="block_001" title="Afficher les …" aria-label="Afficher les …">
                                <svg class="arrow"><use href="../static/icons/endi.svg#chevron-down"></use></svg>
                                Titre du bloc de niveau 1</a>
                        </h4>
                </td>
        </tr>
</tbody>
<tbody class="collapse_content" data-collapse-trigger="block_001" hidden>
        <tr>
                <td>
                </td>
        </tr>
</tbody>
<tbody class="collapse_title" data-collapse-trigger="block_001">
        <tr>
                <td>
                        <h4>
                                <a href="javascript:void(0);" class="collapse_button" aria-expanded="false" data-collapse-target="block_002" title="Afficher les …" aria-label="Afficher les …">
                                <svg class="arrow"><use href="../static/icons/endi.svg#chevron-down"></use></svg>
                                Titre du bloc de niveau 2</a>
                        </h4>
                </td>
        </tr>
</tbody>
<tbody class="collapse_content" data-collapse-trigger="block_001 block_002" data-collapse-parent="block_002" hidden>
        <tr>
                <td>
                </td>
        </tr>
</tbody>

Modales (Pop-ins)

Les modales ou pop-ins sont insérés à l’intérieur d’une balise <section class="modal_view"> qui positionne la modale dans l’écran. C’est elle qu’on affiche ou cache avec par exemple style="display: none;".

Les cinq classes size_small, size_middle, size_large, size_extralarge et size_full permettent d’obtenir des modales de plus en plus grandes. (size_full prend tout l’écran).

La <div role="dialog"> réfère le titre de la modale pour l’accessiblité.

La <div class="modal_layout"> permet la mise en forme du contenu.

Le <header> contient le bouton de fermeture et le titre de la modale (<h2> avec un id référencé par la <div role="dialog">).

Pour afficher des onglets, on peut ajouter la zone de navigation <nav> optionnelle.

Le contenu et le pied de page sont placés dans une <div class="modal_content_layout">. Si le contenu est un formulaire, ils seront placés dans un <form class="modal_content_layout layout">.

Au besoin, l’élément avec la classe modal_content_layout peut être intégré dans une <div class="modal_overflow"> positionnée après le <header>.

On peut placer le contenu des onglets (commandés par la zone de navigation) dans <div|form class="modal_content_layout">.

Le contenu (ou le contenu de chaque onglet) est dans une <div class="modal_content">.

Les boutons d’actions sur l’ensemble de la modale ou sur l’onglet en cours sont situés dans un <footer>.

De cette manière, le pied de page et donc les boutons d’actions sont toujours visibles, et le contenu dans <div class="modal_content"> peut défiler verticalement.

Exemple de modale avec onglets :

<section id="data_with_tabs_add_form" class="modal_view size_middle" style="display: none;">
        <div role="dialog" id="" aria-modal="true" aria-labelledby="data_with_tabs-forms_title">
                <div class="modal_layout">
                        <header>
                                <button class="icon only unstyled close" title="Fermer cette fenêtre" aria-label="Fermer cette fenêtre" onclick="return false;">
                                        <svg><use href="${request.static_url('endi:static/icons/endi.svg')}#times"></use></svg>
                                </button>
                                <h2 id="data_with_tabs-forms_title">Titre de la modale</h2>
                        </header>
                        <nav>
                                <ul class="nav nav-tabs modal-tabs" role="tablist" aria-label="Type de client">
                                        <li role="presentation" class="active">
                                                <a href="#tab1Form" aria-controls="tab1Form" role="tab" aria-selected="true" id="company">Onglet 1</a>
                                        </li>
                                        <li role="presentation">
                                                <a href="#tab2Form" aria-controls="tab2Form" role="tab" aria-selected="false" id="individual" tabindex="-1">Onglet 2</a>
                                        </li>
                                </ul>
                        </nav>
                        <div class="tab-content">
                                <div role="tabpanel" class="tab-pane active row" id="tab1Form" aria-labelledby="company" tabindex="0">
                                        <form class="modal_content_layout layout">
                                                <div class="modal_content">
                                                        <h3>Titre</h3>
                                                        <form>
                                                                Contenu du formulaire
                                                        </form>
                                                </div>
                                                <footer>
                                                        <button class='btn btn-primary' type='submit' name='submit'>Valider</button>
                                                        <button class='btn' data-dismiss='modal'>Annuler</button>
                                                </footer>
                                        </form>
                                <div role="tabpanel" class="tab-pane row" id="tab2Form" aria-labelledby="individual" tabindex="0" hidden>
                                        <div class="modal_content_layout">
                                                <div class="modal_content">
                                                        <h3>Titre</h3>
                                                        Contenu
                                                </div>
                                                <footer>
                                                        <button class='btn btn-primary' type='submit' name='submit'>Valider</button>
                                                        <button class='btn' data-dismiss='modal'>Annuler</button>
                                                </footer>
                                        </div>
                                </div>
                        </div>
                </div>
        </div>
</section>

Exemple de modale sans onglets :

<section id="data_with_tabs_add_form" class="modal_view size_middle" style="display: none;">
        <div role="dialog" id="" aria-modal="true" aria-labelledby="data_with_tabs-forms_title">
                <div class="modal_layout">
                        <header>
                                <button class="icon only unstyled close" title="Fermer cette fenêtre" aria-label="Fermer cette fenêtre" onclick="return false;">
                                        <svg><use href="${request.static_url('endi:static/icons/endi.svg')}#times"></use></svg>
                                </button>
                                <h2 id="data_with_tabs-forms_title">Titre de la modale</h2>
                        </header>
                        <div class="modal_overflow"> <!-- optionnelle -->
                                <form class="modal_content_layout layout"> <!-- ou <div class="modal_content_layout"> -->
                                        <div class="modal_content">
                                                <h3>Titre</h3>
                                                <form>
                                                        Contenu du formulaire
                                                </form>
                                        </div>
                                        <footer>
                                                <button class='btn btn-primary' type='submit' name='submit'>Valider</button>
                                                <button class='btn' data-dismiss='modal'>Annuler</button>
                                        </footer>
                                </form> <!-- ou </div> -->
                        </div>
                </div>
        </div>
</section>

Notifications

Les notifications sont regroupées dans une section dédiée, sous forme de liste. Un nombre maximum de notifications (par exemple 5) est affiché, avec un bouton pour voir le reste des notifications dans une fenêtre modale.

Les types de notification sont différenciées par une classe sur le li et une icône (fragment svg).

Type de notification

Classe du li

Fragment svg

Opération réussie

success

#check

Document validé

valid

#check-circle

Opération échouée

error

#exclamation-triangle

Document invalidé

invalid

#times-circle

Alerte

caution

#exclamation-triangle

Neutre

neutral

#info-circle

La notification neutre peut utiliser divers fragments svg selon le message affiché.

Il est possible de ne pas mettre de classe et de fragment svg (les deux sont mis ou omis ensemble).

Les notifications se composent d’un titre et d’un contenu (optionnel). Ce contenu peut comprendre un ou plusieurs liens (qui s’ouvrent dans une nouvelle fenêtre en respectant Ouverture dans une nouvelle fenêtre) ou des boutons <a class="btn btn-default small"> ou <a class="btn btn-default">.

<div id="notifications" class="notifications" aria-live="polite" role="alert">
        <ul>
                <li class="caution" aria-hidden="true" title="Fermer cette notification">
                        <span class="icon" role="presentation">
                                ${api.icon('exclamation-triangle')}
                        </span>
                        <span class="text">L’enregistrement automatique du devis a échoué. Vous pouvez cliquer sur le bouton <strong>Enregistrer</strong> pour enregistrer le devis manuellement.<br>
                        <a class="btn btn-default small" href="javascript:void(0);">Voir le détail</a>
                        </span>
                        <button class="icon unstyled close" title="Fermer cette notification" aria-label="Fermer cette notification">
                                <svg role="presentation"><use href="../static/icons/endi.svg#times"></use></svg>
                        </button>
                </li>
        </ul>
</div>

Boutons

Les boutons sont soit des <button class="btn"> soit des <a class="btn">.

Les classes disponibles pour les enrichir sont :

  • btn-primary pour les boutons majeurs (un seul par groupe de boutons). Quand on a un groupe de boutons, le bouton majeur est toujours à gauche du ou des bouton·s mineur·s.

  • icon pour les boutons qui comprennent une icône.

  • icon only pour les boutons qui ne comprennent qu’une icône. Dans ce cas il faut préciser le sens du bouton à la fois dans son title et dans son aria-label.

  • disabled pour un bouton inactif

  • negative pour un bouton dont l’action correspond à une suppression, une destruction d’information. Les boutons « Annuler » ne prennent la classe negative que si ils correspondent à une destruction d’informations (pas la fermeture d’une popin ou d’un layer).

  • active pour le bouton sélectionné

  • unstyled pour un bouton non délimité par une bordure. Attention à ce que le bouton soit bien compris comme une action (icône et/ou texte explicite, précision de l’action dans title et aria-label).

  • dropdown-toggle pour un bouton qui déclenche l’ouverture d’un sous-menu

Barre de boutons

Les boutons d’action indépendants ou portant sur tout le contenu de la page sont affichés dans la barre de boutons présente en haut d’écran.

  • Les boutons peuvent être séparés en groupes (dans des <div role="group">)

  • Les actions principales sont affichées en haut à gauche.

  • Les actions secondaires sont affichées en haut à droite. Quand elles comportent une action destructive, celle-ci est en fin de ligne à droite.

Formulaires

Les formulaires complexes sont structurés en blocs (<fieldset>). Ces blocs sont séparés graphiquement avec les classes separate_block (ombre et espacement) et border_left_block (bordure colorée à gauche du bloc).

Quand un formulaire ne contient qu’un bloc, ne pas le séparer graphiquement (ne pas utiliser separate_block et border_left_block).

Quand on veut présenter une donnée non modifiable dans un formulaire, utiliser la structure

<span class="label">Nom de la donnée</span>
<span class="data">Contenu de la donnée</span>

à la place de <label><input>.

Boutons radio, cases à cocher, toggle

Les boutons radio et cases à cocher ont un rendu personnalisé si on respecte les structures suivantes. Il est également possible d’obtenir un toggle à partir d’une case à cocher.

Les toggle sont utilisés pour activer et désactiver des fonctionalités. Par exemple : dés·activer un mode de fonctionnement (étude de prix), dés·activer une fonctionnalité (rester connecté, type de dossier ou d’affaire).

Les cases à cocher sont utilisés pour sélectionner des éléments. Par exemple : sélectionner un ou plusieurs éléments d’une liste (documents sociaux), ou encore pour appliquer des filtres d’affichage d’une liste.

Bouton radio

<div class="radio">
    <label>
        <input type="radio" />
        <span>Libellé du bouton radio</span>
    </label>
</div>

Checkbox

<div class="checkbox">
    <label>
        <input type="checkbox" />
        <span>Libellé de la case à cocher</span>
    </label>
</div>

Toggle

<div class="toggle">
    <label>
        <input type="checkbox" />
        <span>Libellé du toggle</span>
    </label>
</div>

Dans le cas d’une case à cocher ou bouton radio sans libellé visible (pour sélectionner une ligne de tableau par exemple), on doit ajouter title et aria-label sur le <label> et laisser le <span> vide (si on le supprime on perd le rendu personnalisé).

<div class="checkbox">
    <label title="Tout sélectionner" aria-label="Tout sélectionner">
        <input type="checkbox" />
        <span></span>
    </label>
</div>

Icônes

Les icones sont insérées sous la forme d’un fragment SVG. On insère le fichier svg suivi de l’identifiant du fragment à utiliser.

<svg><use href="/static/icons/endi.svg#identifiant"></use></svg> ou <svg><use href="${request.static_url('endi:static/icons/endi.svg')}#identifiant"></use></svg>

On privilégie l’utilisation du helper pour insérer les icônes :

${api.icon('identifiant')}

Une liste des icônes utilisées dans enDI et des identifiants correspondants est disponible ci-dessous :

Lien vers la liste des icônes

Icônes de téléchargement

Pour les boutons permettant de télécharger un fichier :

  • Quand le format du fichier est inconnu ou fourni par l’utilisateur·trice, utiliser l’identifiant #download

  • Quand le format est connu, utiliser l’identifiant correspondant (#file-pdf, #file-excel, #file-csv,…)

Statuts

Liste des styles et fragments d’icônes correspondant aux divers statuts des documents et actions. Ne pas oublier d’ajouter title et aria-label pour préciser le statut au survol de l’icône et pour les lecteurs d’écran.

Statut

Statut en base

Classe du span

Fragment svg

Tous

Brouillon modifié

draft

icon status draft

#pen

Validation demandée

caution

icon status caution

#clock

Validé(e)

valid

icon status valid

#check-circle

Invalidé(e)

invalid

icon status invalid

#times-circle

Non modifiable

closed

icon status closed

#lock

Devis

Annulé, sans suite

closed

icon status closed

#times

Révisé

revised

icon status closed

#redo-alt

Envoyé

valid

icon status valid

#envelope

Signé

valid

icon status valid

#check

Factures générées

valid

icon status valid

#euro-sign

Factures

Payée partiellement

partial_unpaid

icon status partial_unpaid

#euro-sign

Soldée

valid

icon status valid

#euro-sign

Non payée depuis moins de 45 jours

caution

icon status caution

#euro-slash

Non payée depuis plus de 45 jours

invalid

icon status invalid

#euro-slash

Dépenses

En attende de validation

caution

icon status caution

#clock

Payée partiellement

partial_unpaid

icon status partial_unpaid

#euro-sign

Payée intégralement

valid

icon status valid

#euro-sign

Justificatifs reçus

valid

icon status valid

#file-check

Affaires

En cours

valid

icon status valid

#list-alt

Clôturée

closed

icon status closed

#list-check

Jobs

Planifié

planned

icon status planned

#clock

Terminé

completed

icon status completed

#check

Échec

failed

icon status failed

#exclamation-triangle

Écritures

Associée

valid

icon status valid

#link

Non associée

caution

icon status caution

#exclamation-triangle

Commandes

Annulée

closed

icon status closed

#times

Étiquettes

Des étiquettes permettent d’ajouter des informations de classification dans les listes, blocs d’informations, etc… La structure d’une étiquette est du type <span class="icon tag neutral"><svg><use href="/static/icons/endi.svg#identifiant"></use></svg> Libellé</span>.

Des classes sont disponibles pour signifier le type d’information donnée par l’étiquette.

  • <span class="icon tag neutral"> : neutre

  • <span class="icon tag positive"> : positive

  • <span class="icon tag negative"> : négative

  • <span class="icon tag caution"> : avertissement

Si l’étiquette ne doit contenir qu’une icône et pas de texte, on ajoute only aux classes et on précise le sens par un title et un aria-label <span class="icon only tag neutral" title="Libellé" aria-label="Libellé"><svg><use href="/static/icons/endi.svg#identifiant"></use></svg></span>

Bulles

Les bulles permettent d’ajouter des informations de comptagne (nombre de notifications, de mémos, de fichiers, etc…) <span class="bubble">6</span>.

Des classes sont disponibles pour préciser le type d’information donnée par le compte.

  • <span class="bubble"> : neutre

  • <span class="bubble positive"> : positive

  • <span class="bubble negative"> : négative

  • <span class="bubble caution"> : avertissement

  • <span class="bubble inactive"> : inactive (valeur à 0)

Il est possible de préciser sur quoi porte le compte de manière accessible avec une info-bulle et du texte accessible. <span class="bubble caution" title="9 lignes de dépenses">9<span class="screen-reader-text"> lignes de dépenses</span></span>

Mémos

Les notes, commentaires et changements de statuts sont affichés dans un fil de mémos. Ils peuvent afficher une icône, un statut, du texte, des étiquettes. Ils sont horodatés en bas avec le nom de l’auteur·autrice du mémo ou de l’action suivi de la date.

Ils sont regroupés dans un bloc <div class="status_history hidden-print memos"> qui comprend un titre <h4> et une liste <ul> de trois éléments dont chaque <li> contient un mémo. Le mémo le plus récent est en premier.

Si d’autres mémos plus anciens sont présents, ils sont signalés par le texte « …et n mémos plus anciens : » suivi du lien « Voir tous les mémos » qui ouvre une modale comprenant la liste de tous les mémos disponibles, du plus récent au plus ancien.

La structure du mémo est contenue dans un <blockquote>.

<blockquote class="caution">
        <span class="icon status caution" role="presentation">
                <svg><use href="../static/icons/endi.svg#clock"></use></svg>
        </span>
        <div>
                <button class="icon only unstyled close" title="Supprimer ce mémo" aria-label="Supprimer ce mémo">
                        <svg><use href="../static/icons/endi.svg#trash-alt"></use></svg>
                </button>
                <button class="icon only unstyled edit" title="Modifier ce mémo" aria-label="Modifier ce mémo">
                        <svg><use href="../static/icons/endi.svg#pen"></use></svg>
                </button>
                <h5>
                        Validation demandée
                </h5>
                <p>
                        Voilà c’est complet normalement.
                </p>
        </div>
        <footer>FERRAND Grégoire le 18/05/2021</footer>
</blockquote>

Des classes sont disponibles pour signifier le type d’information donnée par le mémo.

  • default : pas de type particulier (quand une icône est présente dans le bloc)

  • draft, closed, neutral, planned : neutre

  • success, valid, completed, partial_unpaid : positive

  • error, invalid, cancelled, failed, unpaid : négative

  • caution, wait, danger : avertissement

  • pinned : mémo épinglé

Les icônes de statuts des mémos sont identiques à celles des Statuts. Elles sont optionnelles. L’icône pour un mémo épinglé est #thumbtack-active.

Les boutons Modifier et Supprimer sont disponibles si l’utlisateur·ice possède les droits correspondants.

Accessibilité

Ouverture dans une nouvelle fenêtre

Quand on ouvre du contenu dans une nouvelle fenêtre <a href= »… » target= »_blank »> ou <button onclick= »window.openPopup(…) »>, il faut prévenir l’utilisateur·trice qu’une nouvelle fenêtre va s’ouvrir en renseignant à la fois title et aria-label.

On utilise onclick= »window.openPopup(…) » si le contenu qui sera affiché dans la nouvelle fenêtre ne contient que des informations ou un formulaire sans possibilité de navigation, qui va mettre à jour la fenêtre appelante. Dans les autres cas, on utilise <a href= »… » target= »_blank »>.

<a href="url" target="_blank" title="Ouvrir le fichier dans une nouvelle fenêtre" aria-label="Ouvrir le fichier dans une nouvelle fenêtre">

Title et aria-label

Sur un <button> sans contenu textuel (class="icon only"), les deux servent : le title comme info-bulle pour les visuels, le aria-label pour les lecteurs d’écran (qui ne lisent souvent pas le title).

Sur un <button> avec contenu textuel, ils ne servent que s’ils précisent le bouton (par exemple Bouton « XLS » avec title et aria-label « Exporter cette liste au format Excel (.xls) » ).

La combinaison title et aria-label n’est possible que sur des éléments interactifs (boutons, menus, zones cliquables…). Si ce n’est pas le cas (pour une icône par exemple), on conserve le title sur l’élément et on insère le texte accessible dans un <span class="screen-reader-text">.

<span class="icon" title="Description de l’icône">
        <svg></svg>
        <span class="screen-reader-text>Description de l’icône</span>
</span>