css tooltip (web.dev)

Table of Contents

  • copyright
  • introduce
  • tool-tip
    • centered on
    • animation effect
    • width
    • boundary
  • tool-tip::after
    • scope
    • tapered gradient
    • -webkit-mask
    • Where did the sharp corner come from?
  • appendix
    • full code

Copyright

This article is original, following the CC 4.0 BY-SA copyright agreement, reprints must indicate the source: https://blog.csdn.net/big_cheng/article/details/130262213.

Introduction

https://web.dev/building-a-tooltip-component/ introduces the implementation of a tooltip. This article simplifies it and analyzes the principle. The effect comparison diagram is as follows:

When the mouse hovers to the parent container, the tooltip will appear.

tool-tip

tooltip is implemented as a child element:

 a<br>b<br>c<br>

    preceding

    <div id="ct" style="display: inline-block; border: 1px solid;">
        div content div content div content
        <tool-tip>this is tip content</tool-tip>
    </div>

The browser actually sees this unknown “tool-tip” element as a “div”.

Centered on top

Tooltip is absolutely positioned, docked above the parent container:

tool-tip {<!-- -->
--_triangle-size: 7px;
\t
position: absolute;
bottom: calc(100% + 0.75ch + var(--_triangle-size));
?…

To achieve horizontal centering, first center the left edge, and then offset half of its own width to the left:

 left: 50%;
transform: translateX(-50%) translateY(3px);

Animation effect

Display the tooltip by modifying “opacity”, and fine-tune the y value to achieve a slight ‘jump’:

tool-tip {<!-- -->
?…
opacity: .2;
transform: translateX(-50%) translateY(3px);
transition: opacity .2s ease, transform .2s ease;
?…
}
#ct {<!-- -->
position: relative;
}
#ct:hover > tool-tip {<!-- -->
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    transition-delay: 200ms;
}

“translateY” positive value is down.

Note: For the convenience of debugging, the initial “opacity” was changed to “.2”.

width

tool-tip {<!-- -->
?…
width: max-content;
max-width: 25ch;
text-align: center;

Determine the width according to the content. Debugging can find that when the screen width is compressed to the tool-tip ‘inside’, the body appears HScroll.

Boundary

tool-tip has no border line – similar effect can be achieved by filter:

 will-change: filter;
filter:
drop-shadow(0 3px 3px hsl(0 0% 0% / 15%))
drop-shadow(0 12px 12px hsl(0 0% 0% / 15%));
}

tool-tip::after

Use ::after to achieve a sharp corner on the bottom edge of the tooltip.

Range

The ::after element uses absolute positioning and occupies the area of the tool-tip:

tool-tip::after {<!-- -->
?…
background: white;
position: absolute;
z-index: -1;
top: 0; right: 0; left: 0;
bottom: -7px;
border-bottom: 7px solid transparent;
?…

Bottom extends 7px more – for sharp corners.

debugging:
a) Disable “opacity|filter” of tool-tip, add “border: 1px solid”
b) Modify ::after: “background: red;”

It can be seen that ::after is within the range of tool-tip (as the parent container) and descends.

Tapered Gradient

For example, the small black block below the horizontal line:

<style>
#ct2 {<!-- -->width: 50px; height: 50px;
background: white conic-gradient(
from -30deg at bottom, #0000, #000 1deg 60deg, #0000 61deg);
?…
}
</style>

<div id="ct2"></div>

a) Vertical upward from the origin is 0 degrees, and -30 degrees is to the left (counterclockwise)
b) The origin “bottom” is “bottom center” – the midpoint at the bottom of the decorated container
c) “#0000”: The line 30 degrees to the left is black and fully transparent (the fourth zero)
d) “#000 1deg 60deg”: The range from 1 to 60 degrees to the right (clockwise) of the previous line is black (the previous transparent line plays the role of anti-aliasing)
e) “#0000 61deg”: Finally, it is black and transparent by 1 degree to the right, and it is still anti-aliasing
f) The rest of the 360-degree range is undefined – display the background color (white) previously defined by the conic-gradient

-webkit-mask

Apply a tapered gradient to the lower side of the ::after element:

tool-tip::after {<!-- -->
?…
-webkit-mask: conic-gradient(from -30deg at bottom, #0000, #000 1deg 60deg, #0000 61deg) bottom / 100% 50% no-repeat;
mask: conic-gradient(from -30deg at bottom, #0000, #000 1deg 60deg, #0000 61deg) bottom / 100% 50% no-repeat;

a) “bottom”: The starting position of the tapered mask image is the midpoint below the mask area. The mask area is the border-box of the decorated container by default.
b) “100% 50%”: The size of the mask image. This is the entire horizontal and vertical half of the mask area.
c) “no-repeat”: No repetition, that is, the mask image will not be drawn horizontally and vertically.

Note: Chrome uses “-webkit-mask” instead of “mask”.

debugging:
a) Modify ::after: “background: red;”

Visible mask plots are drawn starting from the midpoint at the bottom of the ::after element.

Because ::after “z-index” is -1, the content of ::after is displayed below the content of tool-tip (does not ‘cut’ the text).

How did the sharp corner come from?

debugging:
a) tool-tip: disable “opacity”, add “border: 1px solid”
b) ::after modification: “background: red; border-bottom: 7px solid blue;”

::after Comparison of disabling and enabling “-webkit-mask”:

The ::after color is only preserved within the black area of the tapered gradient (tool-tip border-bottom overlap is also ‘wiped out’).

The tool-tip “filter” creates a shadow effect on the sharp corners and the bottom edges on both sides. If “filter” is disabled, the sharp corners cannot be seen, only a small gap in the middle of the bottom edge.

Appendix

Complete code




    

    a<br>b<br>c<br>

    preceding

    <div id="ct" style="display: inline-block; border: 1px solid;">
        div content div content div content
        <tool-tip>this is tip content</tool-tip>
    </div>