How Does Auto Positioning Work In CSS?

A few weeks ago Andrei raised an interesting question on one of my older posts. The post shows how to create a navigation bar. Andrei noticed the submenu was positioned absolutely, but none of its ancestor elements had positioning applied. Why then did the submenu display directly below its parent link in the menu?

I honestly didn’t know. Like Andrei my expectation was the submenu should be positioned relative to the html element given the absence of other positioned elements and should appear in the top left corner of the browser, but it didn’t.

The reason turned out to be very simple, though it took some investigation to find it. I’ll spare you the false leads and just explain what’s going on.

2 toy wood blocks

Containing Blocks Set Positioning Context

As a quick review when you use css positioning on an element its position is relative to some containing block. That containing block will be the nearest ancestor element that also has positioning (other than static) applied. If there is no ancestor with positioning applied the containing block becomes the initial containing block, which is the html element.

In the post I was using the Suckerfish system to create a drop down menu. I’ve been using it to create drop downs for as long as I can remember. You probably have too. By default you position your submenu far off the page, usually -999em to the left. On hover you change the value of left to auto and the submenu appears directly below its parent menu item.

At first glance the submenu seems to be ignoring the above information about containing blocks. None of its ancestors have positioning set implying it should be positioned relative to the html element or the browser window.

At least that’s what Andrei and I both thought should happen. Our mistake was in how we interpreted “auto” to work.

Submenu open when hovering over menu item

How Should a Browser Interpret Auto?

We were both assuming that a value of auto was the same as a value of 0 and so setting left: auto was equivalent to left: 0. There are times when a css value of auto equates to 0. This is not one of those times though.

When an element has been set to position: absolute, its position (and possibly size) is specified with the ‘top’, ‘right’, ‘bottom’, and ‘left’ properties. These properties specify offsets with respect to the box’s containing block. For non-replaced elements, the effect of the auto value (for top, right, bottom, or left) depends on which of these other related properties have the value ‘auto’ as well.

That last part is the key. By definition auto isn’t 0. It might be, but it depends on the values set on the other properties.

The Suckerfish drop down sets and then changes the “left” property, but it leaves the other 3 properties as auto. When we initially set left to -999em the right value comes along for the ride and the submenu is located way off the page. On hover when we change left to auto we have the condition where all 4 values are auto.

An article I came across on auto positioning for absolutely positioned elements explains what happens as does this article from Dev.Opera on absolute and fixed positioning. The quote below is from the latter.

The default value for the top, right, bottom and left properties is auto, which means the absolutely positioned box will appear exactly where it would have had if it wasn’t positioned. Since it’s removed from the flow it will overlap any elements in the normal flow that follow it, though.

You can see this in action in the images above and below this section. Above is where the menu appears when hovering over its parent link. Here left (as well as right, top, and bottom) are set to auto.

Below is the same menu when I remove positioning on the submenu. The submenu is located in the same place as above. The top level menu items are in different locations, because the sub menu is now again in the document flow, but the submenu itself is located in the same place in both images.

It’s obvious once you think about it. If the default of auto was 0, then an element with all 4 sides set to 0 would need to stretch to each edge of its container. There are times when we rely on this stretching. It’s part of one method for vertically centering elements.

That’s clearly not what’s happening here. When all 4 sides (or really when either of the 2 opposing sides) hold values of auto it’s up to the browser to decide how best to locate the element.

We rely on this to horizontally center block level elements with margin-left: auto and margin-right: auto. In this case the margin is split equally and the element centered. In the case of the drop down, a child list gets displayed exactly where it would have been located if no positioning were applied.

Submenu visible without positioning applied

Summary

Some of you might be thinking why am I wasting time talking about something so obvious. It’s obvious in hindsight, but it certainly wasn’t obvious to me before digging into containing blocks and how auto-positioning works. Since Andrei raised the question, I assume it wasn’t obvious to him either. And if it wasn’t obvious to either of us, I assume there are others who would also say it wasn’t so obvious to them.

Sometimes we accept that a technique works without taking the time to understand why it it works. When asked why we’re at a loss to answer. It’s worthwhile to figure out why and better understand what’s happening.

I’ll no longer take the auto value for granted on any property and assume it equates to what I initially expect. Instead I’ll think about how it will be computed and what will happen based on other possible auto values on related properties. More than likely it will usually behave exactly as I’ve always assumed, but I suspect there will be a few times where it doesn’t and in not behaving as expected it might allow for some interesting results.

Download a free sample from my book, Design Fundamentals.

10 comments

  1. Thanks for the article explaining this arcane subject. It would have been even more understandable if you’d used “it’s” to mean “it is,” and “its” to be the possessive of “it.” I was stopped in my tracks trying to decide what you meant when the wrong word was used. Sorry to complain, but thought others might have this problem, too. Thanks again.

    • Thanks Lily. I’m glad you enjoyed the article.

      Wow! I was awful with my its and it’s in this post. I swear I do know the difference. I’m not sure how I screwed it up so much here.

      I think I caught all incorrect uses and fixed them. Hopefully others won’t have the same problem following along. Sorry about that.

      No need to apologize for complaining, by the way. It was completely my bad. I’m glad you let me know so I could fix things. Thanks.

  2. Thanks for the summary Steven. These subtle factors are exactly what can save the day when designing or debugging positioning issues. When there are so many conditional factors behind how an element’s position renders, it’s always illuminating to understand the theory behind rules-of-thumb.

    • Thanks Thor. I think I’ve always taken the auto value for granted. Most of the time I explicitly set a value and so don’t think about it, but at times I forget it’s still set on some properties and it doesn’t necessarily work the same way across all of them.

      Auto positioning definitely tripped me up. After looking into it, it makes perfect sense. It wasn’t what I expected though and I figured others probably expected the same thing I did.

  3. Clearly explained Steve. Understanding the concepts in positioning has been a challenge, but your writing really helps. I’ve recently seen -999em used in the CSS of a javascript image slider and thought it was bizarre until now. Thanks for the insight!

  4. Absolutely not obvious :)
    I started my first widespread CSS project a few weeks ago while converting a table-based layout to CSS with media queries and, the sometimes missing logic of positioning, still gets my head spinning once in a while when an object just won’t stay where I want it to.
    Also I still can’t figure out if it’s possible to absolutely position an element according to its parent’s parent(?)
    By the way – always be careful when positioning elements off-screen and don’t do it if you don’t need to. GoogleBot is smart, but hiding elements like that can be a SEO-disaster. I’m not saying it’s always bad practice but it can be considered black-hat if used extensively.

    Great article – thank you!

    • Guess this topic wasn’t as obvious as I initially thought. Good to know for those topics I don’t cover thinking they’re just as obvious.

      You can position an element according to the parent’s parent. To do that you wouldn’t any any kind of positioning on the parent. So

      Grand Parent – has some kind of positioning
      Parent – has no positioning
      Child – can be positioned relative to Grand Parent.

      I would stress over positioning things off screen. Google isn’t going to object. It’s more about what you’re positioning off screen. If anything we’re going to see much more content positioned off screen now that off canvas navigation patterns are becoming popular with mobile devices.

Leave a Reply

Your email address will not be published.

css.php