list-02-ruled-index

Sommaire à filets numérotés

Lister les sections d'un document en donnant à chacune son libellé, une ligne d'explication et son numéro à droite, séparées par un filet fin qui appartient à l'entrée qu'il suit.

listslideweb700×420px9 benchmarks

Télécharger le .zip

Le fragment RÉEL, dans son propre document, sur le sol de sa charte — pas une image. Ce que vous voyez est exactement ce que vous collerez.

Employer quand

Sommaire d'un deck ou d'une proposition, 3 à 6 entrées, en colonne de droite face au titre. Aussi valable pour une liste d'étapes ou de livrables numérotés.

Éviter quand

Plus de 6 entrées (les filets deviennent une trame et plus personne ne lit), ou les entrées n'ont pas d'explication — une liste de libellés nus n'a pas besoin de cette structure, un simple empilement suffit.

Notes

Deux pièges. (1) Ne JAMAIS répartir les entrées avec `space-between` pour remplir la hauteur : le filet s'éloigne de l'entrée qu'il ferme et l'écart se lit comme un bug. Si la colonne est trop courte pour la zone, on centre le bloc compact (`align-content: center`) et on assume le vide autour — c'est ce que fait ref-06 slide 02. (2) Le numéro s'aligne en HAUT (`align-items: flex-start`), pas au centre de l'entrée : une explication qui passe à trois lignes ferait dériver un numéro centré et la colonne de droite ne tiendrait plus. En .pptx, le filet est un rectangle de 1 px de haut — une bordure de forme y est rendue plus épaisse et plus sombre.

Mots-clés

sommaireindextoclistefiletnumerohairlinedecketapes

Benchmarks — la géométrie, en assertions vérifiables

Rejouables par node bin/check.mjs list-02-ruled-index : le pattern se prouve, il ne se croit pas.

assertionmesureattendu
numéro et libellé alignés sur la MÊME première ligneMath.abs(box('.vl-idx__row:first-child .vl-idx__no').top - box('.vl-idx__row:first-child .vl-idx__label').top)0 ± 2
numéro et libellé au MÊME corpsnum('.vl-idx__no','fontSize') / num('.vl-idx__label','fontSize')1 ± 0.01
saut libellé / explication entre 1,2 et 1,8 (proche = famille, loin = titre)num('.vl-idx__label','fontSize') / num('.vl-idx__desc','fontSize')1.2 → 1.8
filet fin : 1 px, pas un traitnum('.vl-idx__row','borderBottomWidth')≤ 1.5
toutes les entrées ont le même padding verticalMath.abs(num('.vl-idx__row:nth-child(2)','paddingTop') - num('.vl-idx__row:nth-child(3)','paddingTop')) + Math.abs(num('.vl-idx__row:nth-child(2)','paddingBottom') - num('.vl-idx__row:nth-child(3)','paddingBottom'))0 ± 0.5
la 1re entrée n'a pas de padding haut (le bloc commence à sa ligne)num('.vl-idx__row:first-child','paddingTop')0 ± 0
le filet reste collé à son entrée : gouttière ≤ 45 % du pas(box('.vl-idx__row:nth-child(2)').top - box('.vl-idx__row:nth-child(1)').bottom) / (box('.vl-idx__row:nth-child(2)').top - box('.vl-idx__row:nth-child(1)').top)≤ 0.45
explication bornée à ~44 caractèresbox('.vl-idx__desc').w / num('.vl-idx__desc','fontSize')≤ 25
contraste de l'explication ≥ 4,5contrast('.vl-idx__desc')≥ 4.5

Le code

fragment — patterns/list-02-ruled-index.html Télécharger
<!-- list-02-ruled-index — sommaire à filets : libellé + explication à gauche, numéro à droite,
     un filet 1 px sous chaque entrée. Couleurs via --vl-* uniquement. -->
