Time for part two! We’ve got really nice functional positioned tooltips already, but they were mostly concerned with “pointing” up or down and shifting at the edges to avoid overflow. Now we’re going to take it further, considering four positions without shifts.
At the time of writing, only Chrome and Edge have full support of the features we will be using.
Here is a demo of what we are making:
Drag the anchor and see how the tooltip switches between the four positions and how it remains centered relatively to the anchor.
The Initial Configuration
We are going to use the same code structure as in the first part. We start with the tooltip placed above the anchor (the “top”).
<div id='anchor'></div>
<div id='tooltip'></div>Code language: HTML, XML (xml)
#anchor {
  anchor-name: --anchor;
}
#tooltip {
  --d: 1em; /* distance between tooltip and anchor */
  position: absolute; 
  position-anchor: --anchor;
  position-area: top;
  bottom: var(--d);
}Code language: CSS (css)
From here on, things will be different from the previous example.
Defining Multiple Positions
The position-try-fallbacks property allows us to define multiple positions. Let’s try the following:
position-try-fallbacks: bottom, left, right;Code language: CSS (css)
Let’s not forget that the placement is related to the containing block, which is the body in our example (illustrated with the dashed border):
We almost have the same behavior as the first example; however if you are close to the right or left edges, you get the new positions. Instead of overflowing, the browser will swap to the right or left position.

Similar to the first example, the gap disappears when switching to the fallback positions. We know how to fix it! Instead of explicitly defining the positions, we can rely on the “flip” feature.
To move from top to bottom, we use flip-block:
position-try-fallbacks: flip-block, left, right;Code language: CSS (css)
From top to left, we use flip-start:
position-try-fallbacks: flip-block, flip-start, right; Code language: CSS (css)
The flip-block value mirrors the position across the horizontal axis, and flip-start does the same across the diagonal. With this value, we can move from top to left and from bottom to right. And logically, we also have a flip-inline that considers the vertical axis to move from left to right.
But how do we move from top to right? We are missing another value, right?
No, we have all the necessary values. To move from top to right, we combine two flips: flip-block to move to the bottom, then flip-start to move to the right:
position-try-fallbacks: flip-block, flip-start, flip-block flip-start;Code language: CSS (css)
Or flip-start to move to the left, and then flip-inline to move to the right:
position-try-fallbacks: flip-block, flip-start, flip-start flip-inline;Code language: CSS (css)
It should be noted that all the flips consider the initial position defined on the element and not the previous position defined on position-try-fallbacks or the current position. If we first perform a flip-block to move to the bottom, the flip-start of the second position will not consider the bottom position but the top position (the initial one). This can be confusing, especially when you have many positions.
Said differently, the browser will first transform all the flips into positions (considering the initial position) and then pick the suitable one when needed.
Disabling the Shift Behavior
What we have is actually good and might work perfectly for some use-cases, but we’re aiming for slightly more advanced functionality. What we want is to flip to the left or right position as soon as the tooltip touches the edges. We don’t want to have the “shift” behavior. I want the tooltip to remain always centered relatively to the anchor.

For this, we can use:
justify-self: unsafe anchor-center;Code language: CSS (css)
What is this strange value!?
After defining the position of an element using position-area we can also control its alignment using justify-self and align-self (or the shorthand place-self). However, we get a default alignment that you rarely need to change.
For position-area: top, the default alignment is equivalent to justify-self: anchor-center and align-self: end.
Don’t we have a center value? Why is it called anchor-center?
The center value exists, but its behavior is different from anchor-center. The center value considers the center of the area, while anchor-center considers the center of the anchor in the relevant axis.
Here is a screenshot taken from my interactive demo, where you can see the difference:

In addition to that, anchor-center follows the logic of safe alignment which cause the shift behavior. When there is not enough room for centering, the element will shift to remain within the containing block area. To disable this, we tell the browser to consider an “unsafe” behavior hence the use of:
justify-self: unsafe anchor-center;Code language: CSS (css)
Here is a demo with only the top and bottom positions. Notice how the tooltip will overflow from the left and right sides instead of shifting.
And if we add back the left and right positions to the fallbacks, the browser will use them instead of overflowing!
It should be noted that justify-self is also included in the flip. It’s one of those properties that the browser changes when flipping. When the position is top or bottom, it remains justify-self, but when the position is left or right, it becomes align-self. Another reason why it’s better to consider the flip feature instead of explicitly defining a position.
Adding min-width
The position of the tooltip is now good, but in some particular cases, it’s too narrow.

