card-02-notched-brief
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
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
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.
| assertion | mesure | attendu |
|---|---|---|
| numéro et libellé alignés sur la MÊME première ligne | Math.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 corps | num('.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 trait | num('.vl-idx__row','borderBottomWidth') | ≤ 1.5 |
| toutes les entrées ont le même padding vertical | 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')) | 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ères | box('.vl-idx__desc').w / num('.vl-idx__desc','fontSize') | ≤ 25 |
| contraste de l'explication ≥ 4,5 | contrast('.vl-idx__desc') | ≥ 4.5 |
Le code
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 & 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>
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é
card-03-stat-accent
Vignette statistique sur accent
list-01-giant-numbers
Colonnes à numéro géant
list-03-two-column-toc
Sommaire numéroté 2 colonnes
list-04-due-rows
Liste d'échéances à quatre zones
list-05-vitals-strip