<div class="vl-idx">
  <div class="vl-idx__row">
    <div>
      <p class="vl-idx__label">Introduction</p>
      <p class="vl-idx__desc">Who we are, where we operate, and the position we hold in our
        segment today.</p>
    </div>
    <span class="vl-idx__no">01</span>
  </div>
  <div class="vl-idx__row">
    <div>
      <p class="vl-idx__label">Problem &amp; solution</p>
      <p class="vl-idx__desc">The cost operators carry today, and the part of it our product
        removes.</p>
    </div>
    <span class="vl-idx__no">02</span>
  </div>
  <div class="vl-idx__row">
    <div>
      <p class="vl-idx__label">Business model</p>
      <p class="vl-idx__desc">How revenue is earned, retained and expanded across the two
        channels.</p>
    </div>
    <span class="vl-idx__no">03</span>
  </div>
</div>

<style>
.vl-idx { display: flex; flex-direction: column; width: 700px; }
/* Le filet appartient à l'entrée qu'il SUIT : il est posé en `border-bottom` sur la ligne,
   jamais réparti par `space-between` sur la hauteur disponible — un filet éloigné de son
   entrée se lit comme un oubli de mise en page. */
.vl-idx__row {
  display: flex; align-items: flex-start; gap: 48px;
  padding: 30px 0; border-bottom: 1px solid var(--vl-hairline);
}
.vl-idx__row:first-child { padding-top: 0; }
.vl-idx__label {
  margin: 0; font-size: 24px; font-weight: 800; letter-spacing: 0.01em;
  text-transform: uppercase; color: var(--vl-black);
}
.vl-idx__desc {
  margin: 10px 0 0; max-width: 44ch;
  font-size: 17px; line-height: 1.55; color: var(--vl-ink-muted);
}
/* Le numéro est aligné sur la PREMIÈRE ligne du libellé, pas centré sur l'entrée : c'est ce
   qui fait tenir la colonne de droite quand une explication passe de deux à trois lignes. */
