0

I am trying to create a tooltip element that has a min width of 50px and a max width of 200px. I place the tooltip element inside another element so that I can easily control when the tooltip appears or disappears when there is a hover event on the parent.

The problem that I have is that the tooltip element's width appears to be controlled by the parent's width even though I specified that the child(tooltip) has an absolute position.

let p = document.getElementById( 'parent' );
let b = true;
setInterval( ()=> {
  b = !b;
  let w = 10;
  if( b ) {
    w = 300;
  }
  p.style.width = `${w}px`
}, 5000 );
#parent {
  background-color: cyan;
  width: 100px;
  height: 25px;
  position: relative;
  transition: width 2s;
}

#tooltip {
  position: absolute;
  top: calc( 100% + 5px );
  left: 5px;
  min-width: 50px;
  max-width: 200px;
  background-color: yellow;
  padding: 5px;
  border: 1px solid black;
}
<div id="parent">
  <div id="tooltip">
    My long tooltip text that wraps to multiple lines as needed.
  </div>
</div>

I would like the tooltip (yellow div) to keep it's size at 200px in this example, but we can see that when the parent changes width, the tooltip width also changes. Why?

Is there a way to fix this problem?

Clarification: In this example: https://codepen.io/anon/pen/ePPWER we see that the tooltip text looks nice on one line. I don't want the tooltip's div to change its width when the parent changes width, because it forces the tooltip text to wrap onto 2 lines which is undesirable.

Marek Krzeminski
  • 1,308
  • 3
  • 15
  • 40
  • you didn't define a width but a max/min-width thus the width is set to auto – Temani Afif Oct 23 '18 at 19:35
  • I want the width of the tooltip to fit the content inside the tooltip div up to the maximum width (200px). I don't want to fix the width to a specific size that is why I didn't set the width of the child. – Marek Krzeminski Oct 23 '18 at 19:48
  • Your code is working as it should. Check out [this Fiddle](http://jsfiddle.net/bcdv7gq4/19/) where I've added elements at static widths of 50px and 200px. You will see that the tooltip never goes past the 200px mark and it doesn't quite down to 50px but that is because the shortest word in there is a bit bigger than 50px. If you want to keep the tooltip at 200px all the time, don't use min and max widths, just set the width to 200. – Scott Marcus Oct 23 '18 at 20:00
  • @ScottMarcus I don't want to fix the width to 200px. I want the tooltip's content to dictate the width of the tooltip div ( not the parent div's width). In this example https://codepen.io/anon/pen/oaaWvE with the tooltip text can fit nicely on 2 lines. If the parent changes width, I don't want the child's width to change. In this example https://codepen.io/anon/pen/ePPWER the text can fit nicely on one line. I don't want the parent changing the tooltip width and causing 2 lines with wrapping – Marek Krzeminski Oct 23 '18 at 20:16

3 Answers3

2

If we check the specification related to the width of absolutely positioned element we can read this:

  1. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'

So in your case the width of your element is shrink to fit:

Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.

Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).

To make it easy, and without considering the min/max-width, the width of your element will try to fit the content without exceding the width of its parent container (containing block). By adding min/max-width you simply add more constraint.

One idea of fix it to remove positon:relative from the parent element so that it's no more the containing block of the position:absolute element (it will be the initial containing block which is wide enough to avoid the available width constraint).

Then use margin instead of top/left to control the position:

let p = document.getElementById( 'parent' );
let b = true;
setInterval( ()=> {
  b = !b;
  let w = 10;
  if( b ) {
    w = 300;
  }
  p.style.width = `${w}px`
}, 5000 );
#parent {
  background-color: cyan;
  width: 100px;
  height: 25px;
  transition: width 2s;
}

#tooltip {
  position: absolute;
  margin-top: 30px;
  min-width: 50px;
  max-width: 200px;
  background-color: yellow;
  padding: 5px;
  border: 1px solid black;
}
<div id="parent">
  <div id="tooltip">
    My long tooltip text that wraps to multiple lines as needed.
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • In this code snippet, the parent is no longer the parent that the tooltip positions itself relative to... which is a problem. I'd like the tooltip to be placed 5 px's below the parent and 5px's to the left of the parent. So if you add the missing css styling: top: calc( 100% + 5px ); left: 5px; We will see that the tooltip is now being positioned out of view because it is using the body as it's parent – Marek Krzeminski Oct 23 '18 at 20:08
  • @MarekKnows.com that's why you need to use margin and no more top/left (as I explained) ... and it's not the body but the initial containing block (also explained) – Temani Afif Oct 23 '18 at 20:21
  • Sorry about that, I totally missed your point about using margins. I now see what you mean and yes, this seems to work as I expect it. Thank you! – Marek Krzeminski Oct 23 '18 at 20:40
0

ID Tooltip is being used under Parent. When parent's width changes, it also suggest that tooltip's total width is changed. Since you have used mix-width and max-width it will expand till it reaches max-width. If you want it to be fixed then simple use width.

  • I don't want the tooltip div to have a fixed width. I also don't want the parent to dictate the width of the child (tooltip). I want the tooltip to get its width based on the content that it holds and not care about the width of the parent. – Marek Krzeminski Oct 23 '18 at 19:51
0

It is because the .parent has a position: relative. This will keep all children (position: absolute included) as confined by the parent div.

Not sure if this will work for you because it is pulling the tooltip out of the parent and making it's own with span wrapping the text. Alternatively, you'll need to change the parent from being relative otherwise it'll continually affect the child.

let p = document.getElementById('parent');
let b = true;
setInterval(() => {
  b = !b;
  let w = 10;
  if (b) {
    w = 300;
  }
  p.style.width = `${w}px`
}, 5000);
#parent {
  background-color: cyan;
  width: 100px;
  height: 25px;
  transition: width 2s;
  position: relative;
}

#root {
  position: relative;
}

#tooltip {
  width: 100%;
}

#tooltip span {
  position: absolute;
  top: calc( 100% + 5px);
  left: 5px;
  min-width: 50px;
  max-width: 200px;
  background-color: yellow;
  padding: 5px;
  border: 1px solid black;
}
<div id="root">
  <div id="parent"></div>
  <div id="tooltip">
    <span>My long tooltip text that wraps to multiple lines as needed.</span>
  </div>
</div>
Darren
  • 2,176
  • 9
  • 42
  • 98
  • I want a min-width of 50px, so that if I have short tooltip text then it looks okay. see https://codepen.io/anon/pen/ePPWER. I don't want the child to change width when the parent changes width. – Marek Krzeminski Oct 23 '18 at 20:24
  • 1
    I have updated the answer but it may not be right for your application. The answer by @Temani Afif seems to be spot on for your use. – Darren Oct 23 '18 at 20:38