Comment puis-je empêcher une page Web de défiler vers le haut lorsque l'utilisateur clique sur un lien qui déclenche JavaScript?

135

Lorsque j'ai un lien qui est câblé avec un événement jQuery ou JavaScript tel que:

<a href="#">My Link</a>

Comment empêcher la page de défiler vers le haut? Lorsque je supprime l'attribut href de l'ancre, la page ne défile pas vers le haut mais le lien ne semble pas cliquable.

Achille
la source

Réponses:

197

Vous devez empêcher l'action par défaut pour l'événement de clic (c'est-à-dire la navigation vers la cible du lien) de se produire.

Il y a deux façons de faire ça.

Option 1: event.preventDefault()

Appelez la .preventDefault()méthode de l'objet événement passé à votre gestionnaire. Si vous utilisez jQuery pour lier vos gestionnaires, cet événement sera une instance de jQuery.Eventet ce sera la version jQuery de .preventDefault(). Si vous utilisez addEventListenerpour lier vos gestionnaires, ce sera une Eventversion DOM brute de .preventDefault(). Dans les deux cas, vous ferez ce dont vous avez besoin.

Exemples:

$('#ma_link').click(function($e) {
    $e.preventDefault();
    doSomething();
});

document.getElementById('#ma_link').addEventListener('click', function (e) {
    e.preventDefault();
    doSomething();
})

Option 2: return false;

Dans jQuery :

Renvoyer false à partir d'un gestionnaire d'événements appellera automatiquement event.stopPropagation () et event.preventDefault ()

Ainsi, avec jQuery, vous pouvez également utiliser cette approche pour empêcher le comportement de lien par défaut:

$('#ma_link').click(function(e) {
     doSomething();
     return false;
});

Si vous utilisez des événements DOM bruts, cela fonctionnera également sur les navigateurs modernes, car la spécification HTML 5 dicte ce comportement. Cependant, les anciennes versions de la spécification ne le faisaient pas, donc si vous avez besoin d'une compatibilité maximale avec les navigateurs plus anciens, vous devez appeler .preventDefault()explicitement. Voir event.preventDefault () vs return false (pas de jQuery) pour le détail de la spécification.

Paolo Bergantino
la source
9
Publié une solution (3 ans de retard) qui ne nécessite pas de connecter un gestionnaire de clics: stackoverflow.com/a/11246131/216941
Matt Crinklaw-Vogt
Dans ce cas, Achille fait juste cela parce qu'il veut que le lien apparaisse comme cliquable, pour lequel il n'a pas du tout besoin d'utiliser href = "#". Voir ma réponse pour plus d'informations.
achecopar le
164

Vous pouvez définir votre href sur au #!lieu de#

Par exemple,

<a href="#!">Link</a>

ne fera aucun défilement lorsque vous cliquez dessus.

Il faut se méfier! Cela ajoutera toujours une entrée à l'historique du navigateur lorsque vous cliquez dessus, ce qui signifie qu'après avoir cliqué sur votre lien, le bouton de retour de l'utilisateur ne les amènera pas à la page sur laquelle ils se trouvaient auparavant. Pour cette raison, il est probablement préférable d'utiliser l' .preventDefault()approche, ou d'utiliser les deux en combinaison.

Voici un violon illustrant cela (il suffit de baisser votre navigateur jusqu'à ce que vous obteniez une barre de défilement):
http://jsfiddle.net/9dEG7/


Pour les nerds des spécifications - pourquoi cela fonctionne:

Ce comportement est spécifié dans la spécification HTML5 sous la section Naviguer vers un identificateur de fragment . La raison pour laquelle un lien avec un href de "#"fait défiler le document vers le haut est que ce comportement est explicitement spécifié comme la manière de gérer un identifiant de fragment vide:

2. Si fragidest la chaîne vide, alors la partie indiquée du document est le haut du document

Utiliser un href de à la "#!"place fonctionne simplement parce qu'il évite cette règle. Le point d'exclamation n'a rien de magique - il constitue simplement un identifiant de fragment pratique car il est sensiblement différent d'un fragid typique et ne correspondra probablement jamais au idou named'un élément de votre page. En effet, on pourrait mettre presque n'importe quoi après le hachage; les seuls fragments qui ne suffiront pas sont la chaîne vide, le mot «top» ou les chaînes qui correspondent nameou les idattributs des éléments de la page.

Plus exactement, nous avons juste besoin d'un identifiant de fragment qui nous fera passer à l'étape 8 de l'algorithme suivant pour déterminer la partie indiquée du document à partir du fragid:

  1. Appliquez l'algorithme d'analyseur d'URL à l'URL et laissez fragid le composant de fragment de l'URL analysée résultante.

  2. Si fragidest la chaîne vide, alors la partie indiquée du document est le haut du document; arrêtez l'algorithme ici.

  3. Soit fragid bytesle résultat du décodage en pourcentage fragid.

  4. Soit decoded fragidle résultat de l'application de l'algorithme du décodeur UTF-8 à fragid bytes. Si le décodeur UTF-8 émet une erreur de décodeur, abandonnez le décodeur et passez à l'étape étiquetée no decoded fragid.

  5. S'il y a un élément dans le DOM qui a un ID exactement égal à decoded fragid, alors le premier de ces éléments dans l'ordre de l'arborescence est la partie indiquée du document; arrêtez l'algorithme ici.

  6. Pas de fragid décodé : s'il y a un élément a dans le DOM qui a un attribut de nom dont la valeur est exactement égale à fragid( nondecoded fragid ), alors le premier élément de ce type dans l'ordre arborescent est la partie indiquée du document; arrêtez l'algorithme ici.

  7. Si fragid est une correspondance ASCII insensible à la casse pour la chaîne top, alors la partie indiquée du document est le haut du document; arrêtez l'algorithme ici.

  8. Sinon, aucune partie du document n'est indiquée.

Tant que nous atteignons l'étape 8 et qu'aucune partie du document n'est indiquée , la règle suivante entre en jeu:

S'il n'y a pas de pièce indiquée ... alors l'agent utilisateur ne doit rien faire.

c'est pourquoi le navigateur ne défile pas.

Matt Crinklaw-Vogt
la source
4
Peu importe si vous mettez "!" ou toute autre valeur, tant que l'identifiant ne fait pas partie du DOM.
Gopinath le
3
Après avoir été un partisan de cette méthode, j'ai depuis fait un 180 et je le déconseille. Attention: des liens comme celui-ci modifieront toujours l'URL de la page, ce qui entraînera une entrée supplémentaire dans l'historique du navigateur et amènera le bouton «retour» à simplement supprimer le fragment de l'URL au lieu de faire ce que l'utilisateur attend. Ainsi, cette solution en elle-même, tout en répondant à la question posée, n'est généralement pas une alternative souhaitable à l'utilisation preventDefault()dans un gestionnaire de clics - plutôt malheureusement.
Mark Amery
1
Pourquoi ne pas utiliser href = "javascript :;" au lieu? Autant que je sache, cela ne changera pas l'historique du navigateur. Publié à ce sujet sur ma réponse.
achecopar le
30

Une approche simple consiste à tirer parti de ce code:

<a href="javascript:void(0);">Link Title</a>

Cette approche ne force pas une actualisation de la page, donc la barre de défilement reste en place. En outre, il vous permet de modifier par programme l'événement onclick et de gérer la liaison d'événements côté client à l'aide de jQuery.

Pour ces raisons, la solution ci-dessus est meilleure que:

<a href="javascript:myClickHandler();">Link Title</a>
<a href="#" onclick="myClickHandler(); return false;">Link Title</a>

où la dernière solution évitera le problème de saut de défilement si et seulement si la méthode myClickHandler n'échoue pas.

phreeskier
la source
12

Renvoyer false à partir du code que vous appelez fonctionnera et dans un certain nombre de circonstances est la méthode préférée, mais vous pouvez également

<a href="javascript:;">Link Title</a>

En matière de référencement, cela dépend vraiment de l'utilisation de votre lien. Si vous envisagez de l'utiliser pour créer un lien vers un autre contenu, je conviendrais que vous voudriez quelque chose de significatif ici, mais si vous utilisez le lien à des fins de fonctionnalité, peut-être comme Stack Overflow le fait pour la barre d'outils de publication (gras, italique, lien hypertexte) , etc.) alors cela n'a probablement pas d'importance.

doyen
la source
9

Vous devriez changer le

<a href="#">My Link</a>

à

<a href="javascript:;">My Link</a>

De cette façon, lorsque le lien est cliqué, la page ne défile pas vers le haut. C'est plus propre que d'utiliser href = "#" et d'empêcher ensuite l'événement par défaut de s'exécuter.

J'ai de bonnes raisons à cela sur la première réponse à cette question , comme return false;ne s'exécutera pas si la fonction appelée lève une erreur, ou vous pouvez ajouter le return false;à une doSomething()fonction puis oublier d'utiliserreturn doSomething();

achécopar
la source
7

Essaye ça:

<a href="#" onclick="return false;">My Link</a>
Mikeluby
la source
4

Si vous pouvez simplement modifier la hrefvaleur, vous devez utiliser:

<a href="javascript:void(0);">Link Title</a>

Une autre solution intéressante que je viens de proposer consiste à utiliser jQuery pour empêcher l'action de clic de se produire et de faire défiler la page, mais uniquement pour les href="#"liens.

<script type="text/javascript">
    /* Stop page jumping when links are pressed */
    $('a[href="#"]').live("click", function(e) {
         return false; // prevent default click action from happening!
         e.preventDefault(); // same thing as above
    });
</script>
Dazbradbury
la source
Sûrement le return falsedevrait être après la preventDefault()ligne, sinon vous n'atteindrez jamais cette deuxième ligne?
hobailey
3

Lien vers quelque chose de plus sensible que le haut de la page en premier lieu. Puis annulez l'événement par défaut.

Voir la règle 2 de l' amélioration progressive pragmatique .

Quentin
la source
Cela rend également votre site plus convivial pour le référencement.
Frankie
2

Vous pouvez également utiliser event.preventDefault dans l' attribut onclick .

<a href="#" onclick="event.preventDefault(); doSmth();">doSmth</a>

Pas besoin d'écrire un événement de clic exstra.

éfirat
la source
0

Vous pouvez simplement écrire comme ceci aussi: -

<a href="#!" onclick="function()">Delete User</a>
user2436792
la source
0

Lors de l'appel de la fonction, suivez-la par return false exemple:

<input  type="submit" value="Add" onclick="addNewPayment();return false;">
buddhi weerasinghe
la source
0

Créez une page qui contient deux liens - un en haut et un en bas. En cliquant sur le lien du haut, la page doit faire défiler vers le bas de la page où le lien du bas est présent. En cliquant sur le lien du bas, la page doit défiler vers le haut de la page.

Damini
la source
0
<a onclick="yourfunction()">

cela fonctionnera très bien. pas besoin d'ajouter href = "#"

Varaj Vignesh
la source
0

Vous voudrez peut-être vérifier votre CSS. Dans l'exemple ici: https://css-tricks.com/the-checkbox-hack/ il y a position: absolute; top: -9999px;. C'est particulièrement loufoque sur Chrome, car onclick="whatever"il saute toujours à la position absolue de l'élément cliqué.

Retrait position: absolute; top: -9999px;, car display: none;pourrait aider.

Scott Phillips
la source
0

Pour Bootstrap 3 for collapse, si vous ne spécifiez pas data-target sur l'ancre et que vous comptez sur href pour déterminer la cible, l'événement sera évité. Si vous utilisez data-target, vous devrez empêcher l'événement vous-même.

<button type="button" class="btn btn-default" data-toggle="collapse" data-target="#demo">Collapse This</button>

<div id="demo" class="collapse"> 
<p>Lorem ipsum dolor sit amet</p>
</div>
doug
la source