1 Commits
Author SHA1 Message Date
tibo 1b27d0e591 develop
Reviewed-on: #2
2025-11-22 07:41:43 +00:00
8 changed files with 0 additions and 918 deletions
-220
View File
@@ -1,220 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<title>template ZONES</title>
<meta name="description" content="PROTO">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8">
<link rel="preload" as="font" type="../font/woff2" href="fonts/Fonte-Texte.woff2" crossorigin />
<link rel="preload" as="font" type="../font/woff2" href="fonts/Fonte-Titre.woff2" crossorigin />
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<section id="header">HEADER</section>
<section id="navbar">NAVBAR</section>
<section id="synthese">SYNTHESE</section>
<section id="principale">PRINCIPALE</section>
<section id="footer">FOOTER</section>
</body>
<template id="zone">
<div id="div_before_zone"></div>
<div id="div_zone">zone</div>
<div id="div_after_zone"></div>
</template>
<script src="log.js"></script>
<script src="scroll.js"></script>
<script src="zones.js"></script>
<script>
logMsgAddActiveSection('intersectionObserver');
logMsgAddActiveSection('htmlElement');
logMsgAddActiveSection('etatSection');
</script>
<script>
function addClassToElement(id,className){
const element=document.querySelector(id);
if (element) element.classList.add(className);
}
function removeClassToElement(id,className){
const element=document.querySelector(id);
if (element) element.classList.remove(className);
}
function initZoneElements(zone) {
const element=document.querySelector('#div_'+zone);
if (element) {
element.innerHTML=zone;
addClassToElement('#div_before_'+zone,'div_before_section');
addClassToElement('#div_'+zone,'div_section');
addClassToElement('#div_after_'+zone,'div_after_section');
}
}
function initZone(zone) {
const sectionZone = document.querySelector('#'+zone);
if (sectionZone) {
const template = document.querySelector('#zone');
if (template) {
const contenu = document.importNode(template.content, true);
if (contenu) {
sectionZone.innerHTML='';
contenu.childNodes.forEach((element) => {if (element.id) element.id=element.id.replace('zone',zone)});
sectionZone.appendChild(contenu);
initZoneElements(zone);
}
}
}
}
initZone('header');
initZone('navbar');
initZone('synthese');
initZone('principale');
initZone('footer');
addClassToElement('#div_header','header');
addClassToElement('#div_navbar','navbar');
addClassToElement('#div_synthese','synthese');
addClassToElement('#div_principale','principale');
addClassToElement('#div_footer','footer');
function etatSectionLog(message) {
logMsg('etatSection', message);
}
const section_header=document.querySelector('#div_header');
const section_navbar=document.querySelector('#div_navbar');
const section_synthese=document.querySelector('#div_synthese');
const after_section_header=document.querySelector('#div_after_header');
const after_section_synthese=document.querySelector('#div_after_synthese');
function toggleElement(element) {
if (element.style.display === "block") {
element.style.display = "none";
} else {
element.style.display = "block";
}
}
// ----
// ---- La page est une machine à états
// ----
let currentEtatSection = 1;
let maxEtat = 4;
function etatSections(etat) {
if (currentEtatSection == etat) return;
currentEtatSection=etat;
etatSectionLog('Etat courant '+currentEtatSection);
switch (currentEtatSection) {
case 1 :
removeClassToElement('#div_navbar','navbar_fixed');
removeClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
section_header.style.display = "block";
scrollToElement('#div_before_header');
break;
case 2 :
addClassToElement('#div_navbar','navbar_fixed');
addClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
scrollToElement('#div_before_navbar');
section_synthese.style.display = "block";
break;
case 3 :
addClassToElement('#div_navbar','navbar_fixed');
addClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
section_synthese.style.display = "none";
scrollToElement('#div_before_navbar');
break;
default :
break;
}
}
function changeEtatSectionUp() {
if (currentEtatSection != maxEtat)
etatSections(currentEtatSection+1);
}
function changeEtatSectionDown(){
if (currentEtatSection != 1)
etatSections(currentEtatSection-1);
}
after_section_header.addEventListener("click", function() {
etatSectionLog('toggle section_header ');
if (currentEtatSection!=1) etatSections(1);
else etatSections(2);
});
after_section_synthese.addEventListener("click", function() {
etatSectionLog('toggle section_synthese ');
if (currentEtatSection!=2) etatSections(2);
else etatSections(2);
});
function changeEtatSection(_visible) {
if (!_visible) changeEtatSectionUp();
if (_visible) changeEtatSectionDown();
return true;
}
function beforeSection(_visible) {
if (!_visible) changeEtatSectionUp();
}
function afterSection(_visible) {
if (_visible) changeEtatSectionDown();
}
function beforeNavbarVisibility(_visible) {
etatSectionLog('TRIGGER '+arguments.callee.name);
beforeSection(_visible);
}
function afterNavbarVisibility(_visible) {
etatSectionLog('TRIGGER '+arguments.callee.name);
afterSection(_visible);
}
function beforeHeaderVisibility(_visible) {
etatSectionLog('TRIGGER '+arguments.callee.name);
beforeSection(_visible);
}
function afterHeaderVisibility(_visible) {
etatSectionLog('TRIGGER '+arguments.callee.name);
afterSection(_visible);
}
addIntersectionObserverEntry("div_before_header", beforeHeaderVisibility);
addIntersectionObserverEntry("div_after_header", afterHeaderVisibility);
addIntersectionObserverEntry("div_before_navbar", beforeNavbarVisibility);
addIntersectionObserverEntry("div_after_navbar", afterNavbarVisibility);
/*
let yprev = window.pageYOffset;
const scrollHandler = () => {
const y = window.pageYOffset;
const ymax = document.documentElement.scrollHeight - window.innerHeight;
if (y > yprev) {
changeEtatSectionUp();
} else {
changeEtatSectionDown();
}
yprev = Math.min(Math.max(y, 0), ymax);
};
window.addEventListener('scroll', scrollThrottleCallback(scrollHandler, 1000));
*/
</script>
</html>
-14
View File
@@ -1,14 +0,0 @@
const logMsgActivesSections = new Set();
function logMsgAddActiveSection(sectionName) {
logMsgActivesSections.add(sectionName);
}
function logMsgRemoveActiveSection(sectionName) {
logMsgActivesSections.delete(sectionName);
}
function logMsg(section, message){
if (logMsgActivesSections.has(section))
console.log(section, ' : ', message)
}
-92
View File
@@ -1,92 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Scroll Snap CSS</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: Arial, sans-serif;
}
/* NAVBAR */
.navbar {
position: sticky;
top: 0;
height: 80px;
background: #111;
color: white;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
/* ZONE SCROLLABLE */
.scroll-container {
height: calc(100vh - 80px);
overflow-y: scroll;
scroll-snap-type: y mandatory;
}
/* SECTIONS */
.section {
height: calc(100vh - 80px);
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
}
.section-1 {
height: 150px;
background: #4caf50;
}
.section-2 {
background: #2196f3;
}
.section-3 {
background: red;
}
.section-3 {
background: yellow;
}
</style>
</head>
<body>
<nav class="navbar">
Navbar sticky
</nav>
<main class="scroll-container">
<section class="section section-1">
Section 1
</section>
<section class="section section-2">
Section 2
</section>
<section class="section section-3">
Section 3
</section>
<section class="section section-4">
Section 4
</section>
</main>
</body>
</html>
-83
View File
@@ -1,83 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Scroll Snap avec Header Scrollable</title>
<style>
html, body {
margin: 0;
font-family: Arial, sans-serif;
height: 100%;
/* Scroll snap global */
scroll-snap-type: y mandatory;
overflow-y: scroll;
}
header {
height: 120px;
background-color: #34495e;
color: white;
display: flex;
align-items: center;
justify-content: center;
scroll-snap-align: start;
}
nav {
height: 80px;
background-color: #2ecc71;
display: flex;
align-items: center;
justify-content: center;
position: sticky;
top: 0;
z-index: 10;
}
section {
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
scroll-snap-align: start;
scroll-margin-top: 80px;
}
.section-1 {
background-color: #ecf0f1;
min-height: 200px;
}
.section-2 {
background-color: #bdc3c7;
height: calc(100vh - 80px);
}
.section-3 {
background-color: #95a5a6;
min-height: 200vh;
}
</style>
</head>
<body>
<header>
<h1>Header (120px)</h1>
</header>
<nav>
<strong>Navbar sticky (80px)</strong>
</nav>
<section class="section-1">Section 1</section>
<section class="section-2">Section 2</section>
<section class="section-3">Section 3</section>
</body>
</html>
-154
View File
@@ -1,154 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Scroll Snap avec Header Scrollable</title>
<style>
html, body {
margin: 0;
font-family: Arial, sans-serif;
height: 100%;
/* Scroll snap global */
scroll-snap-type: y mandatory;
overflow-y: scroll;
}
header {
height: 120px;
background-color: #34495e;
color: white;
display: flex;
align-items: center;
justify-content: center;
scroll-snap-align: start;
}
nav {
height: 80px;
background-color: #2ecc71;
display: flex;
align-items: center;
justify-content: center;
position: sticky;
top: 0;
z-index: 10;
}
section {
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
scroll-snap-align: start;
scroll-margin-top: 80px;
}
.section-1 {
background-color: #ecf0f1;
min-height: 200px;
}
.section-3 {
background-color: #95a5a6;
min-height: 200vh;
}
.section-2 {
background-color: #bdc3c7;
height: calc(100vh - 80px);
padding: 0;
display: flex;
}
/* Conteneur du tableau */
.table-wrapper {
flex: 1;
overflow-y: auto;
}
/* Tableau */
table {
width: 100%;
border-collapse: collapse;
}
/* THEAD sticky */
thead th {
position: sticky;
top: 0;
background: #ffffff;
z-index: 2;
border-bottom: 2px solid #999;
}
/* TFOOT sticky */
tfoot td {
position: sticky;
bottom: 0;
background: #ffffff;
z-index: 2;
border-top: 2px solid #999;
}
/* Style cellules */
th, td {
padding: 12px;
border: 1px solid #aaa;
text-align: left;
}
</style>
</head>
<body>
<header>
<h1>Header (120px)</h1>
</header>
<nav>
<strong>Navbar sticky (80px)</strong>
</nav>
<section class="section-1">Section 1</section>
<section class="section-2">
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Nom</th>
<th>Valeur</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr><td>Ligne 1</td><td>123</td><td>OK</td></tr>
<tr><td>Ligne 2</td><td>456</td><td>OK</td></tr>
<tr><td>Ligne 3</td><td>789</td><td>OK</td></tr>
<tr><td>Ligne 4</td><td>111</td><td>OK</td></tr>
<tr><td>Ligne 5</td><td>222</td><td>OK</td></tr>
<tr><td>Ligne 6</td><td>333</td><td>OK</td></tr>
<tr><td>Ligne 7</td><td>444</td><td>OK</td></tr>
<tr><td>Ligne 8</td><td>555</td><td>OK</td></tr>
<tr><td>Ligne 9</td><td>666</td><td>OK</td></tr>
<tr><td>Ligne 10</td><td>777</td><td>OK</td></tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Total : 10 éléments</td>
</tr>
</tfoot>
</table>
</div>
</section>
<section class="section-3">Section 3</section>
</body>
</html>
-182
View File
@@ -1,182 +0,0 @@
const scrollThrottleCallback = (callback, timeout) => {
let wait = false;
return () => {
if (wait) return;
callback.call();
wait = true;
setTimeout(() => { wait = false; }, timeout);
};
};
function getAbsolutePosition(element) {
const rect = element.getBoundingClientRect();
return {
top: rect.top + window.scrollY, // Add vertical scroll
left: rect.left + window.scrollX, // Add horizontal scroll
bottom: rect.bottom + window.scrollY,
right: rect.right + window.scrollX
};
}
function getPositionRelativeToParent(element) {
const parent = element.parentElement;
const parentRect = parent.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
return {
top: elementRect.top - parentRect.top,
left: elementRect.left - parentRect.left,
bottom: elementRect.bottom - parentRect.top,
right: elementRect.right - parentRect.left
};
}
function smoothScrollToElement(element, offset = 0) {
const elementPosition = getAbsolutePosition(element);
const targetScroll = elementPosition.top - offset;
// Smooth scroll with animation
window.scrollTo({
top: targetScroll,
behavior: 'smooth'
});
}
// Enhanced version with progress callback
function scrollToElementWithProgress(element, offset = 0, onProgress) {
const start = window.scrollY;
const elementPosition = getAbsolutePosition(element);
const target = elementPosition.top - offset;
const distance = target - start;
const duration = 1000; // ms
const startTime = performance.now();
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function for smooth animation
const easeProgress = 1 - Math.pow(1 - progress, 3);
const currentPosition = start + (distance * easeProgress);
window.scrollTo(0, currentPosition);
if (onProgress) {
onProgress(progress);
}
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}
function scrollToElement(elementSelector) {
const element = document.querySelector(elementSelector);
if (element) {
const methode=1;
switch (methode) {
case 1 :
element.scrollIntoView();
break;
case 2 :
smoothScrollToElement(element);
break;
case 3 :
scrollToElementWithProgress(element, 0, (progress) => {
logMsg('htmlElement',`Scroll progress: ${Math.round(progress * 100)}%`);
});
break;
}
}
logMsg('htmlElement','scrollTo '+elementSelector);
}
function getAbsolutePosition(element) {
const rect = element.getBoundingClientRect();
return {
top: rect.top + window.scrollY, // Add vertical scroll
left: rect.left + window.scrollX, // Add horizontal scroll
bottom: rect.bottom + window.scrollY,
right: rect.right + window.scrollX
};
}
function getPositionRelativeToParent(element) {
const parent = element.parentElement;
const parentRect = parent.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
return {
top: elementRect.top - parentRect.top,
left: elementRect.left - parentRect.left,
bottom: elementRect.bottom - parentRect.top,
right: elementRect.right - parentRect.left
};
}
function smoothScrollToElement(element, offset = 0) {
const elementPosition = getAbsolutePosition(element);
const targetScroll = elementPosition.top - offset;
// Smooth scroll with animation
window.scrollTo({
top: targetScroll,
behavior: 'smooth'
});
}
// Enhanced version with progress callback
function scrollToElementWithProgress(element, offset = 0, onProgress) {
const start = window.scrollY;
const elementPosition = getAbsolutePosition(element);
const target = elementPosition.top - offset;
const distance = target - start;
const duration = 1000; // ms
const startTime = performance.now();
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function for smooth animation
const easeProgress = 1 - Math.pow(1 - progress, 3);
const currentPosition = start + (distance * easeProgress);
window.scrollTo(0, currentPosition);
if (onProgress) {
onProgress(progress);
}
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}
function scrollToElement(elementSelector) {
const element = document.querySelector(elementSelector);
if (element) {
const methode=1;
switch (methode) {
case 1 :
element.scrollIntoView();
break;
case 2 :
smoothScrollToElement(element);
break;
case 3 :
scrollToElementWithProgress(element, 0, (progress) => {
logMsg('htmlElement',`Scroll progress: ${Math.round(progress * 100)}%`);
});
break;
}
}
logMsg('htmlElement','scrollTo '+elementSelector);
}
-119
View File
@@ -1,119 +0,0 @@
:root {
--dark-mode: 1;
--r-sombre: 0;
--g-sombre: 0;
--b-sombre: 0;
--r-clair: 245;
--g-clair: 245;
--b-clair: 240;
--rgb-sombre: var(--r-sombre), var(--g-sombre), var(--b-sombre);
--rgb-clair: var(--r-clair), var(--g-clair), var(--b-clair);
--couleur-sombre: rgb(var(--rgb-sombre));
--couleur-clair: rgb(var(--rgb-clair));
--couleur-texte: black;
--couleur-fond: var(--couleur-clair);
--marker-before-height: 5px;
--marker-after-height: 12px;
--section-min-height: 80px;
--section-header-height: 120px;
--section-navbar-height: var(--section-min-height);
--section-synthese-height: 120px;
--section-principale-height: 400px;
--section-footer-height: 100vh;
}
@font-face {
font-family: 'Fonte-Texte';
font-display: fallback;
/* Penser à bien héberger la font sur le même domaine que mon site */
src: url(../fonts/Fonte-Texte.woff2) format('woff2');
/* Réutiliser ici exactement la même liste unicode que ci-dessus */
unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB,
U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF,
U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D,
U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212;
}
@font-face {
font-family: 'Fonte-Titre';
font-display: fallback;
/* Penser à bien héberger la font sur le même domaine que mon site */
src: url(../fonts/Fonte-Titre.woff2) format('woff2');
/* Réutiliser ici exactement la même liste unicode que ci-dessus */
unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB,
U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF,
U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D,
U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212;
}
html {
font-family: Fonte-Texte, monospace;
width: 95%;
padding-left: 0;
padding-right: 0;
margin: 0 auto;
background: var(--couleur-fond);
color: var(--couleur-texte);
}
body {
padding: 0;
margin: 0;
min-height:1000px;
}
.div_before_section {
color: var(--couleur-texte);
background-color: black;
height: var(--marker-before-height);
}
.div_section {
min-height: var(--section-min-height);
}
.div_after_section {
color: var(--couleur-texte);
background-color: red;
height: var(--marker-after-height);
}
.header {
height: var(--section-header-height);
background-color: aqua;
}
.navbar {
position: relative;
height: var(--section-navbar-height);
background-color: yellow;
}
.navbar_fixed {
position: fixed;
top: 0;
width: 70%;
}
.div_before_synthese_when_navbar_fixed {
height: calc(var(--section-navbar-height) - var(--marker-after-height) - var(--marker-before-height));
}
.synthese {
background-color: pink;
height: var(--section-synthese-height);
}
.principale {
height: var(--section-principale-height);
}
.footer {
background-color: greenyellow;
height: var(--section-footer-height);
}
-54
View File
@@ -1,54 +0,0 @@
function intersectionObserverLog(message) {
logMsg('intersectionObserver', message);
}
function intersectionObserverLogVisibility(_id, _visible) {
if (_visible) {
intersectionObserverLog(_id + ' is Visible');
} else {
intersectionObserverLog(_id + ' is NOT Visible');
}
}
const intersectionObserverRegistry = new Object();
function setIntersectionObserverRegistry(parametre, valeur)
{
intersectionObserverRegistry[parametre] = valeur;
}
function getIntersectionObserverRegistry(parametre)
{
return intersectionObserverRegistry[parametre];
}
function entryVisiblity(_id, _visible) {
let entry=getIntersectionObserverRegistry(_id);
if (entry) return entry(_visible);
return intersectionObserverLogVisibility(_id, _visible)
}
// Create a function that will handle any intersection between some elements and the viewport.
const handleIntersectionObserverEntries = function (entries) {
entries.forEach(entry => {
intersectionObserverLog(entry.target.id+' ratio '+entry.intersectionRatio);
if (typeof entryVisiblity === 'function') entryVisiblity(entry.target.id, entry.isIntersecting);
});
}
const intersectionObserver = new IntersectionObserver(handleIntersectionObserverEntries,{
// Dès qu'il y a ne serait-ce qu'un pixel au dessus de la ligne rouge
// => donc threshold = 1
threshold: 0,
// On met la hauteur en pixel entre la fin de l'image et la ligne rouge
// C'est négatif parce qu'on entre à l'intérieur de l'image. Si le nombre
// était positif, alors la ligne rouge se retrouverait sous l'image
rootMargin: '-1px 0px'
//rootMargin: '2px 0px'
});
function addIntersectionObserverEntry(_id, _func)
{
let item = document.querySelector('#'+_id);
if ((item) && (intersectionObserver)) {
setIntersectionObserverRegistry(_id, _func);
intersectionObserver.observe(item);
logMsg('intersectionObserver', 'Add entry for '+ _id);
}
}