41

I have a CSS only tooltip which loads a span as a tooltip when you hover the link. However this is positioned with CSS but if the link is near to the top of a page or side then the tooltip goes off the side/top of the page.

Is there a way with css to make this change or will I have to rely on JS? I have started to try to put something together with jQuery but would rather use CSS if possible.

JS fiddle at https://jsfiddle.net/gtoprh21/12/

Snippet:

$( ".ktooltip" )
.mouseover(function(e) {
   var mousex = e.pageX + 20; //Get X coordinates
   var mousey = e.pageY + 10; //Get Y coordinates
   if((mousey+100)>$(window).height())
   {

    $('.tooltip')
    .css({ top: mousey-100 ,left: mousex })

   }
   else if((mousex+200)>$(window).width())
   {
      $('.tooltip')
    .css({ top: mousey ,left: mousex-200})

   }
   else
    {
   $('.tooltip')
    .css({ top: mousey, left: mousex })

    }
})
.ref, .refs {
  position:relative;
}
/*added a text indent to overide indent styles further down*/
.ktooltip {
    display: inline-block;
    text-indent:0em;
}

.ref .ktooltiptext, .refs .ktooltiptext {
  visibility:hidden;
  width: 200px;
  background: #fff;
  border-radius: 6px;
  padding: 5px 5px;
  top: -40px;
  left: 10px;
  border:2px solid grey;
  line-height: normal;

    /* Position the tooltip */
    position: absolute;
    z-index: 1;
}