That’s a logical behavior since the text inside can wrap to make the tooltip fit that position. You probably want to keep that behavior, but in our case, we’d like to add min-width to force it to flip to another position before shrinking too much. It can also be a max-height as well.
Oops, min-width is not preventing wrapping, but it is increasing the height! What?!
Can you guess what the issue is? Think a moment about it.
It’s the flip behavior.
The min-width and all the sizing properties are also affected by the flip. The initial configuration is top, so defining min-width means that when we perform a flip-start to move to the left or the right position, the min-width becomes min-height, which is not good.
So we define min-height instead, when flipped it becomes min-width!
Yes, but the min-height will apply to the top and bottom positions, which is not ideal either.
We can fix this by using custom positions where we define all the properties manually.
#tooltip {
  min-width: 10em;
  position-area: top;
  justify-self: unsafe anchor-center;
  bottom: var(--d);
  position-try-fallbacks: flip-block,--left,--right;
}
@position-try --left {
  position-area: left;
  justify-self: normal;
  align-self: unsafe anchor-center;
  right: var(--d);
}
@position-try --right {
  position-area: right;
  justify-self: normal;
  align-self: unsafe anchor-center;
  left: var(--d);
}Code language: CSS (css)
We use @position-try to create a custom position with a given name, and inside it we define all the properties. Instead of using flip-start to set the left position, I define a custom --left position with all the necessary properties to correctly place the tooltip on the left. Same for the right position. In this situation, min-width is preserved for all positions, as we are no longer using flip-start.
It is worth noting that when using a custom position, you need to ensure that you override all the properties of the initial position defined on the element otherwise they still apply. For this reason, I am defining justify-self: normal to override justify-self: unsafe anchor-center. normal being the default value of justify-self.
While this solution works fine, it’s a bit verbose, so I was wondering if we can do better. It turns out we can!
We can combine the flip feature and custom positions to get a shorter code:
#tooltip {
  position-area: top;
  justify-self: unsafe anchor-center;
  bottom: var(--d);
  position-try: flip-block,--size flip-start,--size flip-start flip-inline;
}
@position-try --size {
  min-height: 12em; /* this is min-width! */
}Code language: CSS (css)
When we define a custom position with a flip, the browser selects the properties within the custom position, as well as the properties already defined on the element, and then performs the flip. So --size flip-start will flip the properties defined on the element and the one defined in the custom position --size. min-height becomes a min-width! Clever, right?
But you said we cannot use min-height?
We cannot use it on the main element as it will apply to the top and bottom positions. However, within a custom position, I can select where it applies, and I want it to apply only to the left and right positions. Plus, I don’t need any min-width or min-height constraint when the position is top or bottom.
Now our tooltip position is perfect! Let’s add the tail.
Adding The Tail
First, we create a shape that contains the 4 tails.

#tooltip:before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: calc(-1*var(--d));
  clip-path: polygon(
    calc(50% - var(--s)) var(--d),50% .2em,calc(50% + var(--s)) var(--d),
    calc(100% - var(--d)) calc(50% - var(--s)), calc(100% - .2em) 50%,calc(100% - var(--d)) calc(50% + var(--s)),
    calc(50% + var(--s)) calc(100% - var(--d)),50% calc(100% - .2em),calc(50% - var(--s)) calc(100% - var(--d)),
    var(--d) calc(50% + var(--s)), .2em 50%,var(--d) calc(50% - var(--s))
  );
}Code language: CSS (css)
Then we control it using margin on the tooltip element, just as we did in the first part. When the position is top, we add a margin to all the sides except for the bottom one:
margin: var(--d);
margin-bottom: 0;Code language: CSS (css)

And for the other sides, we do nothing! The flip will do the job for us.
Toggle the “debug mode” to see how the shape behaves in each position.
Conclusion
We have completed the second part. Now, you should be comfortable working with fallbacks, the flip feature, and custom positions. If you are still struggling, give the article another read. We still have one final challenge, so make sure everything is clear before moving to the next article.