.vl-idx__no {
  margin-left: auto; font-size: 24px; font-weight: 800; letter-spacing: 0.01em;
  color: var(--vl-black);
}
</style>
tokens de la charte — systems/ref-06-orange-notched.json Télécharger
:root {
  --vl-bg: #F0EFEC;
  --vl-board: #DEDDD9;
  --vl-white: #FFFFFF;
  --vl-black: #141414;
  --vl-orange: #F2551E;
  --vl-steel: #C6D0CF;
  --vl-ink-muted: #6A6A67;
  --vl-ink-muted-invert: #FFF1E9;
  --vl-ink-on-steel: #3E4746;
  --vl-hairline: #00000015;
  --vl-ph-a: #C9C9C9;
  --vl-ph-b: #4C4C4C;
  --vl-ph-dark-a: #6A6A6A;
  --vl-ph-dark-b: #141414;
  --vl-notch: 34px;
  --vl-margin: 60px;
}
les métadonnées — patterns/list-02-ruled-index.json (télécharger)
{
  "name": "Sommaire à filets numérotés",
  "family": "list",
  "ref": "ref-06-orange-notched",
  "intent": "Lister les sections d'un document en donnant à chacune son libellé, une ligne d'explication et son numéro à droite, séparées par un filet fin qui appartient à l'entrée qu'il suit.",
  "when_to_use": "Sommaire d'un deck ou d'une proposition, 3 à 6 entrées, en colonne de droite face au titre. Aussi valable pour une liste d'étapes ou de livrables numérotés.",
  "avoid_when": "Plus de 6 entrées (les filets deviennent une trame et plus personne ne lit), ou les entrées n'ont pas d'explication — une liste de libellés nus n'a pas besoin de cette structure, un simple empilement suffit.",
  "tags": [
    "sommaire",
    "index",
    "toc",
    "liste",
    "filet",
    "numero",
    "hairline",
    "deck",
    "etapes"
  ],
  "vars": [
    {
      "name": "--vl-hairline",
      "role": "filet sous chaque entrée (opacité comprise)",
      "default": "#00000015"
    },
    {
      "name": "--vl-black",
      "role": "libellé et numéro",
      "default": "#141414"
    },
    {
      "name": "--vl-ink-muted",
      "role": "explication",
      "default": "#6F6F6C"
    }
  ],
  "slots": [
    "label",
    "desc",
    "number"
  ],
  "geometry": {
    "root": ".vl-idx",
    "frame": [
      700,
      420
    ],
    "ratios": {
      "label_over_desc": 1.41
    },
    "type_px": {
      "label": 24,
      "desc": 17
    },
    "pad_ratio": {
      "top": 0.043,
      "x": 0,
      "bottom": 0.043
    }
  },
  "benchmarks": [
    {
      "name": "numéro et libellé alignés sur la MÊME première ligne",
      "measure": "Math.abs(box('.vl-idx__row:first-child .vl-idx__no').top - box('.vl-idx__row:first-child .vl-idx__label').top)",
      "expect": 0,
      "tol": 2
    },
    {
      "name": "numéro et libellé au MÊME corps",
      "measure": "num('.vl-idx__no','fontSize') / num('.vl-idx__label','fontSize')",
      "expect": 1,
      "tol": 0.01
    },
    {
      "name": "saut libellé / explication entre 1,2 et 1,8 (proche = famille, loin = titre)",
      "measure": "num('.vl-idx__label','fontSize') / num('.vl-idx__desc','fontSize')",
      "min": 1.2,
      "max": 1.8
    },
    {
      "name": "filet fin : 1 px, pas un trait",
      "measure": "num('.vl-idx__row','borderBottomWidth')",
      "max": 1.5
    },
    {
      "name": "toutes les entrées ont le même padding vertical",
      "measure": "Math.abs(num('.vl-idx__row:nth-child(2)','paddingTop') - num('.vl-idx__row:nth-child(3)','paddingTop')) + Math.abs(num('.vl-idx__row:nth-child(2)','paddingBottom') - num('.vl-idx__row:nth-child(3)','paddingBottom'))",
      "expect": 0,
      "tol": 0.5
    },
    {
      "name": "la 1re entrée n'a pas de padding haut (le bloc commence à sa ligne)",
      "measure": "num('.vl-idx__row:first-child','paddingTop')",
      "expect": 0,
      "tol": 0
    },
    {
      "name": "le filet reste collé à son entrée : gouttière ≤ 45 % du pas",
      "measure": "(box('.vl-idx__row:nth-child(2)').top - box('.vl-idx__row:nth-child(1)').bottom) / (box('.vl-idx__row:nth-child(2)').top - box('.vl-idx__row:nth-child(1)').top)",
      "max": 0.45
    },
    {
      "name": "explication bornée à ~44 caractères",
      "measure": "box('.vl-idx__desc').w / num('.vl-idx__desc','fontSize')",
      "max": 25
    },
    {
      "name": "contraste de l'explication ≥ 4,5",
      "measure": "contrast('.vl-idx__desc')",
      "min": 4.5
    }
  ],
  "pptx": {
    "primitive": "rows_hairline",
    "pattern": "list-02-ruled-index",
    "note": "Pas encore d'émetteur : le champ annonçait un `index_rows` qui n'a jamais été écrit, ce qui promettait à deck-builder une sortie .pptx inexistante. Ce qu'il faudra y traiter : le filet de séparation est une RANGÉE, pas une bordure — en .pptx il se pose en connecteur pleine largeur entre deux lignes, et l'interligne se règle sur lui, pas sur la boîte de texte."
  },
  "notes": "Deux pièges. (1) Ne JAMAIS répartir les entrées avec `space-between` pour remplir la hauteur : le filet s'éloigne de l'entrée qu'il ferme et l'écart se lit comme un bug. Si la colonne est trop courte pour la zone, on centre le bloc compact (`align-content: center`) et on assume le vide autour — c'est ce que fait ref-06 slide 02. (2) Le numéro s'aligne en HAUT (`align-items: flex-start`), pas au centre de l'entrée : une explication qui passe à trois lignes ferait dériver un numéro centré et la colonne de droite ne tiendrait plus. En .pptx, le filet est un rectangle de 1 px de haut — une bordure de forme y est rendue plus épaisse et plus sombre.",
  "id": "list-02-ruled-index"
}

À côté