Bonjour,
Avec un peu de retard, je découvre ce fil.
J'avais également le problème du formulaire reçu vide alors que les champs à compléter sont bien évidemment "obligés" ...
Finalement j'ai compris (du moins je le pense) que les supposés robots passaient directement par le lien php de validation du formulaire, par exemple :
<form method="post" enctype="multipart/form-data" action="redir-contact.php" name="formmail">

Du coup, et de façon radicale, dans ce php de validation j'ai mis un exit si un des champs obligatoire n'est pas rempli :
if (empty($_POST['mail']))
exit;
Ce qui fait que l'on reste sur une page blanche et plus de risque de valider un formulaire vide..
Le visiteur "normal" lui, ne sera pas arrivé jusque là puisque le champ Mail est obligatoire en complétant le formulaire...
C'est sans doute empirique (suis pas un pro du php), mais ça fonctionne... Smiley lol
Avis ? Inconvénients ? Merci...
Modifié par Charlie-82 (08 Sep 2024 - 09:35)
Bonjour,

Si vertical-align: -3px; ne fonctionnait pas, on aurait été quelques un.e.s à être bien embêté.e.s avant l'avènement de Flexbox (du temps d'IE6 mais il n'y est pour rien pour une fois). Smiley vieux
Pour aligner une puce, c'était la méthode la plus utilisée. Il y avait position: relative; top: -3px; aussi. Et background-position parce que les images de fond étaient ultra-présentes.
Bon par contre avec l'arrivée du responsive puis de nouvelles possibilités CSS (et SVG, etc), adieu à cette technique !

Si tu maîtrises tous tes interlignages et la hauteur de ce que tu alignes, line-height ça se tente.
Sinon tu laisses faire le navigateur avec Flexbox et un simple align-items: center; (et flex-wrap: wrap; probablement)
Modifié par Felipe (07 Sep 2024 - 12:28)
Bonsoir,