.ref:hover .ktooltiptext, .refs:hover .ktooltiptext {
    visibility: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>
 <span id="edtxt.trans1" class="tei l">My hope is in a bishop,
 <!--link to a reference -->
   <sup class="ref expl">
     <a href="#edtxt-explnote1" id="reference-to-edtxt-explnote1" class="ktooltip">1</a>
       <!-- lhe reference in a tooltip -->
       <span class="ktooltiptext">According to tradition <span style="name">Nicholas</span> was bishop of Myra in Lycia (south-west Turkey today).</span>
   </sup>
  </span><br>
  <span id="trans2" class="tei l">and in almighty God and his never-ending miracles.</span><br>
  <span id="trans3" class="tei l">Generous Saint Nicholas holds an office,</span><br>
  <span id="trans4" class="tei l">there is a gold symbol in his sign.
    <!-- likn to ref -->
    <sup class="ref expl">
      <a href="#edtxt-explnote2" id="reference-to-edtxt-explnote2" class="ktooltip">2</a>
        <!-- the tooltip -->
        <span class="ktooltiptext"> One of <span style="">Nicholas’s</span> symbols was three <sup>bags</sup> of gold <span style="font-variant: small-caps;">which</span> were the <span style="color: red;">dowry</span> he provided <span style="color: blue;">for</span> three <span style="color: green;">girls</span>
        </span>
    </sup>
   </span><br>
   </p>
Takit Isy
  • 9,688
  • 3
  • 23
  • 47
Paul M
  • 3,937
  • 9
  • 45
  • 53
  • Bad news, not possible. – VXp Jun 21 '18 at 14:03
  • Are the text from span elements and tooltip text fixed? If so you could position each tooltip depending on the referenced element (span) and its own size to fit in window. Otherwise is not possible with CSS. – August Jun 27 '18 at 15:21
  • Have you considered creating additional tooltip classes - eg tooltip-top, tooltip-bottom and use them per case? – scooterlord Jun 29 '18 at 18:28
  • Just to let you know that I've updated my answer with a JavaScript only solution; avoiding jQuery, the document will be lighter. ⋅⋅⋅ As I see you really want a CSS only solution, I've also added a CSS only *suggestion* without modifying any of your HTML. – Takit Isy Jul 08 '18 at 12:46

5 Answers5

39

Unfortunately, if you want to keep your tooltip good positioning, it isn't possible using only CSS.

Script solutions

But, as you're already using some script, I suggest you this solution:

  • Use position: absolute to position the .ktooltiptext accordingly to .ref,
  • Use the .getBoundingClientRect() method to easily get the position and size of the tooltip,
  • Apply some correction if out of the window,
  • Also made some modifications in CSS.

Snippet with only native JavaScript (avoiding jQuery, document will be lighter.)

var ktooltips = document.querySelectorAll(".ktooltip");
ktooltips.forEach(function(ktooltip, index){                // For each ktooltip
  ktooltip.addEventListener("mouseover", position_tooltip); // On hover, launch the function below
})

function position_tooltip(){
  // Get .ktooltiptext sibling
  var tooltip = this.parentNode.querySelector(".ktooltiptext");
  
  // Get calculated ktooltip coordinates and size
  var ktooltip_rect = this.getBoundingClientRect();

  var tipX = ktooltip_rect.width + 5; // 5px on the right of the ktooltip
  var tipY = -40;                     // 40px on the top of the ktooltip
  // Position tooltip
  tooltip.style.top = tipY + 'px';
  tooltip.style.left = tipX + 'px';

  // Get calculated tooltip coordinates and size
  var tooltip_rect = tooltip.getBoundingClientRect();
  // Corrections if out of window
  if ((tooltip_rect.x + tooltip_rect.width) > window.innerWidth) // Out on the right
    tipX = -tooltip_rect.width - 5;  // Simulate a "right: tipX" position
  if (tooltip_rect.y < 0)            // Out on the top
    tipY = tipY - tooltip_rect.y;    // Align on the top

  // Apply corrected position
  tooltip.style.top = tipY + 'px';
  tooltip.style.left = tipX + 'px';
}
.ref,
.refs {
  position: relative;
}

.ktooltip {
  display: inline-block;
  text-indent: 0em;
}

.ref .ktooltiptext,
.refs .ktooltiptext {
  visibility: hidden;
  width: 200px;
  background: #fff;
  border-radius: 6px;
  padding: 5px;       /* TAKIT: Changed here */
  top: -999px;        /* TAKIT: Changed here */
  left: -999px;       /* TAKIT: Changed here */
  border: 2px solid grey;
  line-height: normal;
  position: absolute; /* TAKIT: Changed here */
  z-index: 1;
}

.ref:hover .ktooltiptext,
.refs:hover .ktooltiptext {
  visibility: visible;
}
<p>
  <span id="edtxt.trans1" class="tei l">My hope is in a bishop,
 <!--link to a reference -->
   <sup class="ref expl">
     <a href="#edtxt-explnote1" id="reference-to-edtxt-explnote1" class="ktooltip">1</a>
       <!-- the reference in a tooltip -->
       <span class="ktooltiptext">According to tradition <span style="name">Nicholas</span> was bishop of Myra in Lycia (south-west Turkey today).</span>
  </sup>
  </span><br>
  <span id="trans2" class="tei l">and in almighty God and his never-ending miracles.</span><br>
  <span id="trans3" class="tei l">Generous Saint Nicholas holds an office,</span><br>
  <span id="trans4" class="tei l">there is a gold symbol in his sign.
    <!-- link to ref -->
    <sup class="ref expl">
      <a href="#edtxt-explnote2" id="reference-to-edtxt-explnote2" class="ktooltip">20</a>
        <!-- the tooltip -->
        <span class="ktooltiptext"> One of <span style="">Nicholas’s</span> symbols was three <sup>bags</sup> of gold <span style="font-variant: small-caps;">which</span> were the <span style="color: red;">dowry</span> he provided <span style="color: blue;">for</span>  three <span style="color: green;">girls</span>
  </span>
  </sup>
  </span><br>
</p>

Snippet with jQuery

$(".ktooltip").mouseover(function(e) {
  var tooltip = $(this).siblings('.ktooltiptext'); // Get tooltip element (ktooltiptext)
  var tipX = $(this).outerWidth() + 5;             // 5px on the right of the ktooltip
  var tipY = -40;                                  // 40px on the top of the ktooltip
  tooltip.css({ top: tipY, left: tipX });          // Position tooltip

  // Get calculated tooltip coordinates and size
  var tooltip_rect = tooltip[0].getBoundingClientRect();
  // Corrections if out of window
  if ((tooltip_rect.x + tooltip_rect.width) > $(window).width()) // Out on the right
    tipX = -tooltip_rect.width - 5; // Simulate a "right: tipX" position
  if (tooltip_rect.y < 0)            // Out on the top
    tipY = tipY - tooltip_rect.y;    // Align on the top

  // Apply corrected position
  tooltip.css({ top: tipY, left: tipX }); 
});
.ref,
.refs {
  position: relative;
}

.ktooltip {
  display: inline-block;
  text-indent: 0em;
}

.ref .ktooltiptext,
.refs .ktooltiptext {
  visibility: hidden;
  width: 200px;
  background: #fff;
  border-radius: 6px;
  padding: 5px;       /* TAKIT: Changed here */
  top: -999px;        /* TAKIT: Changed here */
  left: -999px;       /* TAKIT: Changed here */
  border: 2px solid grey;
  line-height: normal;
  position: absolute; /* TAKIT: Changed here */
  z-index: 1;
}

.ref:hover .ktooltiptext,
.refs:hover .ktooltiptext {
  visibility: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>
  <span id="edtxt.trans1" class="tei l">My hope is in a bishop,
 <!--link to a reference -->
   <sup class="ref expl">
     <a href="#edtxt-explnote1" id="reference-to-edtxt-explnote1" class="ktooltip">1</a>
       <!-- the reference in a tooltip -->
       <span class="ktooltiptext">According to tradition <span style="name">Nicholas</span> was bishop of Myra in Lycia (south-west Turkey today).</span>
  </sup>
  </span><br>
  <span id="trans2" class="tei l">and in almighty God and his never-ending miracles.</span><br>
  <span id="trans3" class="tei l">Generous Saint Nicholas holds an office,</span><br>
  <span id="trans4" class="tei l">there is a gold symbol in his sign.
    <!-- link to ref -->
    <sup class="ref expl">
      <a href="#edtxt-explnote2" id="reference-to-edtxt-explnote2" class="ktooltip">20</a>
        <!-- the tooltip -->
        <span class="ktooltiptext"> One of <span style="">Nicholas’s</span> symbols was three <sup>bags</sup> of gold <span style="font-variant: small-caps;">which</span> were the <span style="color: red;">dowry</span> he provided <span style="color: blue;">for</span>  three <span style="color: green;">girls</span>
  </span>
  </sup>
  </span><br>
</p>

With any of the above snippets, you can play with your window to see that the pop-up won't go outside on the right! It shouldn't go out on the top as well.


⋅ ⋅ ⋅

A CSS only suggestion

Now, if you don't care that much about the positioning of your tooltip, you can use this solution where I didn't change any of your HTML:

  • Use position: relative; on the span elements to use it as a reference,
  • Use position: absolute on the .ktooltiptext,
  • Use top and left to position the .ktooltiptext as you wish.

Using that solution, the tooltip will keep its style, but would be aligned on the left, under the span element, so the tooltip should never go out on the right or on the top.

p span { /* TAKIT: Changed here */
  position: relative;
}

.ktooltip {
  display: inline-block;
  text-indent: 0em;
}

.ref .ktooltiptext,
.refs .ktooltiptext {
  visibility: hidden;
  width: 200px;
  background: #fff;
  border-radius: 6px;
  padding: 5px;       /* TAKIT: Simplified here */     
  border: 2px solid grey;
  line-height: normal;
  position: absolute; /* TAKIT: Changed */
  top: 20px;          /* TAKIT: Changed */
  left: 0;            /* TAKIT: Added to always align tooltip on the left of the span */ 
  z-index: 1;
}

.ref:hover .ktooltiptext,
.refs:hover .ktooltiptext {
  visibility: visible;
}
<p>
  <span id="edtxt.trans1" class="tei l">My hope is in a bishop,
 <!--link to a reference -->
   <sup class="ref expl">
     <a href="#edtxt-explnote1" id="reference-to-edtxt-explnote1" class="ktooltip">1</a>
       <!-- the reference in a tooltip -->
       <span class="ktooltiptext">According to tradition <span style="name">Nicholas</span> was bishop of Myra in Lycia (south-west Turkey today).</span>
  </sup>
  </span><br>
  <span id="trans2" class="tei l">and in almighty God and his never-ending miracles.</span><br>
  <span id="trans3" class="tei l">Generous Saint Nicholas holds an office,</span><br>
  <span id="trans4" class="tei l">there is a gold symbol in his sign.
    <!-- link to ref -->
    <sup class="ref expl">
      <a href="#edtxt-explnote2" id="reference-to-edtxt-explnote2" class="ktooltip">20</a>
        <!-- the tooltip -->
        <span class="ktooltiptext"> One of <span style="">Nicholas’s</span> symbols was three <sup>bags</sup> of gold <span style="font-variant: small-caps;">which</span> were the <span style="color: red;">dowry</span> he provided <span style="color: blue;">for</span>  three <span style="color: green;">girls</span>
  </span>
  </sup>
  </span><br>
</p>
Takit Isy
  • 9,688
  • 3
  • 23
  • 47
  • This is great and works well, however on a page with a lot of text, the popup appears in the same regardless of where the page has been scrolled to. So if you scroll the page, the popup is then not in alignment with the hover or its off the page if that is where the page loaded with the link/hover. – Paul M Jun 28 '18 at 16:11
  • @PaulM I see what you mean. If we put more text, what element will be scrollable? As we could know for how much it has been scrolled, we could compensate the position of the tooltip accordingly. – Takit Isy Jun 28 '18 at 16:51
  • @PaulM Forget about my question above. I modified the `position` from `fixed` to `absolute` and used the `.getBoundingClientRect()` method to get the size and coordinates of our element in order to correct them. See the snippet. I hope it will fulfill your needs. :) – Takit Isy Jun 29 '18 at 07:45
  • Some great work here, thanks Takit. I have awarded you the first bounty and the correct answer. – Paul M Jul 10 '18 at 10:48
  • Small changes now here is not window.innerWidth is replaced by window.visualViewport.width. – Shashank Bhatt Feb 10 '21 at 09:29
  • Oh so its window.screen.width now in above comment. – Shashank Bhatt Feb 10 '21 at 10:05
  • I know I'm a bit late, but I'm not changing my code: https://stackoverflow.com/questions/37443482/what-is-the-difference-between-window-innerwidth-and-screen-width – Takit Isy Feb 24 '22 at 10:00
9

You can try this with only CSS and no JS at all. Not the most elegant type of tooltip but it will never fail you and it will never give you up :)

    .ktooltip {
        display: inline-block;
        text-indent:0em;
    }
    
    .ktooltiptext, .ktooltiptext {
    display: none;
        width: calc(100vw - 35px);
        background: #fff;
        border-radius: 6px;
        padding: 5px 5px;
        left: 10px;
        border: 2px solid grey;
        line-height: normal;
        text-decoration: none;
        position: absolute;
        z-index: 1;
    
    }
    
    p {display:inline-block}
    
    .ktooltip:hover + span {
        display: block;
    }
    <p>
     <span id="edtxt.trans1" class="tei l">My hope is in a bishop,
     <!--link to a reference -->
    <div style="display:inline-block">
      <a href="#edtxt-explnote1" id="reference-to-edtxt-explnote1" class="ktooltip">1</a>
         
    <span class="ktooltiptext">According to tradition <span style="name">Nicholas</span> was bishop of Myra in Lycia (south-west Turkey today).</span>
    </div>
    
      </span><br>
      <span id="trans2" class="tei l">and in almighty God and his never-ending miracles.    </span><br>
      <span id="trans3" class="tei l">Generous Saint Nicholas holds an office,</span><br>
      <span id="trans4" class="tei l">there is a gold symbol in his sign.
        <!-- likn to ref -->
          <a href="#edtxt-explnote2" id="reference-to-edtxt-explnote2" class="ktooltip">2</a>
            <span class="ktooltiptext" onclick="return false;"> One of <span style="">Nicholas’s</span> symbols was three <sup>bags</sup> of gold <span style="font-variant: small-caps;">which</span> were the <span style="color: red;">dowry</span> he provided <span style="color: blue;">for</span> three <span style="color: green;">girls</span>
            </span>
       </span><br>
       </p>

