Comment positionner un élément par rapport à un autre avec jQuery?

354

J'ai une DIV cachée qui contient un menu de type barre d'outils.

J'ai un certain nombre de DIVs qui sont activés pour afficher le menu DIV lorsque la souris les survole.

Existe-t-il une fonction intégrée qui déplace le menu DIV en haut à droite du DIV actif (survol de la souris)? Je cherche quelque chose comme$(menu).position("topright", targetEl);

Paul
la source
1
jetez un œil à stackoverflow.com/questions/8400876/… qui résout tant d'autres problèmes qui peuvent survenir
Toskan
Veuillez consulter "Les questions doivent-elles inclure des" balises "dans leurs titres?" , où le consensus est "non, ils ne devraient pas"!
Andreas Niedermair
@paul Oui, il y a une légère différence dans le style. Le titre initial de cette question était précédé de jQuery:, ce qui n'est pas recommandé. Habituellement, en raison du balisage supplémentaire de la question, ce qui rend le préfixe inutile. Si la technologie est nécessaire dans le titre, elle doit être capturée dans une vraie phrase, pas seulement un préfixe - car c'est à cela que servent les balises.
Andreas Niedermair

Réponses:

203

REMARQUE: cela nécessite jQuery UI (pas seulement jQuery).

Vous pouvez maintenant utiliser:

$("#my_div").position({
    my:        "left top",
    at:        "left bottom",
    of:        this, // or $("#otherdiv")
    collision: "fit"
});

Pour un positionnement rapide ( jQuery UI / Position ).

Vous pouvez télécharger jQuery UI ici .

