Tutoriel : même largeur à chaque étape ; règle ajoutée à la recette

Les pages sont des éléments de la colonne flexible #screen ; leurs marges
automatiques annulaient l'étirement, et une page au contenu court se
réduisait à la largeur de ce contenu : l'étape 6 « à vous » (consigne
courte, pas d'explication) avait un plateau de 300 px au lieu de 396 en
412 × 915. Les pages prennent toute la largeur, bornée par max-width.
La recette mesure le plateau et le texte à chaque écran du tutoriel, dans
les trois tailles, et refuse un plateau de largeur différente ou une page
plus large que l'écran (mesures dans tutoriel-largeurs.txt).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-10 19:42:41 +01:00
co-authored by Claude Opus 5.5
parent 4e74bab3ac
commit b2263c7e3d
3 changed files with 97 additions and 1 deletions
+69
View File
@@ -98,3 +98,72 @@ export async function hiddenUnderActionBar(target) {
return hidden;
});
}
/**
* Les largeurs d'un écran du tutoriel, en px CSS : le plateau, la colonne
* de texte, et la largeur de la page (scrollWidth) face à celle de l'écran.
* Une page plus large que l'écran défile de côté ; sur un téléphone, Chrome
* la dézoome pour la montrer en entier, et tout l'écran paraît rétréci.
*/
export async function tutorialWidths(target) {
return target.evaluate(() => {
const width = (selector) => {
const el = document.querySelector(selector);
return el === null ? 0 : el.getBoundingClientRect().width;
};
const page = document.scrollingElement;
// Le plus à droite des descendants du tutoriel, pour nommer le
// coupable d'un débordement.
let widest = { what: "", right: 0 };
for (const el of document.querySelectorAll("#tutorial *")) {
const r = el.getBoundingClientRect();
if (r.width > 0 && r.right > widest.right) {
const name = el.id
? `#${el.id}`
: `${el.tagName.toLowerCase()}${[...el.classList].map((c) => `.${c}`).join("")}`;
widest = { what: name, right: r.right };
}
}
return {
board: width("#tutorial-board"),
text: width("#tutorial .tutorial-body"),
page: Math.max(page.scrollWidth, document.body.scrollWidth),
screen: innerWidth,
widest,
};
});
}
/**
* Règle de la recette : pour une taille d'écran donnée, le plateau du
* tutoriel a la même largeur à toutes les étapes, et aucune page n'est plus
* large que l'écran. views : [{ name, size, board, text, page, screen,
* widest }]. Renvoie la liste des écarts, décrits (vide si tout va bien).
*/
export function tutorialWidthProblems(views) {
const problems = [];
const bySize = new Map();
for (const v of views) {
bySize.set(v.size, [...(bySize.get(v.size) ?? []), v]);
if (v.page > v.screen + 0.5) {
problems.push(
`${v.name} en ${v.size} : page de ${v.page} px pour ${v.screen} px ` +
`(le plus à droite : ${v.widest.what}, ${Math.round(v.widest.right)} px)`,
);
}
}
for (const [size, list] of bySize) {
const widths = list.map((v) => v.board);
const min = Math.min(...widths);
const max = Math.max(...widths);
if (max - min > 0.5) {
const odd = list
.filter((v) => Math.abs(v.board - max) > 0.5)
.map((v) => `${v.name} ${v.board.toFixed(1)}`);
problems.push(
`${size} : plateau de ${min.toFixed(1)} à ${max.toFixed(1)} px (${odd.join(", ")})`,
);
}
}
return problems;
}