https://jsfiddle.net/gtoprh21/72/

EPurpl3
  • 682
  • 7
  • 25
  • Well, it should be a footer or at least padding. Thats a very extreme case. – EPurpl3 Jun 28 '18 at 07:40
  • Interesting idea, I could play around with the width and instead of doing a calc, just set it at 50vw so its not quite so big. I could also use this to position it at the bottom of the page for all states too. – Paul M Jun 28 '18 at 16:22
  • The advantage of this is that is really light. You can remove a lot of code from the page, including HTML, CSS and JS. If you have many tooltips on page it will save you a few KB, which is a good thing for SEO, which is one of the most important thing regarding websites, nobody wants to make websites that nobody visits, regardless of the technology you use. – EPurpl3 Jul 03 '18 at 09:07
  • I really liked the lightness of this so have awarded you an extra bounty. It also taught me about vw measurements in css. – Paul M Jul 10 '18 at 10:46
  • Thank you, that's so nice of you. Glad i could help. – EPurpl3 Jul 19 '18 at 08:57
  • it fail when there is a scroll in the list and we need to open the tooltip on top instead of down – Pardeep Sharma Mar 30 '20 at 11:42
  • That depends of what kind of tooltip you use. You could ask a question on StackOverflow, i would be happy to answer it. – EPurpl3 Apr 06 '20 at 17:32
