Étiquette : scroll

[CSS] Désactiver le scroll dans la page lorsqu’un élément en position absolue (de type Modale, Off-Canvas, …) est ouvert en sur-impression

ATTENTION: cette solution testée fonctionnelle est plus simple à mettre en place que les solutions précédemment citées sur ce blog:

Source: Disable Scrolling on Body

[jQuery] Eviter le scroll de la page lorsqu’on touche un élément en position absolute en sur-impression

Edit 21/01/2021: préférer la solution suivante: [CSS] Désactiver le scroll dans la page lorsqu’un élément en position absolue (de type Modale, Off-Canvas, …) est ouvert en sur-impression

Source: http://jsfiddle.net/R9Ut6/.

ATTENTION: contrairement à la demo, dans mon cas, ça a fonctionné en mettant la propriété overflow-y à hidden sur .scrollDiv.

[Foundation 6] Contourner le bug du composant Modal en full screen qui empêche de scroller jusqu’en bas si on utilise l’attribut optionnel data-v-offset

Présentation du problème

Voir en fin de ce billet le paragraphe « Améliorations ».

Demande pour un site Responsive avec un menu qui, en vue Mobile:

  • S’ouvre en cliquant sur une icône Sandwich placée dans le bandeau
  • S’ouvre immédiatement sous le bandeau (pas de off-canvas) et par-dessus le contenu de la page (comprendre: sans s’intercaler entre le bandeau et le contenu de page, donc sans pousser ce dernier vers le bas).
  • Le menu doit être en accordéon

J’ai eu l’idée d’utiliser le composant Modal de Foundation 6 qui intègre une option full-screen et la possibilité de faire débuter la modale à x pixels du haut de la fenêtre (pour laisser le bandeau apparent). La modale de Foundation étant scrollable, je me suis dit « Bingo! ». Le code de ma modale ressemble à peu près à ceci :

Problème: la modale semble mal calculer les hauteurs lorsqu’on utilise l’attribut optionnel data-v-offset pour faire débuter la modale à x pixels du haut de la fenêtre. On ne peut pas scroller jusqu’en bas lorsque le contenu de celle-ci est plus haut que la hauteur totale de la fenêtre!!!

Mise en place de la solution

(optimisation) On stocke l’ID affecté à l’élément Modal dans une variable, car on va l’appeler à plusieurs reprises ensuite:

On commence par récupérer la hauteur du bandeau (en utilisant la très pratique javascript Utility BOX fournie avec Foundation 6) pour l’affecter à la modale via l’attribut optionnel data-v-offset du plugin Reveal (lui aussi fourni avec Foundation 6).

Seulement ensuite, on initialise le plugin Reveal de Foundation 6 (ou tous les plugins d’un coup dans notre exemple) :

De base, la modale Foundation a une hauteur et une hauteur minimale fixées à 100% ou 100vh pour les navigateurs les plus récents. Ces styles sont affectés à l’élément Modal via CSS.

D’autres styles sont affectés à l’élément Modal, lors de son ouverture, via javascript (voir l’attribut style="") :

Pour éviter le bug nous concernant, il faut surcharger les valeurs de height et de min-height en les recalculant via javaScript en fonction de la valeur de data-v-offset récupérée plus haut. On stocke les styles existants dans une variable elementStandardStyle et on ajoute les nouvelles valeurs de hauteur via une variable elementCustomStyle :

Optimisations d’ordre ergonomiques

Refermer la modale (le menu) au clic n’importe où d’autre sur l’écran

On commence par créer une fonction qui ferme la modale (cf. doc de Foundation).

Puis on exécute du code à l’événement open.zf.reveal (une fois la modale est ouverte) :

  • Pour une sélection d’éléments, la modale ne se refermera pas si on clique dessus.
  • Pour tout le reste du document, on exécute la fonction closeMobileNavModal() qui referme la modale.
  • Le 2ème point n’est exécuté qu’une seule fois grâce au $(this).off(e); (sinon, on ne peut plus ré-ouvrir la modale).

ATTENTION!!! Sur iPhone, il existe un bug connu qui empêche le clic sur l’ensemble du $(document). Il faut impérativement ajouter la propriété cursor: pointer; sur l’élément ciblé par le clic.

Dans l’exemple ci-dessous, je lance une détection de l’appareil servant à l’internaute et j’affiche une classe en conséquence sur l’élément html via le plugin browser-detection.

Améliorations (pas testé)

J’appelle deux fois l’événement open.zf.reveal. On peut optimiser ça en ne l’appelant qu’une seule fois:


On peut conserver le menu ouvert sur la page en cours (à condition d’avoir les classes standard d’un menu Change .in-path, .current) en ajoutant le code suivant:

Juste en dessous de l’initialisation des plug-ins Foundation ($(document).foundation();) :

