Using SVG to realize the function of prompt box




Tooltips are often referred to asPrompt box (or information prompt box)The prompt box can provide users with corresponding prompt information with strong interactivity and degree of freedom. Today we’re not going to talk about how to achieve powerful interaction, but to see how to restore their visual effects in the best way, and can be applied to different scenes.



The above figure is a screenshot of UI effects encountered in normal work scenes. The tooltips box shown above basically covers common UI styles. To sum it up briefly:

  • Prompt box with border
  • Prompt box for solid color (or solid color with transparency)
  • Tip box with inner shadow (or outer shadow)
  • Tip box with border + gradient
  • Tip box with border and transparent background
  • Tip box triangle tip box with rounded corners and shadows

There may be another UI style that I didn’t come across. Faced with so many UI styles, it is challenging for the front-end implementation, especially the combination of various effects. For example, with border + inside and outside shadow + gradient (or transparency) + rounded triangle, etc. Basically a combination of the various UI styles mentioned above.


Clip path scheme

Usually, the implementation of the above figure is to use CSS to draw a sharp corner to join it. The better scheme is shown in the following figure:

Let’s make a brief introductionclip-pathScheme:

The prompt box is divided into two parts, one is square, the other is triangle, and then the two are spliced together to form a prompt box. Thus, the whole coordinate diagram is as follows:

Suppose the size of the prompt box isw x h, the border thickness ish1Then, the following coordinate points are needed to draw a notch:

  • d1coordinate(0, 0)
  • d2coordinate((50% - b), 0)or((w / 2 - b), 0)amongbIt’s half the length of the diagonal side of a triangle, as we’ll see later
  • d3coordinate((50% - b - h1), h1)or((w / 2 - b - h1), h1)
  • d4coordinate((50% + b + h1), h1)or((w / 2 + b + h1), h1)
  • d5coordinate((50% + b), 0)or((w / 2 + b), 0)
  • d6coordinate(100%, 0)or(w, 0)
  • d7coordinate(100%, 100%)or(w, h)
  • d8coordinate(0, 100%)or(0, h)

Coordinate points placed inclip-pathOfpolygon()Function, the final cut shape looks like the following figure

clip-path: polygon(
    0 0,
    calc(50% - 4px) 0,
    calc(50% - 7px) 2px,
    calc(50% + 7px) 2px, 
    calc(50% + 4px) 0, 
    100% 0, 
    100% 100%, 
     0 100%,
    0 0);

The other is the part of the triangle, if our triangle is one10px x 10pxrotate45degGet it. According to the formula of some trigonometric functions and the known side length of the square, the length of the diagonal angle of the square can be calculated


The clip path scheme encountered problems

This effect looks good on the whole, but if you look closely, you will find that there may be gaps and overlaps at the joints, as shown in the following figure:

usevwAfter the scheme, this kind of pixel misalignment problem is also common. At the same time, the first tooltips needs to be gradient from left to right because of the background. At this time, it takes more effort to match the gradient at the sharp corner and the gradient below.

Due to the previous experience with this kind of tool tip style problem, after informing the visual students, the considerate visual students modified a version of the solid color prompt box without transparency, but the visual effect was greatly reduced.

In fact, we used CSS in the pastclip-pathIn fact, there are a lot of defects in the scheme. It shows the disadvantages of high cost and general effect when it appears with shadow, transparent background or gradient, and border.


Svg scheme

In the discussion, we think of SVGpathIt matches the style of the prompt box naturallypathAfter consulting the relevant documents and materials, we can roughly get the following advantages of using SVG:

  • Can easily meet the shadow, background transparent or gradient, with border effect, even more complex and changeable scene
  • Svg’spathThe implementation is simple, and the amount of code is very small
  • Scalability, maintainability

After referring to relevant articles, we improve demo tools as follows:

Using the demo tool, we getpathThe data are roughly as follows:

M 0,0 L -15,-15 H -79 Q -84,-15 -84,-20 V -85 Q -84,-90-79,-90
H 61 Q 66,-90 66,-85 V -20 Q 66,-15 61,-15 H 15 z

SVG is usually usedpathThe following commands are used:

command name parameter
M Move to (x y)+
Z Closepath (close path) (none)
L Line to (x y)+
H Horizontal line to x+
V Vertical line to y+
C Curveto (cubic Bezier curve to) (x1 y1 x2 y2 x y)+
S Smooth curveto (smooth cubic Bezier curve to) (x2 y2 x y)+
Q Quadratic B é zier curveto (x1 y1 x y)+
T Smooth quadric B é zier curveto (x y)+
A Elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
R Catmull ROM curveto * (Catmull ROM curve) x1 y1 (x y)+

Bezier curve

In SVGpathI personally think the most essential part of the command is the Bezier curve, which can draw all kinds of pleasant curves.

The shape of Bezier curve is completely determined by its control points. N control points correspond to Bessel curve of order n-1, and canDraw it recursively.Let’s first look at how the next and second Bezier curves are drawn

Primary curve:

On a straight line, with the change of time t, the coordinate formula of that point on the red line segment should be as follows:

Quadratic Bezier curve:

p0、p1、p2Three points that are not collinear are connected by line segments in turn. At this time, the line segments are randomly selectedp0p1A point onp0'As shown above: ourp0'Point atp0p126 (t = 0. 26), nowp1p2Take the same ratio of line segmentsp1'At this pointp0'andp1'Connect to form a line segmentp0'p1', the value is calculated according to the above ratio columnp0''In this case, we determine a point of the quadratic Bezier curve.