2

Option 1) Using title global attribute

title - Specifies extra information about an element (displayed as a tool tip)

Docs: The title global attribute Use of the title attribute is highly problematic for:

  • People using touch-only devices
  • People navigating with keyboards
  • People navigating with the aid of assistive technology such as screen readers or magnifiers
  • People experiencing fine motor control impairments
  • People with cognitive concerns. This is mainly due to inconsistent browser support, compounded by the additional complication introduced by assistive technology's parsing of the browser-rendered page.

span {border-bottom: 1px dashed pink}
<span title="According to tradition Nicholas was bishop of Myra in Lycia (south-west Turkey today).">
Mouse over this paragraph, to display the title attribute as a tooltip.
</span>

Option 2) If the text and the tooltip text are fixed sized: 4 css classes can be used to place the tooltip referencing the trigger element. Something like:

.tooltip-top {top: -3em}
.tooltip-bottom {top: 0}
.tooltip-left {left: -3em}
.tooltip-right {right: 0}
August
  • 2,045
  • 10
  • 23
2

although the whole thing needs to recode but you can achieve that with something like this :

$(".ktooltip").on('mouseover', function(e) {
    var tooltip = $('.ktooltiptext'),
        wt = $(window).scrollTop(), //window top pos
        ww = $(window).outerWidth(), //window width
        tt = tooltip.offset().top, //Tooltip top pos
        tl = tooltip.offset().left, //Tooltip left pos
        tw = tooltip.outerWidth(); //Tooltip Width

    tooltip.css({ 'left': '10px', 'right': 'auto', 'top': '-40px' });

    if(tt < wt) tooltip.css('top', 0);
    if((tl + tw) > ww) tooltip.css({ 'left': 'auto', 'right': 0 });
})
MajiD
  • 2,420
  • 1
  • 22
  • 32
0

just copy this css nd replace with your class

.ref .ktooltiptext, .refs .ktooltiptext

.ref .ktooltiptext, .refs .ktooltiptext {
  visibility:hidden;
  width: 200px;
  background: #fff;
  border-radius: 6px;
  padding: 5px 5px;
  top: -15px;
  left: 10px;
  border:2px solid grey;
  line-height: normal;

    /* Position the tooltip */
    position: absolute;
    z-index: 1;
}
bharat savani
  • 339
  • 5
  • 18