8 コミット

作成者 SHA1 メッセージ 日付
  Thibaud ef705874b1 [evo4532] 202601021003 1週間前
  Thibaud 0dbccd74de 202512010737 1ヶ月前
  Thibaud 12df9f1274 202511261413 1ヶ月前
  Thibaud 69b9d98a7e 202511260955 1ヶ月前
  Thibaud 3a562b6d26 202511260822 1ヶ月前
  Thibaud 3870cb21ee 202511260802 1ヶ月前
  Thibaud e5b744ca74 202511260751 1ヶ月前
  Thibaud ddaccfed78 202511232102 1ヶ月前
8個のファイルの変更497行の追加466行の削除
分割表示
  1. +0
    -204
      frontend/protos/back/index.html
  2. +0
    -112
      frontend/protos/back/zones.css
  3. +0
    -56
      frontend/protos/back/zones.js
  4. +197
    -6
      frontend/protos/index.html
  5. +14
    -0
      frontend/protos/log.js
  6. +182
    -0
      frontend/protos/scroll.js
  7. +79
    -36
      frontend/protos/styles.css
  8. +25
    -52
      frontend/protos/zones.js

+ 0
- 204
frontend/protos/back/index.html ファイルの表示

@ -1,204 +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="zones.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="zones.js"></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');
const section_navbar=document.querySelector('#div_navbar');
const section_synthese=document.querySelector('#div_synthese');
const after_section_synthese=document.querySelector('#div_after_synthese');
function scrollToElement(elementSelector) {
const element = document.querySelector(elementSelector);
if (element) {
element.scrollIntoView();
logMsg('HtmlElement','scrollTo '+elementSelector);
}
}
function etatSections(etat) {
switch (etat) {
case 1 :
scrollToElement('#div_before_header');
section_synthese.style.display = "block";
removeClassToElement('#div_navbar','navbar_fixed');
removeClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
break;
case 2 :
scrollToElement('#div_before_navbar');
section_synthese.style.display = "block";
addClassToElement('#div_navbar','navbar_fixed');
addClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
break;
case 3 :
scrollToElement('#div_before_navbar');
section_synthese.style.display = "none";
addClassToElement('#div_navbar','navbar_fixed');
addClassToElement('#div_before_synthese','div_before_synthese_when_navbar_fixed');
break;
}
}
after_section_synthese.addEventListener("click", function() {
if (section_synthese.style.display === "block") {
etatSections(3);
} else {
etatSections(2);
}
});
function beforeHeaderVisibility(_visible) {
intersectionObserverLog('TRIGGER '+arguments.callee.name);
if (!_visible) {
etatSections(2);
}
}
function afterHeaderVisibility(_visible) {
intersectionObserverLog('TRIGGER '+arguments.callee.name);
if (_visible) {
etatSections(1);
}
}
addIntersectionObserverEntry("div_before_header", beforeHeaderVisibility);
addIntersectionObserverEntry("div_after_header", afterHeaderVisibility);
function beforeNavbarVisibility(_visible) {
intersectionObserverLog('TRIGGER '+arguments.callee.name);
if (!_visible) {
etatSections(3);
}
}
function afterNavbarVisibility(_visible) {
intersectionObserverLog('TRIGGER '+arguments.callee.name);
if (_visible) {
etatSections(3);
}
}
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) {
if (section_header.style.display !== "none") {
section_header.style.display="none";
} else {
if (section_synthese.style.display !== "none") {
section_synthese.style.display="none";
}
}
} else {
if (y < yprev) {
if (section_synthese.style.display !== "block") {
section_synthese.style.display="block";
} else {
if (section_header.style.display !== "block") {
section_header.style.display="block";
}
}
}
}
yprev = Math.min(Math.max(y, 0), ymax);
};
const throttleCallback = (callback, timeout) => {
let wait = false;
return () => {
if (wait) return;
callback.call();
wait = true;
setTimeout(() => { wait = false; }, timeout);
};
};
// window.addEventListener('scroll', throttleCallback(scrollHandler, 250));
</script>
</html>

+ 0
- 112
frontend/protos/back/zones.css ファイルの表示

@ -1,112 +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-min-height: 120px;
--section-synthese-min-height: 120px;
--section-principale-min-height: 800px;
}
@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 {
min-height: var(--section-header-min-height);
background-color: aqua;
}
.navbar {
background-color: yellow;
}
.navbar_fixed {
position: fixed;
top: 0;
width: 70%;
}
.div_before_synthese_when_navbar_fixed {
height: var(--section-min-height);
}
.synthese {
background-color: pink;
min-height: var(--section-synthese-min-height);
}
.principale {
min-height: var(--section-principale-min-height);
}
.footer {
background-color: greenyellow;
}

+ 0
- 56
frontend/protos/back/zones.js ファイルの表示

