What is CSS position: static?

position: static is the default positioning mode for almost every element on the page. A static element participates in the normal document flow: it goes where the layout system (block, inline, flex, grid, etc.) places it.

The most important “meaning” to remember: Static elements ignore top, right, bottom, and left. Those offset properties only affect elements that are position: relative, absolute, fixed, or sticky.

.card {
  position: static;
}
  
.card {
  position: static;
  top: 40px;
  left: 40px;
}
  
.card {
  position: relative;
  top: 40px;
  left: 40px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.stack {
  display: grid;
  gap: 12px;
  max-width: 720px;
}

.card {
  border: 3px solid #111;
  border-radius: 14px;
  background: #fff;
  padding: 14px;
}

.label {
  display: inline-block;
  font-weight: 700;
  padding: 4px 10px;
  border: 2px solid #111;
  border-radius: 999px;
}

.muted {
  opacity: 0.8;
}
  
.card

Click the snippets. Notice how top and left do nothing while the element is static, but work immediately once it becomes relative.

Neighbor .card

I am just here to show the layout flow.

Normal flow and position: static

“Normal flow” is how the browser naturally lays out elements:

  • Block elements (like div, p) stack vertically by default.
  • Inline elements (like span, em) sit inside a line of text.
  • Flex and grid containers place their children according to their own layout rules.

If an element is static, it stays inside this normal flow. That means it affects the layout around it and is affected by it.

.flow {
  display: block;
}
  
.flow {
  display: flex;
  gap: 10px;
}
  
.flow {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.flow {
  border: 3px solid #111;
  border-radius: 14px;
  background: #fff;
  padding: 12px;
  max-width: 780px;
}

.item {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #f6f6f6;
}

.item strong {
  font-weight: 800;
}
  
Item A
Static child
Item B
Static child
Item C
Static child
Item D
Static child

Notice: we never had to set position: static here. The children are static automatically, and the container’s layout mode (block, flex, grid) decides where they go.

Learn more about flex in the CSS Flexbox Interactive Tutorial, and about grid in the CSS Grid Interactive Tutorial.

Why top, bottom, left, and right “don’t work” on static elements

This is the classic “CSS position static not working” moment. It’s not broken. It’s doing exactly what static means.

  • If the element is position: static, offsets are ignored.
  • If you want to nudge it without leaving the flow, use position: relative.
  • If you want it to be taken out of the flow and placed precisely, use position: absolute (or fixed).
.badge {
  position: static;
  bottom: 0;
  right: 0;
}
  
.badge {
  position: relative;
  bottom: 0;
  right: 0;
}
  
.badge {
  position: relative;
  bottom: 18px;
  right: 18px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  max-width: 720px;
  border: 3px solid #111;
  border-radius: 16px;
  padding: 18px;
  background: #fff;
}

.badge {
  display: inline-block;
  padding: 8px 12px;
  border: 2px solid #111;
  border-radius: 999px;
  font-weight: 800;
  background: #f6f6f6;
}

.muted {
  opacity: 0.8;
}
  

We are trying to push the badge toward the bottom-right using bottom and right. With static, that does nothing.

Badge

Also important: margin and transform still work on static elements. So if you just need spacing, use margins. If you need a visual shift without affecting layout, transform: translate() is another option.

CSS position: static vs position: relative

These two are close cousins, but they behave differently in one key way:

  • static: normal flow, offsets ignored.
  • relative: still in normal flow, but offsets apply (it can be nudged).

Another way to say it: relative is “static, but allowed to move.”

.pop {
  position: static;
  top: 16px;
  left: 16px;
}
  
.pop {
  position: relative;
  top: 16px;
  left: 16px;
}
  
.pop {
  position: relative;
  top: -12px;
  left: 0;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.row {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  padding: 12px;
  background: #fff;
  display: grid;
  gap: 10px;
}

.box {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #f6f6f6;
}

.pop {
  border-style: solid;
  background: #fff;
}

.muted {
  opacity: 0.8;
}
  
Pop box

Switch between static and relative to see the offset behavior.

Neighbor box

Notice: with relative, the pop box moves visually, but this neighbor still acts as if the pop box is in its original spot.

That last point is crucial for beginners: relative does not “pull things up” around it. It keeps its original space in the layout, then moves visually.

Learn more about position: relative; in the CSS Position Relative Interactive Tutorial.

CSS position: static vs position: absolute

absolute is where positioning gets spicy:

  • static: stays in the normal flow, affects layout.
  • absolute: removed from normal flow, does not take up space, and can be placed using offsets.

Absolute positioning is usually based on the nearest ancestor that is not static (often a parent with position: relative). If no such ancestor exists, the browser uses the initial containing block (roughly the viewport/page).

.pin {
  position: static;
}
  
.pin {
  position: absolute;
  top: 12px;
  right: 12px;
}
  
.frame {
  position: relative;
}

.pin {
  position: absolute;
  top: 12px;
  right: 12px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.frame {
  max-width: 360px;
  border: 3px solid #111;
  border-radius: 16px;
  padding: 18px;
  background: #fff;
}

.content {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 14px;
  background: #f6f6f6;
}

.pin {
  display: inline-block;
  padding: 8px 12px;
  border: 2px solid #111;
  border-radius: 999px;
  font-weight: 800;
  background: #fff;
}

.muted {
  opacity: 0.8;
}
  

The badge tries to "pin" to the top-right. First it is static (no pinning), then absolute (it moves), then we make the parent relative so the pin is relative to this box.

Pinned?

If you ever see an absolutely positioned element “teleport” somewhere unexpected, the first question is: “Which ancestor is it positioned against?” If all ancestors are static, it won’t be relative to the parent you expected.

Learn more about position: absolute; in the CSS Position Absolute Interactive Tutorial.

CSS position: static vs position: sticky

sticky starts out behaving like a normal-flow element (like static), but then it “sticks” when you scroll past a threshold.

Two common beginner gotchas:

  • Sticky needs at least one offset, usually top (or bottom).
  • Sticky sticks within its scroll container (often the nearest ancestor with scrolling).
.header {
  position: static;
}
  
.header {
  position: sticky;
  top: 0;
}
  
.scroller {
  height: 220px;
  overflow: auto;
}

.header {
  position: sticky;
  top: 0;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.scroller {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
}

.header {
  border-bottom: 3px solid #111;
  background: #f6f6f6;
  padding: 12px 14px;
  font-weight: 900;
}

.list {
  padding: 14px;
  display: grid;
  gap: 10px;
}

.row {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #fff;
}

.muted {
  opacity: 0.8;
}
  
Sticky header (scroll inside this box)
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8

If you switch to sticky and it “does nothing,” check: Is there a top (or bottom) value? Without it, there’s no sticking threshold.

Learn more about position: sticky; in the CSS Position Sticky Interactive Tutorial.

CSS position: static vs position: fixed

fixed is the “stick it to the viewport” positioning mode. It removes the element from normal flow (like absolute), but instead of positioning relative to a parent, it positions relative to the viewport (your browser window).

  • static: stays in normal flow, takes up space, offsets ignored.
  • fixed: removed from flow, does not take up space, offsets work, and it stays put when you scroll.

The most common real-world example is a “chat” button or a cookie banner that stays visible while scrolling.

.floater {
  position: static;
  bottom: 16px;
  right: 16px;
}
  
.floater {
  position: fixed;
  bottom: 16px;
  right: 16px;
}
  
.floater {
  position: fixed;
  top: 16px;
  right: 16px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.viewport-demo {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
  height: 260px;
  overflow: auto;
  position: relative;
}

.filler {
  border: 2px dashed #111;
  border-radius: 12px;
  background: #f6f6f6;
  padding: 12px;
  display: grid;
  gap: 10px;
  min-height: 620px;
}

.filler p {
  margin: 0;
}

.floater {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border: 3px solid #111;
  border-radius: 999px;
  background: #fff;
  font-weight: 900;
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  border: 2px solid #111;
  background: #f6f6f6;
}

.muted {
  opacity: 0.8;
}
  

Scroll inside this box. With static, the button sits in the flow and scrolls away. With fixed, it pins itself to the viewport (your screen) and stays visible.

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Scroll content...

Common fixed gotchas (and why they matter when you expected static)

  • Layout jump: because fixed elements are removed from flow, they don’t reserve space. If you turn a header into position: fixed, content may slide under it unless you add padding/margin to compensate.
  • Mobile browser behavior: some mobile browsers treat the “viewport” differently as the address bar shows/hides, which can make fixed UI feel a bit jumpy. Test on real devices.
  • Use fixed for overlays, not layout: if your goal is “put the footer at the bottom of a card,” that’s not fixed. That’s a layout job (flex/grid).

A quick rule of thumb: Static is for normal layout. Fixed is for UI that must stay on screen while scrolling.

Learn more about position: fixed; in the CSS Position Fixed Interactive Tutorial.

CSS position: static and z-index

This is a sneaky one. Beginners often try: z-index: 9999; and nothing happens.

In most common cases, z-index only works on positioned elements (elements whose position is not static), or on certain layout contexts like flex/grid items. So if your element is plain static in normal flow, z-index often won’t change stacking.

.a {
  z-index: 10;
}
  
.a {
  position: relative;
  z-index: 10;
}
  
.b {
  position: relative;
  z-index: 20;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.stage {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
  display: grid;
  gap: 10px;
}

.pile {
  position: relative;
  height: 160px;
  border: 2px dashed #111;
  border-radius: 14px;
  background: #f6f6f6;
}

.card {
  width: 220px;
  height: 110px;
  border: 3px solid #111;
  border-radius: 14px;
  padding: 10px;
  background: #fff;
  position: absolute;
  top: 22px;
  left: 22px;
}

.a {
  transform: translate(0, 0);
}

.b {
  transform: translate(70px, 34px);
}

.title {
  font-weight: 900;
}

.muted {
  opacity: 0.8;
}
  

These boxes overlap. Try changing which one is on top using z-index. First we apply z-index without positioning (often useless), then we position it and it starts to behave.

A
I want to be on top
B
Me too

Quick practical tip: if you’re trying to “bring something forward,” adding position: relative is often the smallest change that makes z-index behave.

Learn more about z-index and stacking in the CSS Z-Index Interactive Tutorial.

“CSS position static bottom” explained

People often search for “position static bottom” because they want an element to sit at the bottom of something. The key idea: bottom does not apply to static elements.

To place something at the bottom, you usually want one of these approaches:

  • Layout approach: use flex or grid to push content to the bottom (recommended).
  • Positioning approach: make the parent positioned, then use position: absolute on the child.
.panel {
  display: flex;
  flex-direction: column;
}

.footer {
margin-top: auto;
} 
.panel {
  position: relative;
}

.footer {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 14px;
}
  
.panel {
  position: relative;
}

.footer {
  position: static;
  bottom: 14px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.panel {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
  height: 310px;
}

.body {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #f6f6f6;
}

.footer {
  border: 3px solid #111;
  border-radius: 12px;
  padding: 10px 12px;
  background: #fff;
  font-weight: 800;
}

.muted {
  opacity: 0.8;
}
  
Panel content

We want the footer to sit at the bottom of this panel. Try the flex method, then the absolute method, then the "static + bottom" method (which fails).

If the element is part of the layout (like a footer inside a card), flex/grid is usually the cleanest choice. Absolute positioning is great for overlays, badges, and “pin to corner” UI.

“CSS position static relative” clarified

This phrase usually means one of two things:

  • “Is static relative to its parent?” (Answer: it’s placed by normal flow inside the parent.)
  • “How do I make it relative?” (Answer: change it to position: relative.)

A static element’s placement depends on layout rules (block, flex, grid). But it is not “relative positioning.” If you need offsets, you need relative (or another positioned value).

.container {
  display: grid;
  gap: 10px;
}

.box {
position: static;
} 
.container {
  display: grid;
  gap: 10px;
}

.box {
  position: relative;
  top: 16px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.container {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  padding: 14px;
  background: #fff;
}

.box {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #f6f6f6;
}

.box strong {
  font-weight: 900;
}

.muted {
  opacity: 0.8;
}
  
Box A

Static: placed by the grid flow.

Box B

This one will get pushed visually when .box becomes relative and moves.

Here are a few quick “static in real life” examples. Most of your page is static most of the time, and that’s a good thing.

.nav a {
  display: inline-block;
  padding: 10px 12px;
}
  
.article p {
  margin: 0 0 12px 0;
}
  
.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.demo {
  max-width: 980px;
  display: grid;
  gap: 14px;
}

.nav {
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 10px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.nav a {
  border: 2px solid #111;
  border-radius: 999px;
  text-decoration: none;
  color: #111;
  background: #f6f6f6;
  font-weight: 700;
}

.article {
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
}

.cards {
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
}

.card {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 12px;
  background: #f6f6f6;
  min-height: 84px;
}

.muted {
  opacity: 0.8;
}

@media (max-width: 740px) {
  .cards {
    grid-template-columns: 1fr;
  }
}
  

Article content

Static paragraphs follow normal flow. This is the browser being helpful.

Spacing is managed with margins and layout, not with top and left.

Card 1
Static
Card 2
Static
Card 3
Static

Debugging: “static not working” checklist

If you tried to move something and it won’t budge, run through this list:

  1. Is it still position: static? If yes, offsets are ignored.
  2. Are you actually trying to do layout? If you’re aligning items, use flex/grid first.
  3. Are you trying to overlay / pin? Use position: absolute on the overlay and make the parent or the target ancestor position: relative.
  4. Is z-index not working? Add position: relative (or confirm it’s a flex/grid item) and watch for stacking contexts.
  5. Is sticky not sticking? Add top and check the scroll container.
.help {
  position: static;
  top: 30px;
  z-index: 999;
}
  
.help {
  position: relative;
  top: 30px;
  z-index: 999;
}
  
.shell {
  position: relative;
}

.help {
  position: absolute;
  top: 14px;
  right: 14px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.shell {
  max-width: 780px;
  border: 3px solid #111;
  border-radius: 16px;
  background: #fff;
  padding: 14px;
}

.block {
  border: 2px dashed #111;
  border-radius: 12px;
  padding: 14px;
  background: #f6f6f6;
  min-height: 140px;
}

.help {
  display: inline-block;
  padding: 8px 12px;
  border: 2px solid #111;
  border-radius: 999px;
  background: #fff;
  font-weight: 900;
}

.muted {
  opacity: 0.8;
}
  

This playground shows the common path: static offsets do nothing, relative offsets work, and absolute is for pinning inside a parent.

?

Key takeaways

  • position: static is the default: normal flow, no offset positioning.
  • Offsets (top, right, bottom, left) do nothing on static elements.
  • Use position: relative to nudge something while keeping its layout space.
  • Use position: absolute to overlay or pin, usually inside a parent set to position: relative.
  • If z-index “doesn’t work,” ensure the element is positioned (or verify its stacking context).

Conclusion

Understanding position: static is crucial because it forms the baseline for all other positioning schemes. Remember, static elements follow the normal flow and ignore offsets, making them predictable and reliable.