…puis à l’événement open.zf.reveal (le if ($(primaryNav)) :

[jQuery][Foundation 6] Détecter la direction du scroll et agir sur des éléments Sticky

Plug-in scrollDirection disponible sur GitHub: https://github.com/franklang/detect-scroll-direction.

Les bases de la mise en place

Le composant Sticky de Foundation 6 for Sites permet de fixer des éléments dans la fenêtre. La technique est utilisée par de nombreux sites pour, par exemple, laisser le bandeau affiché lorsque l’utilisateur scrolle vers le bas de la page.

Il manque cependant une fonctionnalité très ergonomique, notamment sur les plus petits devices (smartphones, petites tablettes) qui consiste à masquer le bandeau lorsque l’utilisateur scrolle vers le bas de la page et à l’afficher dès qu’il scrolle vers le haut (afin qu’il n’ait pas besoin de scroller jusqu’au haut de page pour atteindre le menu, par exemple). Et cette seconde technique est présente sur de plus en plus de sites (https://wpformation.com/ – visionner avec un Smartphone, http://www.eurosport.fr/cyclisme/ – visionner avec un Smartphone).

On commence par mettre en place le composant Sticky (jusque là, pas de dev spé : tout est disponible dans Foundation.

Ensuite, on ajoute en spé (via jQuery) un data-attribute nommé data-scroll-direction sur l’élément HTML de la page. La valeur de ce data-attribute sera down ou up selon que l’utilisateur scrolle vers le bas ou vers le haut de la page.

On cible ensuite les éléments à masquer au scroll down.

Illustration:

1. L’utilisateur arrive sur la page; elle se présente comme ceci:

2. L’utilisateur a scrollé vers le bas. Dans notre exemple, une partie seulement du bandeau est masquée. On laisse en Sticky le moteur de recherche car il est très important sur ce site.

3. L’utilisateur a scrollé vers le haut (1px de scroll vers le haut suffit). La partie masquée du bandeau réapparait.

Appliquer une animation et un délais

Utilisation du projet animate.css

Importer le projet https://daneden.github.io/animate.css/ dans votre propre projet (j’utilise npm pour celà). On charge uniquement les animations dont on a besoin:

Agir sur votre élément Sticky en invoquant les animations et en ajoutant un temps d’exécution:

La fonction hideWithDelay

Permet d’appliquer une classe .hide (qui n’est autre qu’un display: none;) issue de Foundation 6 for Sites au bout de x secondes, qui correspond au temps qu’il faut à votre animation CSS pour se terminer. Dans notre exemple, l’animation CSS mettra 300ms à s’exécuter mais on ajoute la classe .hide au bout de 290ms pour éviter un effet de flash à l’écran:

Résolution d’erreurs, bugs…

Des éléments de la page ou l’ascenseur de la fenêtre se mettent à clignoter (flickering, blinking)

Source: sticky header blinking.

Testé et fonctionnel sur un projet en prod: il suffit de mettre une hauteur fixe à l’élément sticky. Si votre site/appli est Responsive, que la hauteur est différente d’un breakpoint à l’autre et que vous avez la chance d’utiliser Foundation For Sites (v6 dans mon exemple) :

Même solution en vanilla JS (mais avec Lodash)

Cas particulier: les éléments sticky disparaissent totalement en haut de l’écran (avec effet d’animation) avant de réapparaître brutalement

ATTENTION: on part bien du composant Sticky de Foundation for Sites v6, animé via la bibliothèque animate.css (et plus précisément l’animation slideOutUp). Ce cas particulier peut éventuellement vous donner des pistes si vous utilisez un autre composant sticky et une autre bibliothèque d’animation, mais il existe aujourd’hui d’autres moyens de produire un effet de smooth scroll qu’il vaut mieux privilégier.

Pour ce qui est de la qualité de cette soultion, ne la cherchez pas… Mais elle a le mérite de fonctionner!

Dans ce cas là, les animations proposées par la bibliothèque Animate.css peuvent ne pas convenir. Dans la déclaration CSS transform: translate3d(0, -100%, 0); la valeur de -100% correspond à la hauteur de l’élément. C’est ce fait qu’on voit l’élément sticky scroller entièrement hors-champ avant de réapparaître brutalement.

Mon idée: appliquer temporairement (le temps de l’animation) un margin-top de la hauteur de l’élément à ce dernier afin qu’il s’arrête aux limites de la fenêtre, puis retirer ce style.

Ressources en ligne:

Nouvelle version:

Ma nouvelle animation:

Une fonction javascript qui s’occupe d’appliquer le margin-top (qui peut posséder une valeur dynamique):

…qu’on applique avec un tout petit délais histoire de laisser le temps au DOM de se mettre à jour:

Ancienne version:

Ma nouvelle animation:

…appliquée à mes éléments avec l’ajout de forwards:

Une fonction javascript qui s’occupe d’appliquer le margin-top (qui peut posséder une valeur dynamique):

…qu’on applique avec un tout petit délais histoire de laisser le temps au DOM de se mettre à jour:

[jQuery] Vérifier qu’un élément est présent dans le DOM lorsqu’on scrolle dans la page

Source: Check if element is visible after scrolling.

[jQuery] Conserver une DIV en haut de page lorsqu’on scrolle vers le bas et réinitialiser sa position lorsqu’on remonte dans la page

Comportement de la fonctionnalité :
Lorsqu’on scrolle vers le bas de page, une fois que notre DIV en question (il peut s’agit d’un menu, d’une barre de recherche, etc..) a atteint le haut de la page, il y reste fixé.
Lorsqu’on re-scrolle vers le haut de page, notre DIV retourne à sa position initiale (en dessous de certains éléments le cas échéant).

scroll_fixe