After the derivation of balabalabala, the quadratic Bessel curve formula is as follows:

The nth degree Bessel curve can be considered as the iterative process of the above value taking method. The change process of the 1 ~ 4 degree curve with time t can be intuitively felt through the figure below. For the specific formula of the n-degree Bessel curve, please refer to the article on the curve below

Q command in SVG

Back to ourToolTipsTopic, where the fillet can be achieved by quadratic Bezier curve, SVGQThe command is to implement the quadratic Bezier curve in SVGQAn example of the command is shown below:

The corresponding instructions, where X1 and Y1 are the ones mentioned abovep1Point:

Q x1 y1, x y

quadratic Bezier curve QExamples are as follows:

<svg width="190px" height="160px" version="1.1" xmlns="">
   <path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>

By setting the starting point and adjusting the control pointp1We can get the fillet we want, as shown in the figure below, and the small dots are for usp1control point


Style setting

After the above SVG is implemented, the following settings of transparency, background gradient, shadow and border will not be a problem.

Transparent background

path {
  fill: rgba(0,0,0, .3);
  storke: #ffffff;
  storke-width: 1px


svg {
  filter:drop-shadow(2px 4px 6px black)

About whydrop-shadowTo achieve shadow, you can see the figure belowbox-shadowanddrop-shadowThe effect is different,

usebox-shadowWhen our sharp corner has no shadow, the bubble box part has shadow, the situation shown in the following figure will appeardrop-shadowIt can meet our requirements for sharp corners and bubble boxes with shadows.

background gradient

Svg not only supports simple filling, but also supports linear gradient and radial gradient, as well as graphic texture. In order for gradients to be reused, the gradient content needs to be defined inside the label.

As shown in the following figure is a demonstration of radial gradient:

<svg width="120" height="240" version="1.1" xmlns="">
      <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="red"/>
        <stop offset="50%" stop-color="black" stop-opacity="0"/>
        <stop offset="100%" stop-color="blue"/>
  <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>  

After applying this gradient to our prompt box, we can see the effect as shown in the figure below. Finally, we don’t have to work hard to deal with the gradient convergence problem of sharp corners.


Svg also supports texture overlay effect, which can be studied by yourself if you are interested.


The demand is not over

After the above scheme is implemented in the project, it may be that we inadvertently moved the designer. In the recent demand visual draft, we found that the tooltips style involved in it has become more and more amazing. Here are two simple styles:

In the first version, we demonstrated based on demo tool that we have produced the SDK of tooltips, and we used a single parameterarrowHeightPass in to generate sharp corners. It is impossible to cope with the above two styles. The sharp corner style is changeable. How to expand and easy to use has become a problem. It is impossible to develop an SDK for all the changeable sharp corner styles.


Scheme improvement

In order to deal with the changeable bubble corner, we must find a way to pull the sharp angle out of the original bubble outer path, and then integrate it into the bubble to form a complete closed path.

In order to simplify the numerical calculation, I will use the original sharp corner(0,0)The coordinate definition is changed to the point shown below:

So the sharp corner can be designed freely, as long as you can make sure that it is from(0,0)Set off and finally return(-arrowWidth,0)That’s it. Here’s a sharp path:(M 0 0 C -10 0 -8 5 -12 5 S -14 0 -24 0

By designing different sharp paths, we can combine different bubble styles:

The sharp corner bubble on the upper right gives the path string as follows, whereQ -2 7 -9 10 Q -6 5 -7 0This is our sharp path:

M 0 0
Q -2 7 -9 10 Q -6 5 -7 0
H -110
Q -116,0 -116,-6
V -56
Q -116,-62 -110,-62
H 101
Q 107,-62 107,-56
V -6
Q 107,0 101,0
H 0 z

From the short path above, we can see that our sharp corner path is completely integrated in the whole SVG bubble path, so we will not worry about the problem of CSS clip path scheme.


Visualization tools

The solution seems to have solved the sharp corner style in the requirements, but you may say how the sharp path is generated, and does it need to be deduced by strong mathematical ability? The following three Bezier curves have not dared to look directly at, let alone four, five

Therefore, we must produce visualization tools to realize the path generation process. Thanks to the powerful functions of d3.js tool library in SVG operation, we have developed the generation tool address( )As follows:

For those familiar with SVGpathFor example, if you are not familiar with the command below the curve, you can see the difficult operation under the command.



So far inToolTipsThis has basically met the design requirements, but also precipitated the SVG path generation tool. Using SVG to achieveToolTipsCan cover CSSclip-pathSeveral scenarios that can’t be solved perfectly. Thank you for your guidance.


Reference articles

D3 official website( )

Curve: Bezier curve( )

Tooltips using SVG Path( )

Svg gradient( )

Mastering the Bessel curve instruction of SVG path( )

css drop-shadow( )

This article on the use of SVG to achieve the prompt box function of the sample code to introduce this, more related SVG prompt box content, please search the previous articles of developeppaer or continue to browse the related articles below, I hope you will support developeppaer more in the future!

Recommended Today

The selector returned by ngrx store createselector performs one-step debugging of fetching logic

Test source code: import { Component } from ‘@angular/core’; import { createSelector } from ‘@ngrx/store’; export interface State { counter1: number; counter2: number; } export const selectCounter1 = (state: State) => state.counter1; export const selectCounter2 = (state: State) => state.counter2; export const selectTotal = createSelector( selectCounter1, selectCounter2, (counter1, counter2) => counter1 + counter2 ); // […]