Uriel
la source
1
J'ai essayé d'utiliser le plugin positon, mais pour une raison quelconque, je ne peux tout simplement pas le faire fonctionner :(
Salman A
Ne fonctionne pas non plus pour moi. Tenter de l'utiliser pour positionner un simple div de couleur unie au-dessus du corps a entraîné un décalage de 17 pixels en haut à gauche.
Eggplant Jeff
46
Notez que cette réponse dépend de jQueryUI, pas seulement de jQuery. Pourrait expliquer pourquoi cela ne fonctionne pas pour quelques-uns d'entre vous.
btubbs
398

tl; dr: (essayez-le ici )

Si vous avez le code HTML suivant:

<div id="menu" style="display: none;">
   <!-- menu stuff in here -->
   <ul><li>Menu item</li></ul>
</div>

<div class="parent">Hover over me to show the menu here</div>

alors vous pouvez utiliser le code JavaScript suivant:

$(".parent").mouseover(function() {
    // .position() uses position relative to the offset parent, 
    var pos = $(this).position();

    // .outerWidth() takes into account border and padding.
    var width = $(this).outerWidth();

    //show the menu directly over the placeholder
    $("#menu").css({
        position: "absolute",
        top: pos.top + "px",
        left: (pos.left + width) + "px"
    }).show();
});

Mais ça ne marche pas!

Cela fonctionnera tant que le menu et l'espace réservé auront le même parent de décalage. Si ce n'est pas le cas et que vous n'avez pas de règles CSS imbriquées qui se soucient de l'endroit où se trouve l' #menuélément DOM , utilisez:

$(this).append($("#menu"));

juste avant la ligne qui positionne l' #menuélément.

Mais ça ne marche toujours pas!

Vous pourriez avoir une disposition étrange qui ne fonctionne pas avec cette approche. Dans ce cas, utilisez simplement le plugin de position de jQuery.ui (comme mentionné dans une réponse ci-dessous), qui gère toutes les éventualités imaginables. Notez que vous devrez show()l'élément de menu avant d'appeler position({...}); le plugin ne peut pas positionner les éléments cachés.

Notes de mise à jour 3 ans plus tard en 2012:

(La solution originale est archivée ici pour la postérité)

Il s'avère donc que la méthode originale que j'avais ici était loin d'être idéale. En particulier, il échouerait si:

  • le parent de décalage du menu n'est pas le parent de décalage de l'espace réservé
  • l'espace réservé a une bordure / un rembourrage

Heureusement, jQuery a introduit des méthodes ( position()et outerWidth()) depuis 1.2.6 qui facilitent beaucoup la recherche des bonnes valeurs dans ce dernier cas. Dans le premier cas, appendl'élément de menu dans l'espace réservé fonctionne (mais enfreindra les règles CSS basées sur l'imbrication).

Jacob
la source
168
Whoa c'est bizarre: j'ai dû le faire l'autre jour, je ne me souvenais pas comment, je l'ai recherché sur Google et j'ai obtenu ... cette réponse! Je dois aimer SOF.
Jacob
17
Heh - j'ai eu la même chose qui m'arrive - je ne me souviens pas comment faire quelque chose, et j'ai trouvé ma propre réponse sur Stack Overflow.
Herb Caudill
16
Je pense que votre style de menu div devrait utiliser display: none au lieu de display: hidden.
Gabe
6
Cela ne fonctionnera pas correctement lorsque le conteneur du menu a la position: relative (ou quoi que ce soit en plus d'hériter), car position: absolue désactivera cela et .offset désactivera en haut à gauche de la page.
Mike Cooper
3
Selon la position de votre menu, le .offset () de jQuery peut être utilisé en remplacement de .position (). api.jquery.com/offset
Danny C
16

C'est ce qui a finalement fonctionné pour moi.

var showMenu = function(el, menu) {
    //get the position of the placeholder element  
    var pos = $(el).offset();    
    var eWidth = $(el).outerWidth();
    var mWidth = $(menu).outerWidth();
    var left = (pos.left + eWidth - mWidth) + "px";
    var top = 3+pos.top + "px";
    //show the menu directly over the placeholder  
    $(menu).css( { 
        position: 'absolute',
        zIndex: 5000,
        left: left, 
        top: top
    } );

    $(menu).hide().fadeIn();
};
Paul
la source
6

Voici une fonction jQuery que j'ai écrite qui m'aide à positionner les éléments.

Voici un exemple d'utilisation:

$(document).ready(function() {
  $('#el1').position('#el2', {
    anchor: ['br', 'tr'],
    offset: [-5, 5]
  });
});

Le code ci-dessus aligne le coin inférieur droit de # el1 avec le coin supérieur droit de # el2. ['cc', 'cc'] centrerait # el1 dans # el2. Assurez-vous que # el1 a le CSS de position: absolu et z-index: 10000 (ou un très grand nombre) pour le garder en haut.

L'option de décalage vous permet de déplacer les coordonnées d'un nombre spécifié de pixels.

Le code source est ci-dessous:

jQuery.fn.getBox = function() {
  return {
    left: $(this).offset().left,
    top: $(this).offset().top,
    width: $(this).outerWidth(),
    height: $(this).outerHeight()
  };
}

jQuery.fn.position = function(target, options) {
  var anchorOffsets = {t: 0, l: 0, c: 0.5, b: 1, r: 1};
  var defaults = {
    anchor: ['tl', 'tl'],
    animate: false,
    offset: [0, 0]
  };
  options = $.extend(defaults, options);

  var targetBox = $(target).getBox();
  var sourceBox = $(this).getBox();

  //origin is at the top-left of the target element
  var left = targetBox.left;
  var top = targetBox.top;

  //alignment with respect to source
  top -= anchorOffsets[options.anchor[0].charAt(0)] * sourceBox.height;
  left -= anchorOffsets[options.anchor[0].charAt(1)] * sourceBox.width;

  //alignment with respect to target
  top += anchorOffsets[options.anchor[1].charAt(0)] * targetBox.height;
  left += anchorOffsets[options.anchor[1].charAt(1)] * targetBox.width;

  //add offset to final coordinates
  left += options.offset[0];
  top += options.offset[1];

  $(this).css({
    left: left + 'px',
    top: top + 'px'
  });

}
Venkat D.
la source
3

Pourquoi trop compliquer? La solution est très simple

css:

.active-div{
position:relative;
}

.menu-div{
position:absolute;
top:0;
right:0;
display:none;
}

jquery:

$(function(){
    $(".active-div").hover(function(){
    $(".menu-div").prependTo(".active-div").show();
    },function(){$(".menu-div").hide();
})

Cela fonctionne même si,

  • Deux divs placés ailleurs
  • Navigateur redimensionné
gtamil
la source
cette méthode ne fonctionne pas si je veux émuler un espace réservé pour ie et l'afficher au-dessus de l'entrée (
tibalt
Cela ne fonctionne pas lorsque je veux aligner deux éléments qui sont des frères et sœurs ou même complètement indépendants, ce qui est très courant.
oriadam
3

Vous pouvez utiliser le plugin jQuery PositionCalculator

Ce plugin a également inclus la gestion des collisions (flip), de sorte que le menu de type barre d'outils peut être placé à une position visible.

$(".placeholder").on('mouseover', function() {
    var $menu = $("#menu").show();// result for hidden element would be incorrect
    var pos = $.PositionCalculator( {
        target: this,
        targetAt: "top right",
        item: $menu,
        itemAt: "top left",
        flip: "both"
    }).calculate();

    $menu.css({
        top: parseInt($menu.css('top')) + pos.moveBy.y + "px",
        left: parseInt($menu.css('left')) + pos.moveBy.x + "px"
    });
});

pour ce balisage:

<ul class="popup" id="menu">
    <li>Menu item</li>
    <li>Menu item</li>
    <li>Menu item</li>
</ul>

<div class="placeholder">placeholder 1</div>
<div class="placeholder">placeholder 2</div>

Voici le violon: http://jsfiddle.net/QrrpB/1657/

TLindig
la source
La console écrit Undefined n'est pas une fonction pour la ligne: var pos = $ .PositionCalculator ({Pouvez-vous s'il vous plaît aider à résoudre le problème?
Alexandr Belov
@AlexandrBelov: Je suppose que vous n'avez pas chargé le plugin. Avant de pouvoir l'utiliser, vous devez charger le fichier js du plugin PositionCalculator.
TLindig
2

Quelque chose comme ça?

$(menu).css("top", targetE1.y + "px"); 
$(menu).css("left", targetE1.x - widthOfMenu + "px");
slf
la source
2

Cela fonctionne pour moi:

var posPersonTooltip = function(event) {
var tPosX = event.pageX - 5;
var tPosY = event.pageY + 10;
$('#personTooltipContainer').css({top: tPosY, left: tPosX});
devXen
la source