{"id":7543,"date":"2025-11-03T11:15:35","date_gmt":"2025-11-03T16:15:35","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=7543"},"modified":"2025-11-03T18:32:19","modified_gmt":"2025-11-03T23:32:19","slug":"perfectly-pointed-tooltips-all-four-sides","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-all-four-sides\/","title":{"rendered":"Perfectly Pointed Tooltips: All Four Sides"},"content":{"rendered":"\n<p>Time for part two! We&#8217;ve got really nice functional positioned tooltips already, but they were mostly concerned with &#8220;pointing&#8221; up or down and shifting at the edges to avoid overflow. Now we&#8217;re going to take it further, considering <strong><em>four<\/em><\/strong> positions without shifts.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-a-foundation\/\">Perfectly Pointed Tooltips: A Foundation<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-all-four-sides\/\">Perfectly Pointed Tooltips: All Four Sides<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-to-the-corners\/\">Perfectly Pointed Tooltips: To The Corners<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<p class=\"learn-more\">At the time of writing, only Chrome and Edge have full support of the features we will be using.<\/p>\n\n\n\n<p>Here is a demo of what we are making:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_QwyMrvG\" src=\"\/\/codepen.io\/anon\/embed\/QwyMrvG?height=600&amp;theme-id=1&amp;slug-hash=QwyMrvG&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed QwyMrvG\" title=\"CodePen Embed QwyMrvG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Drag the anchor and see how the tooltip switches between the four positions and how it remains centered relatively to the anchor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-initial-configuration\">The Initial Configuration<\/h2>\n\n\n\n<p>We are going to use the same code structure as in the first part. We start with the tooltip placed above the anchor (the &#8220;top&#8221;).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">'anchor'<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">'tooltip'<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#anchor<\/span> {\n  <span class=\"hljs-attribute\">anchor-name<\/span>: --anchor;\n}\n<span class=\"hljs-selector-id\">#tooltip<\/span> {\n  <span class=\"hljs-attribute\">--d<\/span>: <span class=\"hljs-number\">1em<\/span>; <span class=\"hljs-comment\">\/* distance between tooltip and anchor *\/<\/span>\n\n  <span class=\"hljs-attribute\">position<\/span>: absolute; \n  <span class=\"hljs-attribute\">position-anchor<\/span>: --anchor;\n  <span class=\"hljs-attribute\">position-area<\/span>: top;\n  <span class=\"hljs-attribute\">bottom<\/span>: <span class=\"hljs-built_in\">var<\/span>(--d);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_YPwEVqm\/3786d23a4038ad465c536ff107f89b40\" src=\"\/\/codepen.io\/anon\/embed\/YPwEVqm\/3786d23a4038ad465c536ff107f89b40?height=650&amp;theme-id=1&amp;slug-hash=YPwEVqm\/3786d23a4038ad465c536ff107f89b40&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed YPwEVqm\/3786d23a4038ad465c536ff107f89b40\" title=\"CodePen Embed YPwEVqm\/3786d23a4038ad465c536ff107f89b40\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>From here on, things will be different from the previous example.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"defining-multiple-positions\">Defining Multiple Positions<\/h2>\n\n\n\n<p>The&nbsp;<code>position-try-fallbacks<\/code>&nbsp;property allows us to define multiple positions. Let\u2019s try the following:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">position-try-fallbacks<\/span>: <span class=\"hljs-selector-tag\">bottom<\/span>, <span class=\"hljs-selector-tag\">left<\/span>, <span class=\"hljs-selector-tag\">right<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Let\u2019s not forget that the placement is related to the containing block, which is the body in our example (illustrated with the dashed border):<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_LEGQXoG\/f008b8ee74788eef7c17daf4851cbb4c\" src=\"\/\/codepen.io\/anon\/embed\/LEGQXoG\/f008b8ee74788eef7c17daf4851cbb4c?height=600&amp;theme-id=1&amp;slug-hash=LEGQXoG\/f008b8ee74788eef7c17daf4851cbb4c&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed LEGQXoG\/f008b8ee74788eef7c17daf4851cbb4c\" title=\"CodePen Embed LEGQXoG\/f008b8ee74788eef7c17daf4851cbb4c\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>We <em>almost<\/em> 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.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"868\" height=\"245\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/7h4aIKLl.png?resize=868%2C245&#038;ssl=1\" alt=\"Illustration showing a tooltip following an anchor, with a crossed-out example on the left and a correct behavior on the right, displaying the text 'Drag the anchor and I should follow...'\" class=\"wp-image-7552\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/7h4aIKLl.png?w=868&amp;ssl=1 868w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/7h4aIKLl.png?resize=300%2C85&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/7h4aIKLl.png?resize=768%2C217&amp;ssl=1 768w\" sizes=\"auto, (max-width: 868px) 100vw, 868px\" \/><\/figure>\n\n\n\n<p>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 \u201cflip\u201d feature.<\/p>\n\n\n\n<p>To move from top to bottom, we use&nbsp;<code>flip-block<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">position-try-fallbacks<\/span>: <span class=\"hljs-selector-tag\">flip-block<\/span>, <span class=\"hljs-selector-tag\">left<\/span>, <span class=\"hljs-selector-tag\">right<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>From top to left, we use&nbsp;<code>flip-start<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">position-try-fallbacks<\/span>: <span class=\"hljs-selector-tag\">flip-block<\/span>, <span class=\"hljs-selector-tag\">flip-start<\/span>, <span class=\"hljs-selector-tag\">right<\/span>; <\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>flip-block<\/code>&nbsp;value mirrors the position across the horizontal axis, and&nbsp;<code>flip-start<\/code>&nbsp;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&nbsp;<code>flip-inline<\/code>&nbsp;that considers the vertical axis to move from left to right.<\/p>\n\n\n\n<p class=\"learn-more\">But how do we move from top to right? We are missing another value, right?<\/p>\n\n\n\n<p>No, we have all the necessary values. To move from top to right, we <em>combine<\/em> two flips:&nbsp;<code>flip-block<\/code>&nbsp;to move to the bottom, then&nbsp;<code>flip-start<\/code>&nbsp;to move to the right:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">position-try-fallbacks<\/span>: <span class=\"hljs-selector-tag\">flip-block<\/span>, <span class=\"hljs-selector-tag\">flip-start<\/span>, <span class=\"hljs-selector-tag\">flip-block<\/span> <span class=\"hljs-selector-tag\">flip-start<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Or&nbsp;<code>flip-start<\/code>&nbsp;to move to the left, and then&nbsp;<code>flip-inline<\/code>&nbsp;to move to the right:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">position-try-fallbacks<\/span>: <span class=\"hljs-selector-tag\">flip-block<\/span>, <span class=\"hljs-selector-tag\">flip-start<\/span>, <span class=\"hljs-selector-tag\">flip-start<\/span> <span class=\"hljs-selector-tag\">flip-inline<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_ZYQxKjy\/d9b8e34dd58a044957b40a251b0fc415\" src=\"\/\/codepen.io\/anon\/embed\/ZYQxKjy\/d9b8e34dd58a044957b40a251b0fc415?height=650&amp;theme-id=1&amp;slug-hash=ZYQxKjy\/d9b8e34dd58a044957b40a251b0fc415&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed ZYQxKjy\/d9b8e34dd58a044957b40a251b0fc415\" title=\"CodePen Embed ZYQxKjy\/d9b8e34dd58a044957b40a251b0fc415\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>It should be noted that all the flips consider the initial position defined on the element and not the previous position defined on&nbsp;<code>position-try-fallbacks<\/code>&nbsp;or the current position. If we first perform a&nbsp;<code>flip-block<\/code>&nbsp;to move to the bottom, the&nbsp;<code>flip-start<\/code>&nbsp;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.<\/p>\n\n\n\n<p>Said differently, the browser will first transform all the flips into positions (considering the initial position) and then pick the suitable one when needed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"disabling-the-shift-behavior\">Disabling the Shift Behavior<\/h2>\n\n\n\n<p>What we have is actually good and might work perfectly for some use-cases, but we&#8217;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\u2019t want to have the \u201cshift\u201d behavior. I want the tooltip to remain always centered relatively to the anchor.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"897\" height=\"320\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/SSD0LZHO.png?resize=897%2C320&#038;ssl=1\" alt=\"Image showing four tooltip positions in relation to an anchor, with text indicating interaction.\" class=\"wp-image-7553\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/SSD0LZHO.png?w=897&amp;ssl=1 897w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/SSD0LZHO.png?resize=300%2C107&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/SSD0LZHO.png?resize=768%2C274&amp;ssl=1 768w\" sizes=\"auto, (max-width: 897px) 100vw, 897px\" \/><\/figure>\n\n\n\n<p>For this, we can use:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">justify-self<\/span>: <span class=\"hljs-selector-tag\">unsafe<\/span> <span class=\"hljs-selector-tag\">anchor-center<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"learn-more\">What is this strange value!?<\/p>\n\n\n\n<p>After defining the position of an element using&nbsp;<code>position-area<\/code>&nbsp;we can also control its alignment using&nbsp;<code>justify-self<\/code>&nbsp;and&nbsp;<code>align-self<\/code>&nbsp;(or the shorthand&nbsp;<code>place-self<\/code>). However, we get a default alignment that you rarely need to change.<\/p>\n\n\n\n<p>For&nbsp;<code>position-area: top<\/code>, the default alignment is equivalent to&nbsp;<code>justify-self: anchor-center<\/code>&nbsp;and&nbsp;<code>align-self: end<\/code>.<\/p>\n\n\n\n<p class=\"learn-more\">Don\u2019t we have a <code>center<\/code> value? Why is it called <code>anchor-center<\/code>?<\/p>\n\n\n\n<p>The&nbsp;<code>center<\/code>&nbsp;value exists, but its behavior is different from&nbsp;<code>anchor-center<\/code>.&nbsp;The <code>center<\/code> value&nbsp;considers the center of the area, while&nbsp;<code>anchor-center<\/code>&nbsp;considers the center of the anchor in the relevant axis.<\/p>\n\n\n\n<p>Here is a screenshot taken from&nbsp;<a href=\"https:\/\/css-tip.com\/position-area\/\">my interactive demo<\/a>, where you can see the difference:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"489\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/nrJHmtpZ-1.png?resize=975%2C489&#038;ssl=1\" alt=\"Comparison of element alignment in CSS, showing the difference between centering in the top area versus centering at the anchor point.\" class=\"wp-image-7555\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/nrJHmtpZ-1.png?w=975&amp;ssl=1 975w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/nrJHmtpZ-1.png?resize=300%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/nrJHmtpZ-1.png?resize=768%2C385&amp;ssl=1 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><\/figure>\n\n\n\n<p>In addition to that,&nbsp;<code>anchor-center<\/code>&nbsp;follows the logic of&nbsp;<a href=\"https:\/\/css-tip.com\/safe-align\/\">safe alignment<\/a>&nbsp;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 \u201cunsafe\u201d behavior hence the use of:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">justify-self<\/span>: <span class=\"hljs-selector-tag\">unsafe<\/span> <span class=\"hljs-selector-tag\">anchor-center<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>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.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_Wbrzjjb\/159e2f67a7a6e2b14bacec4fc4f45591\" src=\"\/\/codepen.io\/anon\/embed\/Wbrzjjb\/159e2f67a7a6e2b14bacec4fc4f45591?height=600&amp;theme-id=1&amp;slug-hash=Wbrzjjb\/159e2f67a7a6e2b14bacec4fc4f45591&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed Wbrzjjb\/159e2f67a7a6e2b14bacec4fc4f45591\" title=\"CodePen Embed Wbrzjjb\/159e2f67a7a6e2b14bacec4fc4f45591\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And if we add back the left and right positions to the fallbacks, the browser will use them instead of overflowing!<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_VYeXbVg\/02b211bba024d28a17e5ea15846080bc\" src=\"\/\/codepen.io\/anon\/embed\/VYeXbVg\/02b211bba024d28a17e5ea15846080bc?height=600&amp;theme-id=1&amp;slug-hash=VYeXbVg\/02b211bba024d28a17e5ea15846080bc&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed VYeXbVg\/02b211bba024d28a17e5ea15846080bc\" title=\"CodePen Embed VYeXbVg\/02b211bba024d28a17e5ea15846080bc\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>It should be noted that&nbsp;<code>justify-self<\/code>&nbsp;is also included in the flip. It\u2019s one of those properties that the browser changes when flipping. When the position is top or bottom, it remains&nbsp;<code>justify-self<\/code>, but when the position is left or right, it becomes&nbsp;<code>align-self<\/code>. Another reason why it\u2019s better to consider the flip feature instead of explicitly defining a position.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"adding-min-width\">Adding min-width<\/h2>\n\n\n\n<p>The position of the tooltip is now good, but in some particular cases, it\u2019s too narrow.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"295\" height=\"234\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/avEUiDCW.png?resize=295%2C234&#038;ssl=1\" alt=\"A tooltip with a blue background displaying the text 'Drag the anchor and I should follow...' is positioned above a gray anchor icon.\" class=\"wp-image-7556\"\/><\/figure>\n\n\n\n<p>That\u2019s 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&#8217;d like to add&nbsp;<code>min-width<\/code>&nbsp;to force it to flip to another position before shrinking too much. It can also be a&nbsp;<code>max-height<\/code>&nbsp;as well.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_vELRZKB\/d7845171d64b9390b7a6af08af748512\" src=\"\/\/codepen.io\/anon\/embed\/vELRZKB\/d7845171d64b9390b7a6af08af748512?height=650&amp;theme-id=1&amp;slug-hash=vELRZKB\/d7845171d64b9390b7a6af08af748512&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed vELRZKB\/d7845171d64b9390b7a6af08af748512\" title=\"CodePen Embed vELRZKB\/d7845171d64b9390b7a6af08af748512\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Oops,&nbsp;<code>min-width<\/code>&nbsp;is not preventing wrapping, but it is increasing the height! What?!<\/p>\n\n\n\n<p>Can you guess what the issue is? Think a moment about it.<\/p>\n\n\n\n<p>It\u2019s the flip behavior.<\/p>\n\n\n\n<p>The <code>min-width<\/code>&nbsp;and all the sizing properties are also affected by the flip. The initial configuration is top, so defining&nbsp;<code>min-width<\/code>&nbsp;means that when we perform a flip-start to move to the left or the right position, the&nbsp;<code>min-width<\/code>&nbsp;becomes&nbsp;<code>min-height<\/code>, which is not good.<\/p>\n\n\n\n<p class=\"learn-more\">So we define <code>min-height<\/code> instead, when flipped it becomes <code>min-width<\/code>!<\/p>\n\n\n\n<p>Yes, but the&nbsp;<code>min-height<\/code>&nbsp;will apply to the top and bottom positions, which is not ideal either.<\/p>\n\n\n\n<p>We can fix this by using custom positions where we define all the properties manually.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#tooltip<\/span> {\n  <span class=\"hljs-attribute\">min-width<\/span>: <span class=\"hljs-number\">10em<\/span>;\n\n  <span class=\"hljs-attribute\">position-area<\/span>: top;\n  <span class=\"hljs-attribute\">justify-self<\/span>: unsafe anchor-center;\n  <span class=\"hljs-attribute\">bottom<\/span>: <span class=\"hljs-built_in\">var<\/span>(--d);\n  <span class=\"hljs-attribute\">position-try-fallbacks<\/span>: flip-block,--left,--right;\n}\n<span class=\"hljs-keyword\">@position-try<\/span> --left {\n  <span class=\"hljs-selector-tag\">position-area<\/span>: <span class=\"hljs-selector-tag\">left<\/span>;\n  <span class=\"hljs-selector-tag\">justify-self<\/span>: <span class=\"hljs-selector-tag\">normal<\/span>;\n  <span class=\"hljs-selector-tag\">align-self<\/span>: <span class=\"hljs-selector-tag\">unsafe<\/span> <span class=\"hljs-selector-tag\">anchor-center<\/span>;\n  <span class=\"hljs-selector-tag\">right<\/span>: <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--d<\/span>);\n}\n<span class=\"hljs-keyword\">@position-try<\/span> --right {\n  <span class=\"hljs-selector-tag\">position-area<\/span>: <span class=\"hljs-selector-tag\">right<\/span>;\n  <span class=\"hljs-selector-tag\">justify-self<\/span>: <span class=\"hljs-selector-tag\">normal<\/span>;\n  <span class=\"hljs-selector-tag\">align-self<\/span>: <span class=\"hljs-selector-tag\">unsafe<\/span> <span class=\"hljs-selector-tag\">anchor-center<\/span>;\n  <span class=\"hljs-selector-tag\">left<\/span>: <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--d<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We use&nbsp;<code>@position-try<\/code>&nbsp;to create a custom position with a given name, and inside it we define all the properties. Instead of using&nbsp;<code>flip-start<\/code>&nbsp;to set the left position, I define a custom&nbsp;<code>--left<\/code>&nbsp;position with all the necessary properties to correctly place the tooltip on the left. Same for the right position. In this situation,&nbsp;<code>min-width<\/code>&nbsp;is preserved for all positions, as we are no longer using&nbsp;<code>flip-start<\/code>.<\/p>\n\n\n\n<p>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&nbsp;<code>justify-self: normal<\/code>&nbsp;to override&nbsp;<code>justify-self: unsafe anchor-center<\/code>.&nbsp;<code>normal<\/code>&nbsp;being the default value of&nbsp;<code>justify-self<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_MYKGWZX\/38a52cdc861f42c2304930dd7edea196\" src=\"\/\/codepen.io\/anon\/embed\/MYKGWZX\/38a52cdc861f42c2304930dd7edea196?height=600&amp;theme-id=1&amp;slug-hash=MYKGWZX\/38a52cdc861f42c2304930dd7edea196&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed MYKGWZX\/38a52cdc861f42c2304930dd7edea196\" title=\"CodePen Embed MYKGWZX\/38a52cdc861f42c2304930dd7edea196\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>While this solution works fine, it\u2019s a bit verbose, so I was wondering if we can do better. It turns out we can!<\/p>\n\n\n\n<p>We can combine the flip feature and custom positions to get a shorter code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#tooltip<\/span> {\n  <span class=\"hljs-attribute\">position-area<\/span>: top;\n  <span class=\"hljs-attribute\">justify-self<\/span>: unsafe anchor-center;\n  <span class=\"hljs-attribute\">bottom<\/span>: <span class=\"hljs-built_in\">var<\/span>(--d);\n  <span class=\"hljs-attribute\">position-try<\/span>: flip-block,--size flip-start,--size flip-start flip-inline;\n}\n<span class=\"hljs-keyword\">@position-try<\/span> --size {\n  <span class=\"hljs-selector-tag\">min-height<\/span>: 12<span class=\"hljs-selector-tag\">em<\/span>; <span class=\"hljs-comment\">\/* this is min-width! *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>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&nbsp;<code>--size flip-start<\/code>&nbsp;will flip the properties defined on the element and the one defined in the custom position&nbsp;<code>--size<\/code>.&nbsp;<code>min-height<\/code>&nbsp;becomes a&nbsp;<code>min-width<\/code>! Clever, right?<\/p>\n\n\n\n<p class=\"learn-more\">But you said we cannot use <code>min-height<\/code>?<\/p>\n\n\n\n<p>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\u2019t need any&nbsp;<code>min-width<\/code>&nbsp;or&nbsp;<code>min-height<\/code>&nbsp;constraint when the position is top or bottom.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qEbYBge\/3c340988dad465c415beb2f57778f6bb\" src=\"\/\/codepen.io\/anon\/embed\/qEbYBge\/3c340988dad465c415beb2f57778f6bb?height=650&amp;theme-id=1&amp;slug-hash=qEbYBge\/3c340988dad465c415beb2f57778f6bb&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qEbYBge\/3c340988dad465c415beb2f57778f6bb\" title=\"CodePen Embed qEbYBge\/3c340988dad465c415beb2f57778f6bb\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Now our tooltip position is perfect! Let\u2019s add the tail.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"adding-the-tail\">Adding The Tail<\/h2>\n\n\n\n<p>First, we create a shape that contains the 4 tails.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"711\" height=\"219\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/LisUyvsg.png?resize=711%2C219&#038;ssl=1\" alt=\"Comparison of tooltip shapes demonstrating the transition from a red diamond shape to a blue rounded shape with the text 'Drag the anchor and I should follow...'\" class=\"wp-image-7557\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/LisUyvsg.png?w=711&amp;ssl=1 711w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/LisUyvsg.png?resize=300%2C92&amp;ssl=1 300w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/figure>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#tooltip<\/span><span class=\"hljs-selector-pseudo\">:before<\/span> {\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-string\">\"\"<\/span>;\n  <span class=\"hljs-attribute\">position<\/span>: absolute;\n  <span class=\"hljs-attribute\">z-index<\/span>: -<span class=\"hljs-number\">1<\/span>;\n  <span class=\"hljs-attribute\">inset<\/span>: <span class=\"hljs-built_in\">calc<\/span>(-<span class=\"hljs-number\">1<\/span>*var(--d));\n  <span class=\"hljs-attribute\">clip-path<\/span>: <span class=\"hljs-built_in\">polygon<\/span>(\n    calc(<span class=\"hljs-number\">50%<\/span> - var(--s)) <span class=\"hljs-built_in\">var<\/span>(--d),<span class=\"hljs-number\">50%<\/span> .<span class=\"hljs-number\">2em<\/span>,<span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> + var(--s)) <span class=\"hljs-built_in\">var<\/span>(--d),\n    <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - var(--d)) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> - var(--s)), <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - .<span class=\"hljs-number\">2em<\/span>) <span class=\"hljs-number\">50%<\/span>,<span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - var(--d)) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> + var(--s)),\n    <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> + var(--s)) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - var(--d)),<span class=\"hljs-number\">50%<\/span> <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - .<span class=\"hljs-number\">2em<\/span>),<span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> - var(--s)) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100%<\/span> - var(--d)),\n    <span class=\"hljs-built_in\">var<\/span>(--d) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> + var(--s)), .<span class=\"hljs-number\">2em<\/span> <span class=\"hljs-number\">50%<\/span>,<span class=\"hljs-built_in\">var<\/span>(--d) <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">50%<\/span> - var(--s))\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>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:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">margin<\/span>: <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--d<\/span>);\n<span class=\"hljs-selector-tag\">margin-bottom<\/span>: 0;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"681\" height=\"193\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/RZRmCs40.png?resize=681%2C193&#038;ssl=1\" alt=\"Comparison of tooltip designs showing a red diamond-shaped tooltip on the left and a blue rectangular tooltip on the right, both displaying the text 'Drag the anchor and I should follow...'.\" class=\"wp-image-7558\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/RZRmCs40.png?w=681&amp;ssl=1 681w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/RZRmCs40.png?resize=300%2C85&amp;ssl=1 300w\" sizes=\"auto, (max-width: 681px) 100vw, 681px\" \/><\/figure>\n\n\n\n<p>And for the other sides, we do nothing! The flip will do the job for us.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_QwyMrvG\" src=\"\/\/codepen.io\/anon\/embed\/QwyMrvG?height=600&amp;theme-id=1&amp;slug-hash=QwyMrvG&amp;default-tab=result\" height=\"600\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed QwyMrvG\" title=\"CodePen Embed QwyMrvG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Toggle the \u201cdebug mode\u201d to see how the shape behaves in each position.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>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.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-a-foundation\/\">Perfectly Pointed Tooltips: A Foundation<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-all-four-sides\/\">Perfectly Pointed Tooltips: All Four Sides<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/perfectly-pointed-tooltips-to-the-corners\/\">Perfectly Pointed Tooltips: To The Corners<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Tooltips are a natural fit for the abilities of Anchor Positioning, which can help place them on *any* side or corner. It does make dealing with the pointer extra tricky though.<\/p>\n","protected":false},"author":12,"featured_media":7563,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[121,7,417],"class_list":["post-7543","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-anchor","tag-css","tag-tooltips"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/10\/Perfectly-Pointed-Tooltips_-A-Foundation-2-1.jpg?fit=1140%2C676&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7543","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=7543"}],"version-history":[{"count":9,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7543\/revisions"}],"predecessor-version":[{"id":7691,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7543\/revisions\/7691"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/7563"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=7543"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=7543"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=7543"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}