{
"$type": "site.standard.document",
"content": {
"$type": "site.standard.content.markdown",
"text": "As someone who like to think he deeply understands the CSS I’m writing, I do everything I can to avoid using CSS that can cause unintended side effects. As an example, for my new [personal website](https://donnie.damato.design), I use `z-index` *once* to handle the page tearing animation. Trying to manipulate the order of things using CSS can seem reasonable at first but often has hidden problems that you might not notice. I’d like to outline some of those problems here.\n\n## Who’s on first?\n\nLet’s say we have a dropdown component which produces some sort of flyout experience. We believe that setting some high `z-index` value will ensure that it is always on top of the content:\n\n```\n.dropdown {\n z-index: 100;\n}\n```\n\nThen, when we create the modal component, we set it as a higher `z-index` because it is meant to be disruptive and on top of everything:\n\n```\n.modal {\n z-index: 200;\n}\n```\n\nThe question here is, what happens when the dropdown component is meant to be part of the modal composition? For example, perhaps you need to select from a large list of options within the modal. In the current setup, the flyout could appear *underneath* the modal because the `z-index` value for the dropdown is lower than the modal.\n\nNow, when many folks find this problem, they start adding exceptions. Ok when *this specific dropdown* appears, we’re going to increase the `z-index`:\n\n```\n.dropdown.but-only-this-one {\n z-index: 300;\n}\n```\n\nSure, this could work. But then when large teams are trying to use these components it turns into a priority war. With more things that are meant to appear on top of each other, it becomes less clear which items are more important at which times. Everyone thinks their use is the exception to the rule and then no system truly exists.\n\nSome design systems took [Material’s guidelines for elevation](https://m2.material.io/design/environment/elevation.html#default-elevations) and turned them into design tokens for `z-index`. Unfortunately, based on my example above, this doesn’t work. It’s possible that your tooltip is meant to appear in a modal, causing its `z-index` number to increase.\n\nSo what’s the solution? Avoid using `z-index` altogether.\n\nWhen you start working with the `position` property, and then try reordering the elements, you should notice a certain quality. Having nothing else set, the order that the elements appear matches the DOM order. In other words, later elements will appear on top of elements that come before. In the following example, try rearranging the HTML elements without touching the CSS.\n\n<p>See the Pen <a href=\"https://codepen.io/fauxserious/pen/vEEYJoe\"> Positioning</a> by Donnie D’Amato (<a href=\"https://codepen.io/fauxserious\">@fauxserious</a>) on <a href=\"https://codepen.io\">CodePen</a>.</p>\n\nNotice that whatever box is rendered last, is the box that appears on top of the others. This means if we want things to appear on top of other things, we should be rendering them last in the DOM order.\n\nIn fact, this is exactly how the new [top-layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer) works in the DOM. The top-layer is exactly what it sounds like, it is a layer that exists on top of everything else in the page. That means even trying to set `z-index: Infinity` will not work here. Speaking of `z-index`, that doesn’t work on elements in this layer either. The only way to affect the order of elements here is by DOM order. The last rendered element in the layer is the element that appears on top. If you want something to be on top of that, you’ll need to append it to the layer.\n\n## Inset fill\n\nBut, let’s say you don’t need to do any flyouts or disruptions (good!). You want to do something more simple like have an element fill a container without itself contributing to the size of the container. Traditionally, we’d use the inset fill technique to do this.\n\n```\n.parent {\n position: relative;\n}\n\n.child {\n position: absolute;\n inset: 0; /* same as setting top, left, bottom, right all to 0 */\n}\n```\n\nThis was very common when we needed maintain the aspect ratio for media by using the [padding hack](https://css-tricks.com/aspect-ratio-boxes/). While we don’t need that specific hack any longer, there’s still use-cases for making an element fill a parent container. In those cases, I still recommend avoiding the use of `z-index` by making the element to appear on top last in the DOM order. But I’d also recommend avoiding the `position` property altogether.\n\nJosh Comeau has [a great post about stacking contexts](https://www.joshwcomeau.com/css/stacking-contexts/) that you should absolutely read. But the tl;dr is that using `position` creates a stacking context. This is good for when you want to use `z-index` but bad when other stacking contexts are created elsewhere and conflict in some way. Most people don’t know [the properties that create stacking contexts](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Stacking_context#features_creating_stacking_contexts), but these are usually the culprits to when you think you need to start introducing `z-index` into your CSS. Here’s a few important points:\n\n- If you create a container (for container queries) with `inline-size` or `size`, that creates a new stacking context.\n- If you set `opacity` on something to anything less than 1, that creates a new stacking context.\n- Nearly anything related to transforms, filters, masks, and blend modes will create a new stacking context.\n\nThis illustrates one of the things that makes people upset about CSS. There are properties that can affect other things in the composition in ways you don’t expect. You’d think that simply setting `opacity: .5;` is just making the element translucent, but there’s other side effects associated with it that could be unintended. Unfortunately, the only way to really know these is with experience. The more you avoid learning this, the more you’ll wonder what is happening every moment you begrudgingly write CSS.\n\nGetting back to the inset fill technique. Instead of using `position`, I recommend trying to use `display: grid;` instead:\n\n```\n.parent {\n display: grid; /** or inline-grid */\n}\n\n.child {\n grid-area: 1 / 1 / -1 / -1;\n}\n```\n\nThe `grid-area` set in the child says to make sure this item touches all of the edges of the parent grid, filling the space. This forces the element to appear on top of any other children that may be within the grid.\n\n## Reading flow\n\nOrdering things in the third dimension isn’t the only way we can affect elements using CSS. We’ve had the `order` property since the introduction of Flexbox. This has the ability to visually rearrange the elements in a composition without changing their order in the DOM.\n\n```\n.flex-child {\n order: 2;\n}\n```\n\nThere’s other properties that can change the visual order, such as `flex-direction` and even `grid-areas`. However, my recommendation is to avoid doing this, and if you must change the order to update the DOM order instead.\n\nNow I know what you’re probably thinking, using JavaScript to rearrange the DOM sounds expensive when CSS would be much more performant and that’s true. The problem comes down to accessibility. The page structure should match the visual order of elements. If it doesn’t, then folks who can’t see the visual rearrangement can be confused about the order of the elements.\n\nImagine that someone who uses an assistive technology has called a help line for assistance with their account. The person on the phone says, “click the first button”. If the DOM order doesn’t match the visual order, the first button could be different to these folks and cause confusion down the line.\n\nI keep this in mind when designing, and consider the ways I could keep the order maintained when the layout needs to change based on the available size. Sometimes though, you get a design in your inbox that can’t have reordering avoided. That’s when as of right now I’d recommend using a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver) to reflow the elements instead of CSS for the reasons I’ve described above. [Here’s an implementation](https://github.com/damato-design/system/blob/main/src/components/Box/reflow.ts) for my design system playground.\n\n## Bring order\n\nGood things are on the way! There’s a new CSS property being discussed called `reading-flow` which is designed to help the element order problems I’ve described above. If this property becomes available, then we could tell the browser what order the elements should be in if the visual order doesn’t match. Rachel Andrew has [some examples](https://chrome.dev/reading-flow-examples/) and [a presentation](https://www.youtube.com/watch?v=X6azWrtHS-k) on this. This is relating directly to the [Masonry discussions](https://github.com/w3c/csswg-drafts/issues/11243) to help understand what the intended flow is meant to be for the user. Having this along with top-layer will make setting the order of elements more clear than ever before.\n\nBottom line is that when you are trying to update the order of elements using CSS, pause to think of the side-effects of these decisions and refer to some of the recommendations here to help keep a consistent structure.",
"version": "1.0"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreibqz3hxomwgbno53kz73zmgqthwvwzukpctc6vgaf7ut56evz7uw4"
},
"mimeType": "image/png",
"size": 335403
},
"description": "CSS does a lot these days, and I argue that it does too much.",
"path": "/posts/out-of-order",
"publishedAt": "2025-04-16T00:00:00.000Z",
"site": "https://blog.damato.design",
"tags": [
"accessibility",
"css",
"design"
],
"textContent": "As someone who like to think he deeply understands the CSS I’m writing, I do everything I can to avoid using CSS that can cause unintended side effects. As an example, for my new personal website, I use once to handle the page tearing animation. Trying to manipulate the order of things using CSS can seem reasonable at first but often has hidden problems that you might not notice. I’d like to outline some of those problems here.\n\nWho’s on first?\n\nLet’s say we have a dropdown component which produces some sort of flyout experience. We believe that setting some high value will ensure that it is always on top of the content:\n\nThen, when we create the modal component, we set it as a higher because it is meant to be disruptive and on top of everything:\n\nThe question here is, what happens when the dropdown component is meant to be part of the modal composition? For example, perhaps you need to select from a large list of options within the modal. In the current setup, the flyout could appear underneath the modal because the value for the dropdown is lower than the modal.\n\nNow, when many folks find this problem, they start adding exceptions. Ok when this specific dropdown appears, we’re going to increase the :\n\nSure, this could work. But then when large teams are trying to use these components it turns into a priority war. With more things that are meant to appear on top of each other, it becomes less clear which items are more important at which times. Everyone thinks their use is the exception to the rule and then no system truly exists.\n\nSome design systems took Material’s guidelines for elevation and turned them into design tokens for . Unfortunately, based on my example above, this doesn’t work. It’s possible that your tooltip is meant to appear in a modal, causing its number to increase.\n\nSo what’s the solution? Avoid using altogether.\n\nWhen you start working with the property, and then try reordering the elements, you should notice a certain quality. Having nothing else set, the order that the elements appear matches the DOM order. In other words, later elements will appear on top of elements that come before. In the following example, try rearranging the HTML elements without touching the CSS.\n\nSee the Pen Positioning by Donnie D’Amato (@fauxserious) on CodePen.\n\nNotice that whatever box is rendered last, is the box that appears on top of the others. This means if we want things to appear on top of other things, we should be rendering them last in the DOM order.\n\nIn fact, this is exactly how the new top-layer works in the DOM. The top-layer is exactly what it sounds like, it is a layer that exists on top of everything else in the page. That means even trying to set will not work here. Speaking of , that doesn’t work on elements in this layer either. The only way to affect the order of elements here is by DOM order. The last rendered element in the layer is the element that appears on top. If you want something to be on top of that, you’ll need to append it to the layer.\n\nInset fill\n\nBut, let’s say you don’t need to do any flyouts or disruptions (good!). You want to do something more simple like have an element fill a container without itself contributing to the size of the container. Traditionally, we’d use the inset fill technique to do this.\n\nThis was very common when we needed maintain the aspect ratio for media by using the padding hack. While we don’t need that specific hack any longer, there’s still use-cases for making an element fill a parent container. In those cases, I still recommend avoiding the use of by making the element to appear on top last in the DOM order. But I’d also recommend avoiding the property altogether.\n\nJosh Comeau has a great post about stacking contexts that you should absolutely read. But the tl;dr is that using creates a stacking context. This is good for when you want to use but bad when other stacking contexts are created elsewhere and conflict in some way. Most people don’t know the properties that create stacking contexts, but these are usually the culprits to when you think you need to start introducing into your CSS. Here’s a few important points:\nIf you create a container (for container queries) with or , that creates a new stacking context.\nIf you set on something to anything less than 1, that creates a new stacking context.\nNearly anything related to transforms, filters, masks, and blend modes will create a new stacking context.\n\nThis illustrates one of the things that makes people upset about CSS. There are properties that can affect other things in the composition in ways you don’t expect. You’d think that simply setting is just making the element translucent, but there’s other side effects associated with it that could be unintended. Unfortunately, the only way to really know these is with experience. The more you avoid learning this, the more you’ll wonder what is happening every moment you begrudgingly write CSS.\n\nGetting back to the inset fill technique. Instead of using , I recommend trying to use instead:\n\nThe set in the child says to make sure this item touches all of the edges of the parent grid, filling the space. This forces the element to appear on top of any other children that may be within the grid.\n\nReading flow\n\nOrdering things in the third dimension isn’t the only way we can affect elements using CSS. We’ve had the property since the introduction of Flexbox. This has the ability to visually rearrange the elements in a composition without changing their order in the DOM.\n\nThere’s other properties that can change the visual order, such as and even . However, my recommendation is to avoid doing this, and if you must change the order to update the DOM order instead.\n\nNow I know what you’re probably thinking, using JavaScript to rearrange the DOM sounds expensive when CSS would be much more performant and that’s true. The problem comes down to accessibility. The page structure should match the visual order of elements. If it doesn’t, then folks who can’t see the visual rearrangement can be confused about the order of the elements.\n\nImagine that someone who uses an assistive technology has called a help line for assistance with their account. The person on the phone says, “click the first button”. If the DOM order doesn’t match the visual order, the first button could be different to these folks and cause confusion down the line.\n\nI keep this in mind when designing, and consider the ways I could keep the order maintained when the layout needs to change based on the available size. Sometimes though, you get a design in your inbox that can’t have reordering avoided. That’s when as of right now I’d recommend using a [](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver) to reflow the elements instead of CSS for the reasons I’ve described above. Here’s an implementation for my design system playground.\n\nBring order\n\nGood things are on the way! There’s a new CSS property being discussed called which is designed to help the element order problems I’ve described above. If this property becomes available, then we could tell the browser what order the elements should be in if the visual order doesn’t match. Rachel Andrew has some examples and a presentation on this. This is relating directly to the Masonry discussions to help understand what the intended flow is meant to be for the user. Having this along with top-layer will make setting the order of elements more clear than ever before.\n\nBottom line is that when you are trying to update the order of elements using CSS, pause to think of the side-effects of these decisions and refer to some of the recommendations here to help keep a consistent structure.",
"title": "Out of order",
"updatedAt": "2026-06-13T19:13:42.970Z"
}