Skip to content

Commit 4815f3d

Browse files
committed
feat: add @view-transition ; add @layer ; revised breakpoint + add @Custom-Media ; add docs
1 parent 267bce9 commit 4815f3d

35 files changed

Lines changed: 1543 additions & 1478 deletions

app/UA0/styles/development/button.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
}
5959
}
6060

61-
@media (max-width: 45.01em) {
61+
@media (width <= 35em) {
6262
.xs-button-full .button {
6363
width: 100%;
6464
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Synthèse technique : Bug d'invalidation GPU (Blink) par collision entre l'API View Transitions et le Shadow DOM matériel
2+
3+
## 1. Le Symptôme
4+
5+
Lors d'une transition inter-documents (View Transitions), une page spécifique contenant des éléments `<input type="range">` subit un gel complet de sa rasterization. L'élément conteneur (`#main`) devient invisible (transparent) juste après la destruction des pseudo-éléments de transition.
6+
7+
**Comportement critique :** L'interaction utilisateur (un `.focus()` sur n'importe quel champ) force instantanément le recalcul et l'affichage de la page entière. La perte de focus (`.blur()`) renvoie immédiatement la page à son état invisible.
8+
9+
---
10+
11+
## 2. L'Anatomie du Problème (Pipeline de rendu Blink)
12+
13+
Le problème se situe au niveau de la synchronisation entre le **Thread de mise en page (Layout Thread)** et le **Thread de composition (Compositor Thread / GPU)** du moteur Blink (Chromium).
14+
15+
1. **La nature du Widget Native :** L'élément `input[type="range"]` n'est pas un nœud DOM passif. Il encapsule un _User-Agent Shadow DOM_ complexe (pistes, curseurs) et requiert l'allocation dynamique de calques de composition matériels (_Composited Layers_) dédiés pour assurer une interaction fluide à 60/120 Hz sur le GPU.
16+
2. **Le mécanisme de capture de la Transition :** À l'activation d'une View Transition, le moteur applique temporairement un confinement strict (`contain: paint`) et un flag interne de suppression de peinture (**Paint Suppression**) sur le conteneur (`#main`). L'objectif est de figer l'arbre et de sérialiser ses pixels dans une texture globale pour exécuter le fondu enchaîné.
17+
18+
---
19+
20+
## 3. Le Mécanisme de Rupture (Le Deadlock Graphique)
21+
22+
La panne est provoquée par une désynchronisation de frames (_Race Condition_) lors du chargement de la page :
23+
24+
```
25+
[Page Reveal] -> [Activation du Paint Suppression sur #main] -> [Capture du Snapshot]
26+
27+
Le GPU tente d'allouer les calques matériels du Shadow DOM (Range)
28+
29+
30+
[Fin de la Transition] -> [Échec du Damage Tracking (Suivi des modifications)]
31+
32+
Le GPU conserve et affiche une texture parent vide / gelée
33+
34+
```
35+
36+
- **Défaut d'invalidation (Damage Tracking Failure) :** Si l'allocation mémoire ou le calcul géométrique des calques internes du widget `range` se finalise au micro-instant où le parent `#main` est sous confinement de peinture, le gestionnaire de calques de Blink s'enraye.
37+
- Comme le parent a temporairement désactivé son flux de peinture, la mutation interne du widget n'arrive pas à marquer le calque de `#main` comme "sale" (_dirty_).
38+
- **Le cycle gelé :** À la fin de la transition, les pseudo-éléments sont détruits et le navigateur lève le _Paint Suppression_. Cependant, n'ayant enregistré aucun signal de modification (_damage_) sur cette frame, le compositeur matériel réaffiche son dernier cache de texture valide pour `#main` : un état transparent et vide.
39+
- **L'interruption par le Focus :** L'action de focus sur un élément de formulaire court-circuite le flux d'invalidation standard. Elle envoie une directive impérative `SetNeedsRepaint()` directement depuis le thread UI vers le GPU pour dessiner l'anneau d'interaction. Cela force une rasterization complète du sous-arbre, faisant réapparaître la page. Au _blur_, le compositeur bascule à nouveau sur son cache défaillant.
40+
41+
---
42+
43+
## 4. La Résolution : L'Isolation Déterministe
44+
45+
Le correctif consiste à imposer une étanchéité absolue de l'allocation mémoire des widgets avant même que l'API de transition n'intercepte l'arbre de rendu :
46+
47+
```css
48+
[class^='range'] input {
49+
isolation: isolate;
50+
will-change: transform;
51+
contain: layout paint;
52+
}
53+
```
54+
55+
### Rôle mécanique des directives :
56+
57+
- **`contain: layout paint;`** : Garantit que les limites de calcul de disposition et de peinture du widget sont strictement hermétiques. Le navigateur sait qu'aucune modification interne du `range` ne peut impacter la géométrie externe.
58+
- **`isolation: isolate;`** : Force la création d'un contexte d'empilement (_Stacking Context_) indépendant, isolant l'élément sur l'axe Z.
59+
- **`will-change: transform;`** : Indique explicitement au compositeur de pré-allouer la texture matérielle du widget dès le parsing initial, en amont du rendu.
60+
61+
Grâce à ce layout de données rigide, le navigateur résout l'instanciation des calques du Shadow DOM de manière asynchrone sans jamais interférer avec le calcul de la texture globale du parent lors de la transition. Le pipeline reste fluide et déterministe.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
"author": "Olivier Chavarin",
99
"license": "MIT",
1010
"devDependencies": {
11-
"browser-sync": "^3.0.4",
11+
"@csstools/postcss-global-data": "^4.0.0",
1212
"eslint": "^10.2.0",
1313
"image-size": "^2.0.2",
1414
"ora": "^9.3.0",
1515
"postcss": "^8.5.9",
1616
"postcss-advanced-variables": "^5.0.0",
1717
"postcss-calc": "^10.1.1",
1818
"postcss-cli": "^11.0.1",
19+
"postcss-custom-media": "^12.0.1",
1920
"postcss-import": "^16.1.1",
2021
"postcss-minify": "^1.2.0",
2122
"postcss-preset-env": "^11.2.0",
@@ -44,8 +45,7 @@
4445
"spriteutil": "svg-symbol-sprite -p '' -a 'xmlns=\"http://www.w3.org/2000/svg\"' -s '' -c false -i medias/icons/utilDest -o sprites/util.svg",
4546
"spriteplayer": "svg-symbol-sprite -p '' -a 'xmlns=\"http://www.w3.org/2000/svg\"' -s '' -c false -i medias/icons/playerDest -o sprites/player.svg",
4647
"img": "node tasks/images",
47-
"imglist": "node tasks/imageList",
48-
"bs": "browser-sync start --proxy 'scriptura.github.io.localhost' --port 9010 --reload-debounce 2000 --files 'assets' 'views' --no-notify"
48+
"imglist": "node tasks/imageList"
4949
},
5050
"pnpm": {
5151
"ignoredBuiltDependencies": [

page/register.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><title>Register . Scriptura</title><meta name="description" content="Exemple de démonstration pour une page d'inscription."><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><meta name="theme-color" content="#333"><link rel="manifest" href="/app.webmanifest" crossorigin="use-credentials"><link rel="shortcut icon" href="/favicons/favicon.ico"><link rel="icon" type="image/svg+xml" href="/favicons/favicon.svg"><link rel="icon" type="image/png" href="/favicons/favicon.png"><link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png"><link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5"><link rel="stylesheet" href="/styles/main.css" media="screen"><link rel="stylesheet" href="/styles/print.css" media="print"><link rel="preload" href="/fonts/notoSans-Regular.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/fonts/notoSerif-Regular.woff2" as="font" type="font/woff2" crossorigin></head><body class="type-register"><a class="sr-only" href="#main">Aller au contenu</a><nav class="nav" role="navigation"><a class="logo-nav" href="/"><span class="sr-only">Scriptura</span></a><button class="cmd-nav" id="cmd-nav" type="button" aria-label="Main Menu" aria-controls="sub-nav"><svg viewBox="0 0 100 100"><rect x="5" y="20" width="90" height="6"></rect><rect x="5" y="47" width="90" height="6"></rect><rect x="5" y="74" width="90" height="6"></rect></svg></button><ul class="sub-nav" id="sub-nav" aria-labelledby="cmd-nav"><li><a href="/page/components.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#trowel-bricks"></use></svg>Components</a></li><li><a href="/page/templates.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#gopuram"></use></svg>Templates</a></li><li><a href="/page/grids.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#border-none"></use></svg>Grid systems</a></li><li><a href="/page/article.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#ampersand"></use></svg>Sample article</a></li><li><a href="/page/forum.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#bubbles"></use></svg>Sample forum</a></li><li><a href="/page/imageGallery.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#picture"></use></svg>Sample gallery</a></li><li><a href="/page/dashboard.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#cogwheel3"></use></svg>Sample dashboard</a></li><li><a href="//github.com/Scriptura/scriptura.github.io"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#github"></use></svg>Repository</a></li></ul><ol class="breadcrumb" aria-label="Breadcrumb"><li><a href="/">Home</a></li><li><a href="/page/templates.html">Templates</a></li><li><div>Register <span>.&nbsp;Sample register template</span></div></li></ol></nav><main id="main" role="main"><header role="banner"><h1 class="main-heading">Register <span>.&nbsp;Sample register template</span></h1></header><div class="grid2 s-grid1 m-grid1 gap"><div class="grid gap"><div class="boxx"><form class="grid gap" action="/page/dashboard.html" method="post"><div class="input"><label for="input-username">Créez un nom d'utilisateur</label><input id="input-username" type="text" name="username" placeholder="user" autocorrect="off" autocapitalize="off" spellcheck="false" required="required"></div><div class="input"><label for="input-password">Créez votre mot de passe</label><input id="input-password" type="password" name="password" placeholder="• • • • • • • •" required="required"></div><div class="input"><label for="input-password2">Réécrivez votre mot de passe</label><input id="input-password2" type="password" name="password2" placeholder="• • • • • • • •" required="required"></div><p><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#warning"></use></svg>Question anti-spam. Paramétrez les curseurs selon les donnnées suivantes&nbsp;: la valeur la plus petite est vingt-sept, la plus grande fait cinquante de plus.</p><div class="range-multithumb"><label class="sr-only" for="range-start-1">Valeur minimale</label><input id="range-start-1" type="range" name="range-start" min="0" max="100" step="1" value="0"><label class="sr-only" for="range-stop-1">Valeur maximale</label><input id="range-stop-1" type="range" name="range-stop" min="0" max="100" step="1" value="100"><output class="phylactery"></output></div><div class="flex"><button class="button push"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#quill"></use></svg>Je m'inscris</button></div></form></div><div class="boxx"><p>Déjà inscrit&nbsp;?</p><p><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#login"></use></svg><a href="/page/login.html">Se connecter</a></p></div></div><div class="center"><svg class="size decorative-svg" role="img" focusable="false"><use href="/sprites/silos/195v.svg#a"></use></svg></div></div></main><footer class="footer" role="contentinfo"><div class="wrap"><div><div class="logo"><svg><use href="/sprites/silos/195v.svg#a"></use></svg></div><p>Scriptura</p></div><p>Created by <a class="author" href="https://www.linkedin.com/in/olivier-chavarin/">Olivier Chavarin</a></p><p>Since 2015</p></div></footer><div class="alert"><template id="gdpr"><div class="wrap" id="gdpr-see"><div class="mm" role="alert"><svg class="icon" role="img" focusable="false"><use href="/sprites/util.svg#cookie-bite"></use></svg><div><p>Ce site utilise des cookies et vous donne le contrôle sur ceux que vous souhaitez activer.</p></div></div><div class="flex gap"><button class="button" id="gdpr-true-consent" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#checkmark"></use></svg>Tout accepter</button><button class="button" id="gdpr-false-consent" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#mark"></use></svg>Tout refuser</button><button class="button" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#quill"></use></svg>Personnaliser</button></div></div></template><noscript><div class="wrap"><div class="mm" role="alert"><svg class="icon" role="img" focusable="false"><use href="/sprites/util.svg#warning"></use></svg><p>Javascript est désactivé dans votre navigateur. Afin de bénéficier de toutes les fonctionnalités du site, réactivez cette option dans vos paramètres.</p></div></div></noscript></div><script>if (window.location.host !== 'scriptura.github.io.localhost' && window.location.protocol === "http:") window.location.protocol = 'https'</script><script src="/scripts/main.js" async></script></body></html>
1+
<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><title>Register . Scriptura</title><meta name="description" content="Exemple de démonstration pour une page d'inscription."><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><meta name="theme-color" content="#333"><link rel="manifest" href="/app.webmanifest" crossorigin="use-credentials"><link rel="shortcut icon" href="/favicons/favicon.ico"><link rel="icon" type="image/svg+xml" href="/favicons/favicon.svg"><link rel="icon" type="image/png" href="/favicons/favicon.png"><link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png"><link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5"><link rel="stylesheet" href="/styles/main.css" media="screen"><link rel="stylesheet" href="/styles/print.css" media="print"><link rel="preload" href="/fonts/notoSans-Regular.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/fonts/notoSerif-Regular.woff2" as="font" type="font/woff2" crossorigin></head><body class="type-register"><a class="sr-only" href="#main">Aller au contenu</a><nav class="nav" role="navigation"><a class="logo-nav" href="/"><span class="sr-only">Scriptura</span></a><button class="cmd-nav" id="cmd-nav" type="button" aria-label="Main Menu" aria-controls="sub-nav"><svg viewBox="0 0 100 100"><rect x="5" y="20" width="90" height="6"></rect><rect x="5" y="47" width="90" height="6"></rect><rect x="5" y="74" width="90" height="6"></rect></svg></button><ul class="sub-nav" id="sub-nav" aria-labelledby="cmd-nav"><li><a href="/page/components.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#trowel-bricks"></use></svg>Components</a></li><li><a href="/page/templates.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#gopuram"></use></svg>Templates</a></li><li><a href="/page/grids.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#border-none"></use></svg>Grid systems</a></li><li><a href="/page/article.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#ampersand"></use></svg>Sample article</a></li><li><a href="/page/forum.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#bubbles"></use></svg>Sample forum</a></li><li><a href="/page/imageGallery.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#picture"></use></svg>Sample gallery</a></li><li><a href="/page/dashboard.html"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#cogwheel3"></use></svg>Sample dashboard</a></li><li><a href="//github.com/Scriptura/scriptura.github.io"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#github"></use></svg>Repository</a></li></ul><ol class="breadcrumb" aria-label="Breadcrumb"><li><a href="/">Home</a></li><li><a href="/page/templates.html">Templates</a></li><li><div>Register <span>.&nbsp;Sample register template</span></div></li></ol></nav><main id="main" role="main"><header role="banner"><h1 class="main-heading">Register <span>.&nbsp;Sample register template</span></h1></header><div class="grid2 s-grid1 m-grid1 gap"><div class="grid gap"><div class="boxx"><form class="grid gap" action="/page/dashboard.html" method="post"><div class="input"><label for="input-username">Créez un nom d'utilisateur</label><input id="input-username" type="text" name="username" placeholder="user" autocorrect="off" autocapitalize="off" spellcheck="false" required="required"></div><div class="input"><label for="input-password">Créez votre mot de passe</label><input id="input-password" type="password" name="password" placeholder="• • • • • • • •" required="required"></div><div class="input"><label for="input-password2">Réécrivez votre mot de passe</label><input id="input-password2" type="password" name="password2" placeholder="• • • • • • • •" required="required"></div><p><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#warning"></use></svg>Question anti-spam. Paramétrez les curseurs selon les donnnées suivantes&nbsp;: la valeur la plus petite est vingt-sept, la plus grande fait cinquante de plus.</p><div class="flex"><button class="button push"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#quill"></use></svg>Je m'inscris</button></div></form></div><div class="boxx"><p>Déjà inscrit&nbsp;?</p><p><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#login"></use></svg><a href="/page/login.html">Se connecter</a></p></div></div><div class="center"><svg class="size decorative-svg" role="img" focusable="false"><use href="/sprites/silos/195v.svg#a"></use></svg></div></div></main><footer class="footer" role="contentinfo"><div class="wrap"><div><div class="logo"><svg><use href="/sprites/silos/195v.svg#a"></use></svg></div><p>Scriptura</p></div><p>Created by <a class="author" href="https://www.linkedin.com/in/olivier-chavarin/">Olivier Chavarin</a></p><p>Since 2015</p></div></footer><div class="alert"><template id="gdpr"><div class="wrap" id="gdpr-see"><div class="mm" role="alert"><svg class="icon" role="img" focusable="false"><use href="/sprites/util.svg#cookie-bite"></use></svg><div><p>Ce site utilise des cookies et vous donne le contrôle sur ceux que vous souhaitez activer.</p></div></div><div class="flex gap"><button class="button" id="gdpr-true-consent" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#checkmark"></use></svg>Tout accepter</button><button class="button" id="gdpr-false-consent" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#mark"></use></svg>Tout refuser</button><button class="button" style="background-color:tomato"><svg class="icon-inline" role="img" focusable="false"><use href="/sprites/util.svg#quill"></use></svg>Personnaliser</button></div></div></template><noscript><div class="wrap"><div class="mm" role="alert"><svg class="icon" role="img" focusable="false"><use href="/sprites/util.svg#warning"></use></svg><p>Javascript est désactivé dans votre navigateur. Afin de bénéficier de toutes les fonctionnalités du site, réactivez cette option dans vos paramètres.</p></div></div></noscript></div><script>if (window.location.host !== 'scriptura.github.io.localhost' && window.location.protocol === "http:") window.location.protocol = 'https'</script><script src="/scripts/main.js" async></script></body></html>

0 commit comments

Comments
 (0)