{"id":5796,"date":"2025-05-13T11:26:46","date_gmt":"2025-05-13T16:26:46","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=5796"},"modified":"2025-05-13T11:26:47","modified_gmt":"2025-05-13T16:26:47","slug":"container-query-for-is-there-enough-space-outside-this-element","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/container-query-for-is-there-enough-space-outside-this-element\/","title":{"rendered":"Container Query for &#8220;is there enough space outside this element?&#8221;"},"content":{"rendered":"\n<p>Say you had a UI component that had pagination arrows for whatever reason. If there was enough space on the outside of that component, you wanted to put those arrows <em>outside<\/em>, like this this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"647\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=1024%2C647&#038;ssl=1\" alt=\"\" class=\"wp-image-5798\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=1024%2C647&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=300%2C190&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=768%2C485&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=1536%2C970&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.55%E2%80%AFPM.png?resize=2048%2C1294&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>But if there isn&#8217;t enough room for them without shrinking the main content area, then place them <em>inside<\/em>, like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"977\" height=\"1024\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.59%E2%80%AFPM.png?resize=977%2C1024&#038;ssl=1\" alt=\"\" class=\"wp-image-5799\" style=\"width:500px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.59%E2%80%AFPM.png?resize=977%2C1024&amp;ssl=1 977w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.59%E2%80%AFPM.png?resize=286%2C300&amp;ssl=1 286w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.59%E2%80%AFPM.png?resize=768%2C805&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-06-at-2.25.59%E2%80%AFPM.png?w=1410&amp;ssl=1 1410w\" sizes=\"auto, (max-width: 977px) 100vw, 977px\" \/><\/figure>\n<\/div>\n\n\n<p>You could do that with plenty of magic numbers, especially in how big the main content area is. But wouldn&#8217;t it be cool if you didn&#8217;t have to know? Like the main content area could be whatever, fluid\/responsive\/flexible, and you could still test if there is &#8220;room&#8221; outside for the arrows or not.<\/p>\n\n\n\n<p class=\"learn-more\">I was playing with this trick because I remember Adam Argyle talking about it one time, but couldn&#8217;t find where he used it. So I wrote this article up to re-learn and document it. <a href=\"https:\/\/nerdy.dev\/carousel-adaptive-anchor-positioning-with-calc-in-a-container-query\">Then of course I find the original article.<\/a> So full credit to Adam here. Mine approach here is super similar of course. I think I prefer how his <code>@container<\/code> query uses <code>cqi<\/code> units inside of it in case the parent isn&#8217;t the viewport. Clever.<\/p>\n\n\n\n<p>The trick is in combining viewport units within a container query. You could probably do it by using container units within a media query too, but we&#8217;ll go with the former because I tried it and it worked.<\/p>\n\n\n\n<p>We&#8217;re going to need a &#8220;wrapper&#8221; element because that&#8217;s just how <code>@container<\/code> queries tend to be most useful. You can&#8217;t query the same element that is the container, so easier if the container is a wrapper. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">&lt;div <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span><\/span>=<span class=\"hljs-string\">\"box\"<\/span>&gt;\n  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"box-inner\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"arrow arrow-left\"<\/span>&gt;<\/span>\n       <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">svg<\/span> <span class=\"hljs-attr\">...<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">svg<\/span>&gt;<\/span>\n    <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\">class<\/span>=<span class=\"hljs-string\">\"arrow arrow-right\"<\/span>&gt;<\/span>\n       <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">svg<\/span> <span class=\"hljs-attr\">...<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">svg<\/span>&gt;<\/span>\n  <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>&gt;<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The box will be the container:<\/p>\n\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-class\">.box<\/span> {\n  <span class=\"hljs-attribute\">container<\/span>: box \/ inline-size;\n  <span class=\"hljs-attribute\">inline-size<\/span>: <span class=\"hljs-built_in\">min<\/span>(<span class=\"hljs-number\">500px<\/span>, <span class=\"hljs-number\">100vw<\/span>);\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<p>I love using that second declaration, which says: &#8220;Make the element 500px wide, but if the entire browser window is smaller than that, do that instead.&#8221; That element is the container.<\/p>\n\n\n\n<p>Then we can use a <code>@container<\/code> query on the inside. If we wanted to make a style change <em>exactly<\/em> when the container is the same size as the browser window, we could do this:<\/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-class\">.box-inner<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: rebeccapurple;\n  ...\n\n  @container box (inline-size &gt;= 100vw) {\n    <span class=\"hljs-attribute\">background<\/span>: red;\n  }\n}<\/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>That will do this!<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='363' src='https:\/\/videopress.com\/embed\/PGI6aImQ?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1739540970'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>But we&#8217;re actually dealing with the arrows here, so what we want to know is &#8220;is there enough space outside for them?&#8221; Meaning not the <em>exact<\/em> size of the element, but that:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Element &lt;= Viewport - Arrows - Gap<\/pre>\n\n\n\n<p>Which we can express like this:<\/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-class\">.box-inner<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: rebeccapurple;\n  ...\n\n  @container box (inline-size &lt;= calc(100vw - 80px * 2 - 1rem * 2)) {\n    <span class=\"hljs-comment\">\/* move arrows here *\/<\/span>\n  }\n}<\/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>I&#8217;ll use a bit of <code>translate<\/code> to move the arrows here:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qEEVjeR\" src=\"\/\/codepen.io\/anon\/embed\/qEEVjeR?height=450&amp;theme-id=47434&amp;slug-hash=qEEVjeR&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qEEVjeR\" title=\"CodePen Embed qEEVjeR\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And here&#8217;s a video of the success:<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='329' src='https:\/\/videopress.com\/embed\/hKDgwenc?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1739540970'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>Again what&#8217;s kinda cool about this is that we don&#8217;t know what the size of the container is. It could be changed anytime and this will continue to work. The only hard coded numbers we used were for the size of the arrow elements and the gap, which you could abstract out to custom properties if you wanted to be more flexible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A container query can contain viewport units, meaning you can compare the window vs the element and make choices.<\/p>\n","protected":false},"author":1,"featured_media":5864,"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":[341,47,7,340],"class_list":["post-5796","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-carousels","tag-container-queries","tag-css","tag-viewport-units"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/05\/Container-Query-for_-is-there-enough-space-outside-this-element_-1.jpg?fit=1140%2C676&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/5796","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=5796"}],"version-history":[{"count":8,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/5796\/revisions"}],"predecessor-version":[{"id":5865,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/5796\/revisions\/5865"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/5864"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=5796"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=5796"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=5796"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}