@ -1,56 +0,0 @@
function logMsg(section, message){
console.log(section, ' : ', message)
}
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'
});
function addIntersectionObserverEntry(_id, _func)
{
let item = document.querySelector('#'+_id);
if ((item) && (intersectionObserver)) {
setIntersectionObserverRegistry(_id, _func);
intersectionObserver.observe(item);
logMsg('intersectionObserver', 'Add entry for '+ _id);
}
}

+ 197
- 6
frontend/protos/index.html ファイルの表示

@ -8,22 +8,213 @@
<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>
<header></header>
<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;
}
<nav></nav>
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);
<section id="synthese"></section>
/*
let yprev = window.pageYOffset;
const scrollHandler = () => {
const y = window.pageYOffset;
const ymax = document.documentElement.scrollHeight - window.innerHeight;
<section id="principale"></section>
if (y > yprev) {
changeEtatSectionUp();
} else {
changeEtatSectionDown();
}
yprev = Math.min(Math.max(y, 0), ymax);
};
<footer></footer>
window.addEventListener('scroll', scrollThrottleCallback(scrollHandler, 1000));
*/
</body>
</script>
</html>

+ 14
- 0
frontend/protos/log.js ファイルの表示

@ -0,0 +1,14 @@
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)
}

+ 182
- 0
frontend/protos/scroll.js ファイルの表示

@ -0,0 +1,182 @@
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);
}

+ 79
- 36
frontend/protos/styles.css ファイルの表示

@ -19,58 +19,101 @@
--couleur-texte: black;
--couleur-fond: var(--couleur-clair);
--header-height: 400px;
--nav-height: 80px;
--synthese-min-height: 150px;
--principale-min-height: 1000px;
--footer-min-height: 80px;
--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: monospace;
max-width: 95%;
padding-left: 0;
padding-right: 0;
margin: 0 auto;
background: var(--couleur-fond);
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;
padding: 0;
margin: 0;
min-height:1000px;
}
header {
.div_before_section {
color: var(--couleur-texte);
background-color: aqua;
height: var(--header-height);
background-color: black;
height: var(--marker-before-height);
}
nav {
position: sticky;
top: 0px;
.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;
height: var(--nav-height);
}
#synthese {
color: var(--couleur-texte);
background-color: rgb(252, 130, 201);
min-height: var(--synthese-min-height);
.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));
}
#principale {
color: var(--couleur-texte);
background-color: rgb(63, 15, 177);
min-height: var(--principale-min-height);
.synthese {
background-color: pink;
height: var(--section-synthese-height);
}
footer {
position: sticky;
bottom: 0px;
color: var(--couleur-texte);
background-color: rgb(9, 138, 15);
min-height: var(--footer-min-height);
.principale {
height: var(--section-principale-height);
}
.footer {
background-color: greenyellow;
height: var(--section-footer-height);
}

+ 25
- 52
frontend/protos/zones.js ファイルの表示

@ -1,3 +1,15 @@
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)
{
@ -10,16 +22,26 @@ function getIntersectionObserverRegistry(parametre)
function entryVisiblity(_id, _visible) {
let entry=getIntersectionObserverRegistry(_id);
if (entry) return entry(_visible);
return consoleLog (_id, _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);
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)
{
@ -27,55 +49,6 @@ function addIntersectionObserverEntry(_id, _func)
if ((item) && (intersectionObserver)) {
setIntersectionObserverRegistry(_id, _func);
intersectionObserver.observe(item);
logMsg('intersectionObserver', 'Add entry for '+ _id);
}
}
function consoleLog(_id, _visible) {
if (_visible) {
console.log(_id + ' is Visible');
} else {
console.log(_id + ' is NOT Visible');
}
}
function scrollToElement(elementSelector) {
let element = document.querySelector(elementSelector);
if (element) element.scrollIntoView({ behavior: 'smooth' });
}
function beforeHeaderVisibility(_visible) {
console.log('TRIGGER beforeHeaderVisibility');
if (_visible) {
console.log('HEADER is Visible');
} else {
console.log('HEADER is NOT Visible');
scrollToElement('#before_nav');
}
}
function afterHeaderVisibility(_visible) {
console.log('TRIGGER afterHeaderVisibility');
if (_visible) {
scrollToElement('#before_header');
} else {
console.log('HEADER is NOT Visible');
}
}
function beforeNavVisibility(_visible) {
console.log('TRIGGER beforeNavVisibility');
let synthese=document.querySelector('#synthese');
if (synthese) {
if (_visible) {
synthese.style.display="block";
} else {
synthese.style.display="none";
}
}
}
/*
addIntersectionObserverEntry("before_header", beforeHeaderVisibility);
addIntersectionObserverEntry("after_header", afterHeaderVisibility);
addIntersectionObserverEntry("before_nav", beforeNavVisibility);
*/

読み込み中…
キャンセル
保存