{"id":1473,"date":"2024-04-16T17:22:15","date_gmt":"2024-04-16T23:22:15","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=1473"},"modified":"2024-04-16T17:22:16","modified_gmt":"2024-04-16T23:22:16","slug":"things-that-can-break-aspect-ratio-in-css","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/things-that-can-break-aspect-ratio-in-css\/","title":{"rendered":"Things That Can Break aspect-ratio in CSS"},"content":{"rendered":"\n<p>CSS has <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/aspect-ratio\">an <code>aspect-ratio<\/code> property<\/a>, which has had full support since around 2021. It can be a very satisfying property to use, because it can help match how your brain \ud83e\udde0 works or what the desired design outcome does better than forcing dimensions does. <em>&#8220;I need a square here&#8221;<\/em> or <em>&#8220;I need to match the 16:9 size of a <code>&lt;video&gt;<\/code>&#8221; <\/em>are very reasonable design needs. Especially in a fluid environment where you&#8217;re purposely trying not to think in exact dimensions because you know they can change.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Usually, It Just Works<\/h2>\n\n\n\n<p>Here I&#8217;ve got a <code>&lt;div&gt;<\/code> sitting in a container. The <code>&lt;div&gt;<\/code> naturally fills the width. I&#8217;ve set <code>aspect-ratio: 1 \/ 1;<\/code> on it, thus, it&#8217;s a square. \ud83e\udd41<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_rNbZqxG\" src=\"\/\/codepen.io\/anon\/embed\/rNbZqxG?height=450&amp;theme-id=47434&amp;slug-hash=rNbZqxG&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed rNbZqxG\" title=\"CodePen Embed rNbZqxG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>That video example from the intro is also prudent. In that case, for whatever historical reason, <code>&lt;video&gt;<\/code> has a default style of being <code>300px<\/code> wide, so if we want it to fill the space, we need to set <code>width: 100%<\/code> and then aspect-ratio will do what we want:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_eYoLPZG\" src=\"\/\/codepen.io\/anon\/embed\/eYoLPZG?height=450&amp;theme-id=47434&amp;slug-hash=eYoLPZG&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed eYoLPZG\" title=\"CodePen Embed eYoLPZG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Element in a grid will behave nicely as well. Here, 12 <code>&lt;div&gt;s<\/code> are placed within a grid with a square aspect ratio and they respect it handily:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_GRLXdoG\" src=\"\/\/codepen.io\/anon\/embed\/GRLXdoG?height=450&amp;theme-id=47434&amp;slug-hash=GRLXdoG&amp;default-tab=html,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed GRLXdoG\" title=\"CodePen Embed GRLXdoG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>But things <em>can<\/em> go wrong, leaving an element that appears to <em>not<\/em> respect the <code>aspect-ratio<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Potential Breakage #1) Setting Both Dimensions<\/h2>\n\n\n\n<p>If both a <code>height<\/code> <em>and<\/em> <code>width<\/code> are set on an element, then <code>aspect-ratio<\/code> is ignored. That goes for <code>block-size<\/code> and <code>inline-size<\/code> too, of course, the logical property equivalents. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.el<\/span> {\n  <span class=\"hljs-attribute\">inline-size<\/span>: <span class=\"hljs-number\">300px<\/span>;\n  <span class=\"hljs-attribute\">block-size<\/span>: <span class=\"hljs-number\">200px<\/span>;\n  <span class=\"hljs-attribute\">aspect-ratio<\/span>: <span class=\"hljs-number\">1<\/span> \/ <span class=\"hljs-number\">1<\/span>; <span class=\"hljs-comment\">\/* does nothing *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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 makes sense to me (which one would it ignore?), but it can be awfully confusing if one of the dimensions is set from somewhere you didn&#8217;t expect. Perhaps you were expecting to set a <code>height<\/code> and <code>aspect-ratio<\/code> on an <code>&lt;img&gt;<\/code>, not realizing your baseline CSS file also sets the <code>width<\/code> on images, that would make <code>aspect-ratio<\/code> fail somewhat unexpectedly. <\/p>\n\n\n\n<p>This can be true of information outside of CSS as well. For example a <code>height<\/code> attribute on an <code>&lt;img&gt;<\/code> tag (which is highly recommended) counting as the other axis here and not allowing <code>aspect-ratio<\/code> to work:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_poBOxdr\" src=\"\/\/codepen.io\/anon\/embed\/poBOxdr?height=450&amp;theme-id=47434&amp;slug-hash=poBOxdr&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed poBOxdr\" title=\"CodePen Embed poBOxdr\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Note that limiting dimensions with <code>min-width<\/code>, <code>min-height<\/code>, <code>min-inline-size<\/code>, <code>min-block-size<\/code>, <code>max-width<\/code>, <code>max-height<\/code>, <code>max-block-size<\/code>, <code>max-inline-size<\/code> will be respected and also might break the <code>aspect-ratio<\/code>. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Potential Breakage #2) Stretching<\/h2>\n\n\n\n<p>Here we have three <code>&lt;div&gt;<\/code> in a flex container all with different aspect ratios. But&#8230; they are all the same dimensions:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_gOydBop\" src=\"\/\/codepen.io\/anon\/embed\/gOydBop?height=450&amp;theme-id=47434&amp;slug-hash=gOydBop&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed gOydBop\" title=\"CodePen Embed gOydBop\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Why?! Those <code>&lt;div&gt;<\/code>s <em>only<\/em> have a <code>width<\/code> set on them, no <code>height<\/code> (or logical equivalent). The problem here is that the height\/block-size is forced because flex items are influenced by the default <code>align-items: stretch;<\/code><\/p>\n\n\n\n<p>If we change that default to <code>align-items: flex-start;<\/code> on the parent flex container, you can see <code>aspect-ratio<\/code> start working:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_NWmLXPo\/cc3377144d3cb7ed1ea4c2f22c2082e2\" src=\"\/\/codepen.io\/anon\/embed\/NWmLXPo\/cc3377144d3cb7ed1ea4c2f22c2082e2?height=450&amp;theme-id=47434&amp;slug-hash=NWmLXPo\/cc3377144d3cb7ed1ea4c2f22c2082e2&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed NWmLXPo\/cc3377144d3cb7ed1ea4c2f22c2082e2\" title=\"CodePen Embed NWmLXPo\/cc3377144d3cb7ed1ea4c2f22c2082e2\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>This kind of thing can be true of any of the <code>stretch<\/code> values in CSS grid or flexbox. For example, CSS grid has <code>justify-items: stretch<\/code>; which is capable of causing this same kind of problem. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Potential Breakage #3) Content That Forces Height<\/h2>\n\n\n\n<p>One of the ways we <em>used<\/em> to pull of <code>aspect-ratio<\/code> was <a href=\"https:\/\/daverupert.com\/2012\/04\/uncle-daves-ol-padded-box\/\">Uncle Dave&#8217;s ol&#8217; Padded Box Trick<\/a>. The box would be created by using <code>padding-bottom<\/code> on a zero-height box. Percentage padding is a percentage of the <code>width<\/code>, so that connection between width and height is established that way. But then you&#8217;d put an absolutely positioned box <em>inside that<\/em>. The problem with absolute positioning here is that the content is outside the normal flow of the document. So if, for example, you put text inside that is taller than the box, you&#8217;d have a problem. See below how the content hangs out of the box. The box has the right aspect-ratio, but it&#8217;s unlikely this is a desirable outcome:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_yLrxRQv\" src=\"\/\/codepen.io\/anon\/embed\/yLrxRQv?height=450&amp;theme-id=47434&amp;slug-hash=yLrxRQv&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed yLrxRQv\" title=\"CodePen Embed yLrxRQv\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>If we use <code>aspect-ratio<\/code> for our box instead, we&#8217;ll get:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_RwOYeEP\" src=\"\/\/codepen.io\/anon\/embed\/RwOYeEP?height=450&amp;theme-id=47434&amp;slug-hash=RwOYeEP&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed RwOYeEP\" title=\"CodePen Embed RwOYeEP\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Now the orange box contains all the content, which again is probably the desired outcome here in most situations. But notably, the box is no longer the <code>aspect-ratio<\/code> that we declared. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Did I miss any of the ways <code>aspect-ratio<\/code> can break or have unexpected results? I suppose browser-support is another thing to consider, but it&#8217;s pretty solid. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>CSS has an aspect-ratio property, which has had full support since around 2021. It can be a very satisfying property to use, because it can help match how your brain \ud83e\udde0 works or what the desired design outcome does better than forcing dimensions does. &#8220;I need a square here&#8221; or &#8220;I need to match the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1712,"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":[156,7],"class_list":["post-1473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-aspect-ratio","tag-css"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/aspect-ratio-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1473","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=1473"}],"version-history":[{"count":12,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1473\/revisions"}],"predecessor-version":[{"id":1715,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1473\/revisions\/1715"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/1712"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=1473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=1473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=1473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}