Alvaro Menéndez
Alvaro Menéndez

Reputation: 9012

How can I move an absolute positioned element if out of viewport?

I have many boxes with differents widths. All of them are displayed inline-block so they will be distributed differently as window width changes.

Every box has a big tooltip that will show on hover. These tooltips have a fixed width and height, same for all of the boxes.

These tooltips are position:absolute over the boxes and centered with:

left: 50%;
margin-left: -halfwidth; 

My problem is that if the box is close to window left or right they will be partially hidden (I have no problem with top and bottom, they will never reach those edges)

Is there any easy way with javascript (better if jquery) to detect when the element is out of the viewport and then change the left property accordingly to prevent it?

any help, hint or comment will be greatly apreciated. Thank You

JSFIDDLE

html, body {margin:0;padding:0;height:100%;}
ul {
  width:100%; 
  text-align:center;
  position:relative;
  top:50%;
  transform:translateY(-50%);
  padding:0;
  }
li {
  display: inline-block;
  background-color: red;
  width: 100px;
  height: 25px;
  margin-right: 10px;
  position: relative;
}

.hover-element {
  position: absolute;
  background-color: yellow;
  z-index: 9999;
  width: 350px;
  height: 175px;
  left: 50%;
  margin-left: -175px;
  bottom:25px;
  display: none;
  border:1px solid #000;
}

li:hover .hover-element {
  display: block;
}
.hover-element:hover {
  visibility: hidden;
}
<ul>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
</ul>

Upvotes: 4

Views: 3348

Answers (5)

Shiven Sinha
Shiven Sinha

Reputation: 696

I'm going to mention the steps here. If you'd need the code, just ask for it. I am currently on my mobile device, so typing the code would get hard!

Steps

  • To make things easy to include JS, change the display property using JS. Accomplish this using a mouse event on each of the list items, that changes their respective tooltip's display property. (Here's how to access the respective child)

In the same hover event, do these:

  • After changing the display, check if the tooltip element is in viewport. You can refer to the link Victor Medeiros provided.

  • If is not completely in viewport, change the margin-left property to -175px - (the number of pixels it crossed the boundary by). I just realised, if it crosses the viewport, just set the margin-left or margin-right (as applicable, find it by getBoundingClientRect) to 0.

Yep, that's it! I hope that should work, I haven't tried it out. What's the result?

Upvotes: 1

JiangangXiong
JiangangXiong

Reputation: 2426

Have a look:

var windowWidth = document.body.scrollWidth || window.innerWidth;
$('li').on('mouseenter', function(e){
  var $hover = $(this).find('.hover-element');
  var coords = $hover[0] && $hover[0].getBoundingClientRect();
  var rightDistance = 0;
  
  if (coords.left <= 0) {
    $hover.css({
      'left': ($hover.css('left').split('px')[0] - coords.left) + 'px'
    })
  }
  rightDistance = windowWidth - coords.left - $hover.width() - 2 * $hover.css('borderWidth').split('px')[0];
  if (rightDistance < 0) {
    $hover.css({
      'left': ($hover.css('left').split('px')[0] - (-rightDistance)) + 'px'
    })
  }
  $('p').html($hover.css('left') + '/' + coords.left)
})
html, body {margin:0;padding:0;height:100%;overflow-x: hidden;}
ul {
  width:100%; 
  text-align:center;
  position:relative;
  top:50%;
  transform:translateY(-50%);
  padding:0;
  }
li {
  display: inline-block;
  background-color: red;
  width: 100px;
  height: 25px;
  margin-right: 10px;
  position: relative;
}

.hover-element {
  position: absolute;
  background-color: yellow;
  z-index: 9999;
  width: 350px;
  height: 175px;
  left: 50%;
  margin-left: -175px;
  bottom:25px;
  display: none;
  border:1px solid #000;
}

li:hover .hover-element {
  display: block;
}
.hover-element:hover {
  visibility: hidden;
}
<script
  src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous"></script>
<ul>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
</ul>

Upvotes: 2

Awsme Sandy
Awsme Sandy

Reputation: 1408

Thats all you need, i detected the offset left position of the div, and added the class to li and a small tweaks in css.

$("li").mouseenter(function(){
 var f = $(this).find('.hover-element');
    var rightEdge = f.width() + f.offset().left;
    var leftEdge = f.offset().left;
    var screenWidth = $(window).width();
    if(leftEdge < 0){
    $(this).addClass("left");
    $(this).removeClass("right");
    }
    else if(rightEdge > screenWidth){
    $(this).addClass("right");
    $(this).removeClass("left");
    }
    else{
    $(this).removeClass("right lefft");
    }


});

$("li").mouseleave(function(){
$(this).removeClass("right lefft");
}) 
html, body {margin:0;padding:0;height:100%;}
ul {
  width:100%; 
  text-align:center;
  position:relative;
  top:50%;
  transform:translateY(-50%);
  padding:0;
  }
li {
  display: inline-block;
  background-color: red;
  width: 100px;
  height: 25px;
  margin-right: 10px;
  position: relative;
}

.hover-element {
  position: absolute;
  background-color: yellow;
  z-index: 9999;
  width: 350px;
  height: 175px;
  left: 50%;
  margin-left: -175px;
  bottom:25px;
  display: none;
  border:1px solid #000;
}
li.left .hover-element{
    left: 0;
    margin-left: 0;
}
li.right .hover-element{
    margin-left: 0;
    left: auto;
    right: 0;
}
li:hover .hover-element {
  display: block;
}
.hover-element:hover {
  visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
  <li>
    <div class="hover-element"></div>
  </li>
</ul>

Upvotes: 3

Victor Medeiros
Victor Medeiros

Reputation: 116

The following links are a starting point for your question (if not the actual answer).

Is there any easy way with javascript (better if jquery) to detect when the element is out of the viewport and then change the left property accordingly to prevent it?

How to tell if a DOM element is visible in the current viewport?

Absolute position of an element on the screen using jQuery

Upvotes: 1

yavonz15
yavonz15

Reputation: 178

Change

li {
    display: inline-block;
    background-color: red;
    width: 100px;
    height: 25px;
    margin-right: 10px;
    position: relative;
}

Whit

li {
    display: inline-block;
    background-color: red;
    width: 100px;
    height: 25px;
    margin-right: 10px;
    position: static;
}

Upvotes: -5

Related Questions