Je fais un retour ici car je viens de tenter quelque chose d'approchant - avec toutefois une logique légèrement différente - et j'ai repensé à ce topic de Lionel. Alors moi je n'avais pas d'API (j'ai bien fait une demande mais personne au bout du fil) donc j'ai fait du sraping :

1. un premier utilisateur appelle une page de mon site qui déclenche un sraping permettant de requêter toutes les données nécessaires que je formate dans la foulée.
2. J'enregistre le tout dans un JSON, ainsi, TOUS les utilisateurs suivants bénéficierons des données directement disponibles dans le JSON.
3. Donc, si pas de JSON ou si JSON datant d'avant minuit du jour en cours, alors déclenchement du scraping, sinon recours aux données JSON.

Donc, la première différence est là : pas de tâche CRON, c'est le premier utilisateur de la journée qui lance le script. Ensuite, le JSON évite de devoir structurer une table à destination de données qui n'appartiennent pas à mon site : celles-ci peuvent évoluer au cours du temps, le fichier se doit de pouvoir être modulaire si besoin ; surtout pas une structure rigide comme une table SQL.

J'utilise uniquement Node.js, le script :
import { JSDOM } from 'jsdom'
import fs from 'fs/promises'
import path from 'path'
import { fileURLToPath } from 'url'

const jsonFilePath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../data/eventsData.json')

function formatISODate(dateISO) {
  const date = new Date(dateISO)
  const formattedDate = new Intl.DateTimeFormat('fr-FR', {
    weekday: 'long',
    day: 'numeric',
    month: 'long',
    year: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
  }).format(date)
  return formattedDate.charAt(0).toUpperCase() + formattedDate.slice(1)
}

function formatEventDate(date) {
  return date
    .replace(/ -/, ',')
    .replace(/(09:00)/, '<span style="color:var(--color5)">$1</span>')
    .replace(/ -/, ',')
    .replace(/(10:00)/, '<span style="color:var(--color2)">$1</span>')
}

function formatLocation(location) {
  return location
    .toLowerCase()
    .split(' ')
    .map(word => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
    .join('-')
}

function processEvents(events) {
  return events.map(event => ({
    formattedDate: formatEventDate(formatISODate(event.dateISO)),
    formattedLocation: formatLocation(event.location),
  }))
}

async function scrapeWebsite(url) {
  try {
    const response = await fetch(url)
    if (!response.ok) {
      throw new Error(`Erreur HTTP : ${response.status}`)
    }
    const html = await response.text()
    const dom = new JSDOM(html)
    const document = dom.window.document
    const rows = document.querySelectorAll('article')

    const events = []
    rows.forEach(row => {
      const dateISO = row.querySelector('meta[itemprop="startDate"]').getAttribute('content')
      const location = row.querySelector('h4 [itemprop="addressLocality"]')?.textContent.trim()

      if (dateISO && location) {
        events.push({ dateISO, location })
      }
    })

    return events
  } catch (error) {
    console.error('Erreur lors du scraping de', url, ':', error.message)
    return []
  }
}

async function scrapeMultiplePages() {
  const urls = ['https://messes.info/horaires/CODE1', 'https://messes.info/horaires/CODE2']
  const results = await Promise.all(urls.map(url => scrapeWebsite(url)))
  const aggregatedEvents = results.flat()
  const sortedEvents = aggregatedEvents.sort((a, b) => new Date(a.dateISO) - new Date(b.dateISO))
  return processEvents(sortedEvents)
}

async function readJsonData() {
  try {
    const data = await fs.readFile(jsonFilePath, 'utf8')
    return JSON.parse(data)
  } catch (error) {
    return null
  }
}

async function writeJsonData(data) {
  const jsonData = JSON.stringify(data, null, 2)
  await fs.writeFile(jsonFilePath, jsonData, 'utf8')
}

async function getStoredEvents() {
  const data = await readJsonData()
  if (data) {
    const lastUpdated = new Date(data.lastUpdated)
    const now = new Date()
    const isOutdated = now.setHours(0, 0, 0, 0) > lastUpdated.setHours(0, 0, 0, 0)

    if (!isOutdated) {
      return data.events
    }
  }
  return null
}

async function getPlayground(req, res) {
  let data = {}
  data.url = req.url
  data.name = 'Playground <span>.&nbsp;Page de test</span>'
  data.title = 'Playground, page de test'
  data.description = 'Page de test.'

  let events = await getStoredEvents()

  if (!events) {
    events = await scrapeMultiplePages()
    await writeJsonData({ lastUpdated: new Date(), events })
  }

  data.content = events
  return res.view('playground', { data })
}

export { getPlayground }

Tout ça pour obtenir les horaires des messes dans mon secteur car je suis à cheval sur 3 paroisses et que j'en avais marre de devoir consulter tous les sites... Smiley cligne
Modifié par Olivier C (07 Sep 2024 - 06:39)
ricem a écrit :

J'ai vu que tu as modifié ton générateur, cependant, il ajoute des
\n
.
Mais comme les sauts de ligne des balises &lt;p&gt; son pris en charge par "innerHTML", du coup le
\n
ne sert pas à grand chose ?


ah zut, ils ne sont pas échappés!

maj de l'outil pour qu'il soit fonctionnel https://codepen.io/gc-nomade/pen/vYqvNEr

Soit tu gardes les \\n ou injecte le saut de ligne ( lignes à commenter/décommenter)

ricem a écrit :

J'ai vu que tu as modifié ton générateur ...

oui, je joue avec Smiley decu
Modifié par gcyrillus (06 Sep 2024 - 17:02)
gcyrillus a écrit :
Si tu as des difficultés à créer ton fichier json, tu peut toujours te faire un petit script pour t'aider : exemple https://codepen.io/gc-nomade/pen/vYqvNEr

J'ai vu que tu as modifié ton générateur, cependant, il ajoute des
\n
.
Mais comme les sauts de ligne des balises <p> son pris en charge par "innerHTML", du coup le
\n
ne sert pas à grand chose ?
@niuxe, j'avais penser aussi en flex en premier lieu et me suite raviser à relire sa question avant de suivre ton exemple Smiley cligne

@ObiJuanKenobi peut-tu préciser le problème que tu rencontre avec la ligne du dessous et ce que tu as tenté?

Tu peut aussi tester et compléter ce codepen https://codepen.io/gc-nomade/pen/KKjbXJj (vertical-align + line-height, et grid et flex avec avec align-items ) j'y ai mis une image de 60px de haut, donc plus haute que l'interligne de base.

Cdt
Modifié par gcyrillus (06 Sep 2024 - 16:33)
gcyrillus a écrit :


Heu!? c'est une bourrasque , si si cela est possible, c'est dans la doc Smiley cligne

Si je comprend ta question, c'est la hauteur d'interligne que tu ne veut pas voir agrandie avec une image plus haute que le texte, dans ce cas , ce serait line-height qu'il faudrait fixer.
h1{line-height:1.2}


oups au temps pour moi. J'ai eu un doute et j'avoue que je n'ai pas fait attention. J'étais sur 3 trucs en même temps. Ça m'apprendra de répondre "à la va vite". vertical-align, je l'utilise très rarement.

Je n'avais pas pensé au line-height. En outre, ça me parait casse-gueule. Beaucoup trop de contraintes si le contexte change.

Or, avec un flex par exemple et align-self ou margin auto, on est sur du résultat dans n'importe quel contexte.
Modifié par niuxe (06 Sep 2024 - 13:21)
Merci gcyrillus, j'ai testé line-height en mettant des valeurs hautes et les éléments bougent en se décalant vers le bas.

En utilisant position: absolute; puis top, les éléments ne bougent pas mais cela pose un problème de positionnement en responsive (c"est déclaé sur un écran smartphone). C'est pour ça que je cherche une alternative à vertical-align si elle existe.
niuxe a écrit :
Salut,

je passe en coup de vent.

La règle vertical-align ne peut pas avoir des valeurs en px, em, %, etc. Je t'invite à consulter la doc



Heu!? c'est une bourrasque , si si cela est possible, c'est dans la doc Smiley cligne

Si je comprend ta question, c'est la hauteur d'interligne que tu ne veut pas voir agrandie avec une image plus haute que le texte, dans ce cas , ce serait line-height qu'il faudrait fixer.
h1{line-height:1.2}

Modifié par gcyrillus (06 Sep 2024 - 11:44)
Bonjour à vous tous,

Je voudrais savoir s'il existe une propriété CSS similaire à vertical-align qui ne déplace pas vers le bas les éléments situés en-dessous du titre principal <h1>.

Voici mon code HTML et CSS pour illustrer mes propos et juste en-dessous une capture écran :
<!DOCTYPE html>
<html lang="fr">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test</title>
    <style>
        .icone {
            vertical-align: -5px;
        }
    </style>
</head>

<body>
    <h1>
        Titre principal <img src="pictogramme.png" alt="Pictogramme" class="icone">
    </h1>
    <p>
        Exemple de texte pour voir comment il se comporte avec le titre placé juste au-dessus.
    </p>
</body>

</html>

upload/1725611944-62242-capturedncran2024-09-06103815.png
Merci pour votre aide
Modifié par Felipe (07 Sep 2024 - 12:13)
OMG, je viens de comprendre, quel abrutit je suis Smiley biggol

suffit de remplacer le "innertext" par" innerhtml" Smiley mur

Edit : J'avais lu que pour une question de sécurité, il fallait plutôt utiliser le "innerTex"t que le "innerHTML".
Sauf que le "innerHTML" prend les balise html en charge, mais pas le innerText, voilà pourquoi il affichait les balises au lieu de les prendre en compte Smiley hum
Modifié par ricem (06 Sep 2024 - 09:26)
Bon pour exemple, le code html :
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="fruits.css">
    <script src="fruits.js" defer></script>
    <title>Fruits rouges</title>
</head>
<body>
    <main>
        <section class="liste">
            <p>Votre fruit préféré :</p>
            <ul>
                <li data-value="1">Cerise</li>
                <li data-value="2">Fraise</li>
                <li data-value="3">Framboise</li>
                <li data-value="4">Mûre</li>
            </ul>
        </section>
        <section class="contenu">
            <h2 class="titre">Titre :</h2>
            <p><b><u>Description :</u></b> <span class="description"></span></p>
        </section>
    </main>
</body>
</html>

le code javaScript :
fetch("fruits.json")
  .then(response => response.json())
  .then(data => {
    // Initialiser le titre et la description avec les données du premier fruit
    const titreElement = document.querySelector(".titre");
    const descriptionElement = document.querySelector(".description");

    titreElement.innerText = data[0]["titre"];
    descriptionElement.innerText = data[0]["description"];

    // Sélectionner tous les éléments li
    const selection = document.querySelectorAll('li');

    // Ajouter un événement click à chaque élément li
    selection.forEach((element) => {
      element.addEventListener("click", (event) => {
        event.preventDefault(); // Empêcher le comportement du lien par défaut

        const result = event.target.getAttribute('data-value');
        const fruitData = data[result];
        console.log(result);
        

        titreElement.innerText = fruitData["titre"];
        descriptionElement.innerText = fruitData["description"];
      });
    });
  })
  .catch((erreur) => console.error('Erreur :', erreur));


et le Json :
[
    {
        "titre": "Les fruits rouges",
        "description": "Veuillez sélectionner l'un des fruits dans le panneaux de gauche."
    },
    {
        "titre": "Cerise",
        "description": "<p>La cerise est le fruit comestible du cerisier, et il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge.</p> <p>Ce petit fruit compte environ 50 calories pour 100 grammes.</p> <p>La fleur est généralement blanche.</p>" 
    },

    {
        "titre": "Fraise",
        "description": "<p>La fraise est un petit fruit rouge issu des fraisiers.</p> <p>Espèces de plantes herbacées appartenant au genre Fragaria.</p>"
    },
    {
        "titre": "Framboise",
        "description": "<p>La framboise est un fruit rouge issu du framboisier.</p> <p>Un arbrisseau de la famille des rosacées.</p>"
    },
    {
        "titre": "Mûre",
        "description": "La mûre est un fruit comestible de la ronce commune, buisson épineux très envahissant du genre Rubus, de la famille des Rosacées, comme le framboisier"
    }
]

Et voila, ce que je voudrais, c'est qu'il m’interprète les balises html et qu'il ne me les retranscrit pas. Merci.
fetch n'a rien à voir ici, c'est ce que tu récupère qui importe et comment tu le traite.

A priori tu récupére quelque chose qui ne provoque pas d'erreurs. A priori tu traite mal ces données.

Ils nous faut plus pour voir ce que tu fait et voir les erreurs éventuelles. Tu indique que ton code affiche description : et la suite ... Il est étonnant de voir ces deux point qui dans ton JSON lit la clé et sa valeur , donc il y a un defaut de traitement ou un defaut dans les données JSON . A part avec une boule de cristal , impossible de voir ce qui cloche depuis le peu d'infos que tu donnes Smiley smile

edit, je n'ai pas de boule de cristal comme tu t'en doute Smiley cligne
Modifié par gcyrillus (05 Sep 2024 - 22:25)
ricem a écrit :


Bonjour, j'ai dû marquer résolu un peu trop vite, car là j'ai plusieurs phrases à mettre et quand je teste le code, dans le navigateur il me retranscrit le code complet
Description : &lt;p&gt;La cerise est le fruit comestible du cerisier.&lt;/p&gt;&lt;p&gt;Il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge.&lt;/p&gt;

Doit il être utilisé avec une fonction quelconque ?


A quoi ressemble ton fichier json, et comment le lit tu ?
niuxe a écrit :
Et bin, c'est encore plus simple. Tu mets tout sur une seule ligne et tu ajoutes les éléments html adéquates

{
    "titre": "Cerise",
    "description": "&lt;p&gt;La cerise est le fruit comestible du cerisier.&lt;/p&gt;&lt;p&gt;Il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge.&lt;/p&gt;"
}


Bonjour, j'ai dû marquer résolu un peu trop vite, car là j'ai plusieurs phrases à mettre et quand je teste le code, dans le navigateur il me retranscrit le code complet
Description : <p>La cerise est le fruit comestible du cerisier.</p><p>Il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge.</p>

Doit il être utilisé avec une fonction quelconque ?
tu n'as pas pris en compte
JENCAL a écrit :
Après, on a pas tous le code, mais sache que quand tu fais un "document.getElementById("mailform").submit();" tu recharge entièrement ta page, donc le code sur les lignes d'après ne sont même pas executer. essaye de faire de l'ajax plutôt

ni le conseil
casper2 a écrit :
Utilisez plutôt addEventListener() :
https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener


Il n'y a pas de click fantôme, ton formulaire est tout simplement soumis et charge la page demandé, sans definir une page spécifique avec l'attribut action, c'est la page courante qui est rappelé.

remplace document.getElementById("mailform").submit(); par une fonction de type AJAX qui envoi une requête au serveur(vers le script qui va gérer le contenu du formulaire) et attend la réponse pour afficher le message . Cela ne rechargera pas ta page entièrement .


edit
voir https://www.alsacreations.com/tuto/lire/1870-L-API-Fetch-en-JavaScript-qu-est-ce-que-c-est.html
et voici un exemple https://github.com/bobbyhadz/post-form-data-using-javascript-fetch-api
avec son article (anglophone, désolé pas trouvé de lien francophone couvrant juste l'exemple dune soumission de formulaire) https://bobbyhadz.com/blog/post-form-data-using-javascript-fetch-api
Modifié par gcyrillus (04 Sep 2024 - 17:57)
Bon bon bon... ça m'énerve.... mais restons calme.
Dernière modif :

	<div id="confirmation">
	Merci</br></br>Votre mail a bien été envoyé

#### ici le bouton qui n'attend pas qu'on le clique... !!!

	<p><button id="kenavo" type="button">OK</button></p>
	</div>
	<script>
	function kenavo() {
		document.getElementById("colg").style.display='block';
		document.getElementById("confirmation").style.display='none';
	}
		const el = document.getElementById("kenavo");
		el.addEventListener (
			"click", function () { 
			kenavo();}
			, false
			)
	</script>
</body>
</html>


...et toujours le même problème...
Parce que sa baseline est encore récente, mars 2023, et surtout c'est ce que je possède au boulot - dans un CHU -, les techniciens bloquant les MAJ par "sécurité"...

C'est ce qui m'a permis de voir le bug mentionné plus haut et qui m'a incité à trouver une alternative élégante : au départ je ne savais pas d'où venait le problème, il était donc important de trouver au minimum la solution d'une dégradation gracieuse au cas où.
C'est bon, j'ai trouvé la source du problème et il s'agissait de CSS : la version susnommée de Chrome (v111 et inf.) ne supporte pas cette partie de la règle conditionnelle @media qui n'est supportée qu'à partir de Chrome v120 :
(scripting: enabled)

J'ai déjà modifié le JS pour qu'il n'y ait rien de non nécessaire en attribut inline, ce qui fait que, au pire, les SVG s'affichent sans animation. Tant pis pour les anciens navigateurs ; pas grave car même si la baseline est proche, le temps que je sorte un truc pour la production...
Modifié par Olivier C (04 Sep 2024 - 23:43)
PLGPPUR a écrit :
Bonjour casper2
qu'est-ce qui empêchait vraiment le bon placement du sous-menu ?

Bonjour, Tel que le code avait été écrit, je pense que c'est le positionnement absolute qui n'est pas compatible avec le display none/block.
Je suis parti du postula que vous cachiez les sous menus avec un display none; j'ai adapter le code pour qu'il fonctionne dans ces conditions. Mais, comme l'explique frogweb sur son site, l'usage d'un display: none/block pose de problème d'accessibilité.

Comment faire alors? Utiliser le positionnement absolute en positionnant ce que l'on souhaites cacher hors écran, c'est à dire vers la gauche de la partie visible. Lire :
Positionnement hors écran (anysurfer)
Techniques CSS pour cacher du texte
La solution proposée est fonctionnel mais pas accessible. Je vous recommande d'utiliser la technique de cacher le sous menu hors écran plutôt qu'avec display tel que décrit sur le site de frogweb.
Vérifier également que le sous menu est accessible en utilisant le clavier.
Bonne continuation.
Modifié par casper2 (04 Sep 2024 - 11:56)
Merci de vos remarques.

Pour le au-revoir/au_revoir, il faut que je vous dise que dans mon *vrai* code, ce n'est ni l'un ni l'autre mais "kenavo". Je me disais qu'une traduction en français y gagnerait en lisibilité sémantique...

Je vais essayer de transformer le code en utilisant un event listener quand j'aurai le temps.
Jencal, peux-tu préciser ce que tu entends par :
a écrit :
quand tu fais un "document.getElementById("mailform").submit();" tu recharge entièrement ta page, donc le code sur les lignes d'après ne sont même pas executer

De quelles lignes parles-tu exactement ? parce que la suite du programme se déroule quand même...
Bonjour,
Plusieurs problème en CSS, j'ai l'impression que vous ne savez pas exactement toutes les implications de l'application des propriétés que vous utilisez.
Pour le sélecteur .mynavbar il y a un display: none; je dois commenter cette propriété pour voir le burger menu. Puisque cette classe est utilisée pour le parent du burger menu, donc cellui-ci n'apparais pas au chargement de la page.

Je ne comprends pas pourquoi vous faite flotter votre sous menu ni pourquoi celui ci est positionné???
J'ai commenté les propriétés inutiles :

    nav .mynavbar li:hover ul {
      /* Affiche le ul contenant le sous-menu au survol de la souris */
      /* Il ne faut pas d'espace entre le li qui déclenche l'affichage du sous-menu et ce ul */
      /* Sinon, quand on déplacera la souris du li vers le sous-menu, on perdra le hover */
      /* z-index: 99999; */
      display: block;
      /* position: absolute; */
      /* top: 100%; */
      /* float: left; */
    }


Autre chose : ceci n'est pas à faire :

  * {
      margin: 0;
      padding: 0;
    }

Inutile de péter toutes les marges de tout les éléments surtout pour ceux qui n'en on pas. De toutes façon vous devrez les remettre par après . Reset au cas par cas, ou utilisez une feuille de style par défaut de type normalize .
Lire également : https://www.alsacreations.com/astuce/lire/36-la-technique-du-reset-css.html
https://www.alsacreations.com/article/lire/1867-reset-css-une-histoire-heritage-et-reinitialisation.html

Pour .mynavbar pas de width: 100% sur un éléments positionné. Utiliser left: 0; right: 0; Lire width: 100%, tu es le Mal !

Pour nav .mynavbar .menu-items li, left: 0px; n'est pas pris en compte car ce n'est pas un élément positionner (voir via l'inspecteur des éléments (touche F12)). Et l'unité n'est pas nécessaire pour la valeur zéro.

Pour .mynav-container .hamburger-lines vous avez plusieurs propriété display. La dernière valeur écrase les précédentes.

Je vous recommande ce site pour réaliser vos menus déroulants : https://www.frogweb.fr/
Modifié par casper2 (03 Sep 2024 - 15:57)
Bonjour, je n'ai pas regardé le premier code, mais dans le deuxième la fonction au_revoir() est différent de la fonction au-revoir().
Dans une autre mesure n'utilisez pas des évènements online. Voir ce qu'en dit la doc MDN => https://developer.mozilla.org/fr/docs/Learn/JavaScript/Building_blocks/Events#les_gestionnaires_d%C3%A9v%C3%A9nements_en_ligne_ne_les_utilisez_pas_!

Utilisez plutôt addEventListener() :
https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener
Bonjour à tous,
voici le HTML enfin propre :
<nav class="">
      <div class="mynavbar">
        <div class="container mynav-container">
            <input class="checkbox" type="checkbox">
            <div class="hamburger-lines">
              <span class="line line1"></span>
              <span class="line line2"></span>
              <span class="line line3"></span>
			</div>

          <div class="menu-items">
	<nav>
		<ul class="mynavbar">
			<li><a href="#">Menu1</a>
				<ul>
					<li><a href="#">Drop 1</a></li>
					<li><a href="#">Drop 2</a></li>
					<li><a href="#">Drop 3</a></li>
				</ul>
			</li>
			<li><a href="#musette">Rock'n'Roll</a></li>
			<li><a href="Contact/formpage.html" target="_blank">Contact</a></li>
		</ul>
			  </nav>
			</div></div></div>

Le problème reste le même : les sous-menus (Drop1 et Drop2)apparaissent à la fin du menu, comme le montre la capture jointe auparavant.
Les CSS n'ont pas changé.

Merci pour votre aide,
P.
Salut !

Effectivement mais ça n'a pas l'air de venir de là : comme je n'arrivais pas à me dépatouiller avec les guillemets simples et doubles, j'ai transformé la fin comme ça :

<button onClick="au_revoir();">OK</button>
<script>
	function au-revoir() {
		document.getElementById("confirmation").style.display='none';
		document.getElementById("colg").style.display='block';
		}
</script>


... et le message ne fait toujours que rester une demi-seconde...
Modifié par Titen (03 Sep 2024 - 13:40)
J'ai peut-être trouvé mon problème (je suis au boulot avec l'inspecteur de mon vieux Chrome v111) : sur les paths du SVG j'injecte des attributs en javascript de cette manière (ici pour le contexte) :
  path.setAttribute('stroke-dasharray', pathLength) // ok
  path.setAttribute('stroke-dashoffset', pathLength) // ok
  path.setAttribute('fill', 'transparent') // ?
  path.setAttribute('stroke', 'orange') // ?
  path.setAttribute('stroke-width', '1') // ?

Les deux premiers sont nécessaires pour l'animation CSS qui va s'appuyer sur les valeurs définies ainsi. Par contre je ne sais plus pourquoi j'avais aussi défini les attributs fill et strocke (et même stroke-width)... peut-être lors de mon dev... Quoi qu'il en soit ils ne me semblent plus nécessaires et même pire : ce sont peut-être eux qui me foutent le bronx pour les anciens navigateurs qui semblent ne pas pouvoir passer outre via CSS. Une histoire de poids des sélecteurs qui aurait changé d'une version à l'autre face aux attributs inlines ?

J'attends de rentrer chez moi pour supprimer ces lignes et voir ce que ça donne.

Édit : me revoilà chez moi, modifs faites... il n'y a pas d'effet de bord sur les navigateurs récents, maintenant je dois attendre de retourner au boulot pour tester sur la vieille version 111 de Chrome (ah misère...).
Modifié par Olivier C (03 Sep 2024 - 22:26)
Bonjour Niuxe,
niuxe a écrit :
Bref, est-ce que par hasard, ça ne viendrait pas de là ? [...] Si je ne dis pas de bêtise, ton anim passe de 90% à 100%. (j'ai tendance à écrire en % mes anims). Pour moi, tu déclares à 90%, stroke-dashoffset: 0; et à 100% tu redéclares stroke-dashoffset: 0; . Sachant que la valeur par défaut de stroke-dashoffset est de 0.

stroke-dashoffset passe bien d'un 0% implicite à 100%. Il ne démarre pas de 0px car la valeur est calculée pour chaque path par JavaScript via la fonction setSvgAnimationAttributes() inclue dans le fichier svgAnimation.js. Le 90% de l'animation CSS c'est pour gérer la couleur.

niuxe a écrit :
Aussi, tu parles d'un bug sur chrome, mais quel est le comportement qu'il te sort ?

Le SVG, éventuellement sprite, est bien rendu en inline, les stroke-dashoffset sont bien rendus pour chaque path, mais le SVG est "invisible", comme si la colorisation ne se faisait pas.

niuxe a écrit :
Je viens d'inspecter ta 404. [...] Or, tu utilises un symbole. Il me semble que ça peut poser problème.

Tout à fait, on ne peut pas animer les sprites SVG, c'est pourquoi j'utilise préalablement une fonction JS svgSpriteToInline() qui transforme ces sprites en SVG inline. Lorsque le SVG est prêt la fonction envoie un CustomEvent('svgSpriteInlined') et la fonction initSvgObserver() capte l'événement personnalisé.
Modifié par Olivier C (03 Sep 2024 - 11:25)
Bonsoir Olivier,

Ce qui m'embête, c'est que sur ma machine, je n'ai pas de chrome. Juste un FF, Chromium et opera sur ma Debian. Sur le win10, il y a un FF, edge et opera. (Chrome, c'est pas ma tasse de thé)

Bref, est-ce que par hasard, ça ne viendrait pas de là ?

@keyframes anim-svg {
    90% {
      stroke: var(--colorG38);
    }
    to {
      stroke-dashoffset: 0;
      stroke: var(--colorT2);
    }
  }


Si je ne dis pas de bêtise, ton anim passe de 90% à 100%. (j'ai tendance à écrire en % mes anims). Pour moi, tu déclares à 90%, stroke-dashoffset: 0; et à 100% tu redéclares stroke-dashoffset: 0; . Sachant que la valeur par défaut de stroke-dashoffset est de 0.

Aussi, tu parles d'un bug sur chrome, mais quel est le comportement qu'il te sort ?

Je viens d'inspecter ta 404. (Pas sexy à lire la minification du html).

<figure class="xs-center">
            <svg class="size xs-scale decorative-svg sprite-to-inline svg-animation invisible-if-animation" role="img" focusable="false" style="--size:35em;--xs-scale:90%">
              <use href="/sprites/silos/195v.svg#a"></use>
            </svg>
          </figure>

Or, tu utilises un symbole. Il me semble que ça peut poser problème.

*Je n'ai pas mis les mains dans le cambouis. Cette réponse est juste une réflexion.
Modifié par niuxe (03 Sep 2024 - 02:01)
Bonsoir,

Comme je ne sais pas exactement d'où vient le problème - CSS ou JS - je poste le sujet en "débutant", mais j'ai tout de même l'impression que mon problème est lié au CSS.

Il s'agit de la compatibilité avec Chrome v111 ou inférieur pour une animation SVG.

Tout est partit de cet article posté sur CSS-Tricks où il s'agit de simuler le dessin de SVGs avec les propriétés CSS stroke-dasharray et stroke-dashoffset. Cet article m'a inspiré et j'ai eu envie d'aller jusqu'au bout en créant un script permettant d'animer n'importe quel SVG, même s'il est très complexe.

Vous pourrez vous donner une idée du résultat obtenu en consultant cette page 404 : Page 404 avec une animation sur le SVG.
Ça fonctionne aussi au scroll, lorsque vous arrivez au niveau de chaque SVG animable, comme sur cette page, grâce à un `IntersectionObserver`.

Ça fonctionne aussi sur les Sprites SVG car j'injecte préalablement le contenu du symbole du sprite en SVG en ligne grâce à une fonction `svgSpriteToInline()` de mon cru (pour info voir la fonction ici : Github).

Donc j'étais bien content du résultat obtenu avant de voir que j'ai un bug sur un Chrome v111 que j'ai au boulot : le SVG n'est pas colorisé, il est donc invisible pour l'utilisateur.

Je n'ai pas d'erreur JavaScript, à priori les SVG sont tous bien retournés en inline, si besoin est, par la fonction `svgSpriteToInline()`, j'ai donc l'impression que ça pêche côté CSS mais sans trouver pourquoi. Un problème de compatibilité avec une règle CSS ? Mais alors laquelle ? J'ai fais le tour et il me semble qu'elles sont toutes supportées :
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  .invisible-if-animation {
    visibility: hidden;
  }

  .svg-animation.active {
    & :where(path, circle, ellipse, line, polygon, polyline, rect, text, textPath, tref, tspan) {
      stroke-width: 1;
      fill: transparent;
      stroke: var(--colorG38);
      animation: anim-svg var(--anim-svg, 5s) cubic-bezier(0.5, 0, 1, 0) forwards;
    }
  }

  @keyframes anim-svg {
    90% {
      stroke: var(--colorG38);
    }
    to {
      stroke-dashoffset: 0;
      stroke: var(--colorT2);
    }
  }
}

Le JavaScript qui calcule la longueur des paths - et qui donc permet l'animation correcte via les styles CSS - est un peu conséquent ; je vous le met en lien : svgAnimation.js (Github).

Si l'un d'entre-vous y voit plus clair que moi... Merci à lui.
Modifié par Olivier C (03 Sep 2024 - 01:00)
Bonjour Alsacréateurs, Alsacréatrices,

Voilà j'ai un fichier php/html qui contient :
1 - un formulaire, avec un bouton d'envoi.
2 - Une fois le formulaire sousmis et envoyé, il disparaît, un texte apparait avec un nouveau bouton pour passer à la suite... Sauf que ce dernier texte n'attend pas que le bouton soit cliqué et ne reste qu'une fraction de seconde à l'écran.

Voici le code concerné, avec, dans l'orde, la fin du formulaire, le code de traitement de la soumission du formuaire et de son envoi, et le message de confirmation au bouton facétieux :
<p><button type="button" onclick="myFunction()">envoikas</button><button type="button" id="mailout" onclick="history.back();">abandon</button></p>

	
<p><button type="button" onclick="myFunction()">envoi</button><button type="button" id="mailout" onclick="history.back();">abandon</button></p
</form>
	<script>
	function myFunction() {
	  document.getElementById("mailform").submit();
	  document.getElementById("mailform").reset();
	  document.getElementById("communique").style.display='none';
	  document.getElementById("confirmation").style.display='block';
	  }	
	</script>
	</article> <!--communique-->
	<?php
	if (isset($_POST['pickup_place'])){
		$subject = $_POST['pickup_place'];
		$mail_message = $_POST['nom_envoyeurr'].PHP_EOL.$_POST['mel_envoyeur'].PHP_EOL.PHP_EOL.$_POST['comments'];

		$curl = curl_init();
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
		curl_setopt($curl, CURLOPT_URL, "https://eu-api.smtp2go.com/v3/email/send");
		curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode(array(
				  "api_key" => "api-macléperso",
				  "to" => array(
					0 => "<monadresse@arpenefigourt.bzh>"
				  ),

				  "sender" => "<monadresse@arpenefigourt.bzh>",
				  "subject" => $subject,
				  "text_body" => $mail_message
				)));

		$result = curl_exec($curl);
	}
	?>

	<div id="confirmation">
	Merci</br></br>Votre mail a bien été envoyé

#### ici le bouton qui n'attend pas qu'on le clique... !!!

	<p><button onClick='document.getElementById("confirmation").style.display='none'; document.getElementById("colg").style.display='block';>OK</button></p>
	</div>

Si quelqu'un a une piste... merci !
Modifié par Titen (02 Sep 2024 - 14:14)
50 Dernières réponses