Tooltips are like homemade dishes. Everyone uses tooltips and everyone has their own recipe. If you don’t remember a particular recipe, you’ll search for the recipe, follow it, and move on with your day. This concept of “different ways to do the same thing” is common in web development and programming (and life!), but it’s especially true for tooltips. There is no special way to create them, and there is currently no need for one. So people come up with different ways to fill those gaps.
Today I want to focus on just one step of the recipe. For lack of a better name, we’ll call it the little tooltip triangle. This is one of those things that doesn’t get a lot of attention (admittedly, I didn’t know much about it until I wrote this), but it’s amazing how many ways to make it. Let’s start with the simplest and move on to the less simple ones.
Ideally, the tooltip is just one element. I don’t want to mess up the markup just for that little triangle.
I’m a tooltip
wise boundaries
Before you can run, you must learn to walk. And before we can connect those little triangles, we have to learn how to make triangles. Perhaps the most widespread recipe for triangles is the border trick. You can also see this in the 2010 Stack Overflow issue and here by Chris in 2016.
Simply put, borders intersect each other at 45 degree angles, so if an element has a border but no width and height, the borders form four complete triangles. All that remains is to set the three border colors to transparent so that only one triangle is visible. You can find an animated version on this CodePen by Chris Coyier.
CodePen embed fallback
Usually the small triangle will be a pseudo-element in the tooltip, so set its dimensions to 0px (this is already done in ::before and ::after) and set only one of the borders to solid color. Must be. You can control the size of the base of the triangle by making the other borders wider, and you can control the height by making the visible border larger.
.tooltip { &::before { Contents: “”;Border width: var(–triangle-base);Border style: Solid;Border color: Transparent; border-top: var(–triangle-height) Red Isshiki; } }
Attaching a triangle to a tooltip is an art in itself, so follow the basics and set the position of the small triangle to absolute, set the .tooltip to relative, then adjust its inset property to place it where you want it. I will. The only thing to note is that you need to move the small triangle to account for its width. -50% if you set the position with the left property, 50% if you use the right property.
.tooltip { position: relative; &::before { /* … */ position: absolute; top: var(–triangle-top); left: var(–triangle-left); transform: transform X( -50%); } }
However, you can also use the new anchor position property for tasks. Whichever method you choose, you should see a small triangle in the tooltip.
CodePen embed fallback
rotated square
One disadvantage of the last example is that it blocks the boundary property, so if you ever need it for other purposes, you’re out of luck. However, there is another old-fashioned way to create that little triangle. Rotate the square 45 degrees and hide half of it behind the body of the tooltip. This way only the corners will be displayed in the triangle. You can create squares from pseudo-elements.
.tooltip { &::before { Content: “”;Display: Block;Height: var(–triangle-size);Width: var(–triangle-size);Background color: Red; } }
Then place it behind the body of the tooltip. In this case, only half will be visible. Since the square is rotated, the transformation is on both axes.
.tooltip { position: relative; &::before { /* … */ position: absolute; top: 75%; left: 50%. z index: -1; /* So it’s behind the body of the tooltip */transform:translateX(-50%);Transform: Rotate (45 degrees) Translate Y(25%) Translate X(-50% ); } }
CodePen embed fallback
I also found that this method works better with anchor placement, since I don’t have to change the style every time I move a small triangle. This is different from the border method, where the displayed border changes depending on the direction.
CodePen embed fallback
Crop a square with a clip path
I didn’t mention it before, but you may have noticed that there are some issues with the last approach. First, this isn’t exactly a triangle, so it’s not the most reliable take. If the tooltip is too short, the square can be hidden at the top, and moving the fake triangle to the side reveals its true square nature. Both problems can be solved using the clip-path property.
The Clip-path property allows you to select an area of an element and display it while clipping the rest. This works by specifying the path you want to trim. Since we need a triangle from a square, we can use the polygon() function. Get points within an element and trim them with a straight line. Points can be written as a percentage from the origin (i.e. top left corner) and in this case we want to crop three points: 0% 0% (top left corner), 100% 0% (top right corner). corner) and 50% 100% (bottom center point).
So the clip path value will be a Polygon() function with these three points in a comma-separated list.
.tooltip { &::before { Contents: “”;Width: var(–triangle-base);Height: var(–triangle-height);Clip path: Polygon(0% 0%, 100% 0% , 50% 100%);Conversion: Conversion(-50%);Background color: Red; } }
This time we will set the top and left properties using CSS variables that will be useful later.
.tooltip { position: relative; &::before { /* … */ position: absolute; top: var(–triangle-top); /* 100% */ left: var(–triangle-left) ; /* 50% */ Conversion: Conversion(-50%); } }
You should now have a true little triangle attached to your tooltip.
CodePen embed fallback
However, if you bring the small triangle to the end of either side, you can see how it slides out of the body of the tooltip. Fortunately, the clip-path property gives us better control over the shape of the triangle. In this case, depending on the horizontal position of the small triangle, you can change the point through which the trim passes. For the top-left corner, the horizontal value should approach 50% as the tooltip position approaches 0%, and the top-right corner should approach 50% as the tooltip position approaches 100%.
The following min() + max() combination does just that.
.tooltip { clip path: polygon( max(50% – var(–triangle-left), 0%) 0, min(150% – var(–triangle-left), 100%) 0%, 50% 100 %); }
The calc() function is not needed inside math functions such as min() and max().
Move the tooltip to see how the shape changes depending on its position on the horizontal axis.
CodePen embed fallback
Using the border-image property
It may seem that the last little triangle is the ultimate triangle. However, if you’re already using both pseudo-elements and can’t spare one for a small triangle, or simply want a more elegant way to do it without using pseudo-elements. Imagine the situation. Although this task may seem impossible, there are two properties available for this task: the clip path and border image properties that are already visible.
The clip path property allows you to trim the shape of the tooltip to include a small triangle. — taken directly from the element. The problem is that the background of the element is not large enough to account for the small triangle. However, you can create a lush background using the border-image property. The syntax is a bit complicated, so I recommend reading more about border-image by Temani Afif. This means you can now use an image or CSS gradient as an element border. In this case, we are creating a border with a solid color that is the same width as the height of the triangle.
.tooltip { border-image: fill 0 // var(–triangle-height) conic-gradient(red 0 0);; }
This time the trim will be a little more complicated. We will also be trimming smaller triangles, so we will need more points. Specifically, there are seven points below.
This will be converted to the following clip path value:
.tooltip { /* … */ Clip path: polygon( 0% 100%, 0% 0%, 100% 0%, 100% 100%, calc(50% + var(–triangle-base) / 2 ) 100%, 50% calc(100% + var(–triangle-height)), calc(50% – var(–triangle-base) / 2) 100% ); }
You can do a smart rotation by capping the bottom point of a small triangle every time you pass either side of the tooltip.
.tooltip { /* … */ Clip path: polygon( 0% 100%, 0% 0%, 100% 0%, 100% 100%, min(var(–triangle-left) + var(- – triangle-base) / 2, 100%) 100%, var(–triangle-left) calc(100% + var(–triangle-height)), max(var(–triangle-left) – var(–triangle-base) / 2, 0%) 100%;
The last little triangle in the tooltip is now complete. This is part of the body and uses only one element.
CodePen embed fallback