Absolute X

Horizontal views via position: absolute — all panels share
the same page Y so transforms are direct X, Z, and small Y offsets.

position: absolute

Why Absolute?

In the relative-flow approach (views-horizontal.html), each panel sits lower in the page than the one before it — panel 1 might be at Y=1360px, panel 4 at Y=3300px. To bring them to the same 3D height, each needs a different, large negative translateY: −1360px, −1880px, −2540px, −3300px. Those values must be re-estimated whenever content height changes.

With position: absolute all panels share the same top value in the page, so their base Y position is identical. The CSS 3D transform only needs to specify intentional offsets — a consistent rotation and X/Z translation, with small optional Y tweaks for deliberate vertical variation. No compensation math, no large magic numbers.

/* All panels at the same DOM Y — direct transforms */
.abs-panel {
  position: absolute;
  top: 300px;        /* shared baseline — same for all */
  left: 0; right: 0;
  margin: 0 auto;
  max-width: 700px;
}

.panel-far-left.foldpage-el {
  transform: rotateY(42deg) translateX(-880px) translateZ(160px);
  /* no translateY needed — panel is already at the right height */
}
.panel-near-left.foldpage-el {
  /* small translateY = intentional 80px lift, not compensation */
  transform: translateY(-80px) rotateY(20deg) translateX(-440px) translateZ(-200px);
}
Same base Y

All panels share top: 300px — the 3D Y difference between them is whatever you put in the transform.

Content-length safe

Changing a panel's content height doesn't shift any other panel's Y position in the page.

Direct control

To shift a panel 200px higher in 3D, write translateY(-200px) — nothing to reverse-engineer.

Scroll spacer required

Absolute panels don't extend the page. A .scroll-spacer div provides the scroll room instead.

This panel is panel-far-left — transform: rotateY(42deg) translateX(-880px) translateZ(160px). No Y offset — it sits at exactly top: 300px.

Scroll Room

The Scroll Spacer

Fold derives the total scroll range from document.scrollHeight − window.innerHeight. Absolute elements don't contribute to scrollHeight — only elements in normal document flow do. Without intervention, a page of all absolute panels would have barely any scroll room and the view system would stall.

The fix is a .scroll-spacer div in normal flow at the end of the wrapper. Its height is the scroll room budget for all view transitions.

<div id="wrapper" class="foldpage" style="position:relative">

  <header data-foldpage-view="0" style="min-height:115vh">...</header>

  <!-- position:absolute — all at the same top -->
  <section class="panel-left"  style="position:absolute;top:300px" data-foldpage-view>...</section>
  <section class="panel-right" style="position:absolute;top:300px" data-foldpage-view>...</section>

  <!-- Normal-flow spacer: adds the scroll room absolute panels can't -->
  <div class="scroll-spacer"></div>

</div>

Sizing the Spacer

The scroll range used by the view system is split into equal segments, one per view transition. Rough formula:

/* Minimum scroll spacer height */
.scroll-spacer {
  height: calc(
    (N_views − 1) × 100vh  /* one viewport per transition */
    + 25% buffer           /* headroom for tall zones */
  );
}

This demo has 5 views (0–4) so 4 transitions. At 900px viewport: 4 × 900 × 1.25 ≈ 4500px. The home section (min-height: 115vh) already contributes ~1035px, but the spacer covers the rest as a flat guarantee — it's simpler to over-size it than to calculate exactly.

This panel is panel-near-left: translateY(-80px) rotateY(20deg) translateX(-440px) translateZ(-200px). The translateY(-80px) is a deliberate 80px upward shift — not compensation for page flow.

Side by Side

Absolute vs Relative Flow

Both techniques produce identical 3D results — the difference is only in how the CSS is authored and how robust it is to content changes.

Transform Comparison

✗ Relative flow (views-horizontal.html)
/* Each panel needs its own
 * large Y compensation */
.p1.foldpage-el {
  transform:
    translateY(-1360px)
    rotateY(42deg)
    translateX(-860px)
    translateZ(160px);
}
.p2.foldpage-el {
  transform:
    translateY(-1880px)
    rotateY(20deg)
    translateX(-440px)
    translateZ(-200px);
}
.p3.foldpage-el {
  transform:
    translateY(-2540px)
    ...
}
✓ Absolute positioning (this file)
/* All panels at top:300px.
 * No per-panel Y offsets. */
.p1.foldpage-el {
  transform:
    rotateY(42deg)
    translateX(-880px)
    translateZ(160px);
}
.p2.foldpage-el {
  transform:
    translateY(-80px)
    rotateY(20deg)
    translateX(-440px)
    translateZ(-200px);
}
.p3.foldpage-el {
  transform:
    translateY(80px)
    ...
}

When to Use Each

Use relative flow when…

Content naturally flows vertically (articles, docs) and the Y layout is meaningful.

Use absolute when…

Panels are layout-independent cards or panels with no natural vertical relationship.

Absolute limitation

Panels overlap in the flat browser view (before Fold activates). Fine for Fold-first pages.

Absolute advantage

Changing panel content height doesn't cascade — each panel's position is independent.

Aligning Panels with the Home View

The home section's center Y depends on min-height: 115vh, which changes with viewport height. The absolute panels are at a fixed top: 300px, so at a 900px viewport they appear slightly above the home section center (~517px). If you want exact alignment, use a fixed home height instead of min-height:

.view-home { height: 900px; }  /* fixed — viewport-independent */

.abs-panel { top: 250px; } /* 900/2 - panel_height/2 = 250px */
This panel is panel-near-right: translateY(80px) rotateY(-20deg) translateX(440px) translateZ(-200px). The translateY(80px) intentionally drops it 80px below the outer panels to reinforce the horizontal arc shape.

Starter Template

Copy & Adapt

A minimal absolute-positioning horizontal layout. Fixed home height for predictable panel alignment, a sized scroll spacer, and clean transforms.

<div id="wrapper" class="foldpage">

  <header class="home" data-foldpage-view="0">
    <h1>My Page</h1>
    <a href="#left"  data-foldpage-view-link="#left">Left</a>
    <a href="#right" data-foldpage-view-link="#right">Right</a>
  </header>

  <section id="left"  class="panel-left"  data-foldpage-view>Left</section>
  <section id="right" class="panel-right" data-foldpage-view>Right</section>

  <div class="scroll-spacer"></div>

</div>

<style>
  #wrapper  { position: relative; }

  .home     { height: 900px; }  /* fixed — easier math */

  .panel-left,
  .panel-right {
    position: absolute;
    top: 250px;    /* 900/2 − panel_h/2 ≈ home center */
    left: 0; right: 0; margin: 0 auto; max-width: 700px;
  }

  /* 2 transitions × 900px × 1.25 buffer */
  .scroll-spacer { height: 2250px; }

  .panel-left.foldpage-el  { transform: rotateY(40deg)  translateX(-800px) translateZ(150px); }
  .panel-right.foldpage-el { transform: rotateY(-40deg) translateX(800px)  translateZ(150px); }
</style>

See views-horizontal.html for the relative-flow version of this pattern, or all demos for the full set.

This panel is panel-far-right: rotateY(-42deg) translateX(880px) translateZ(160px). Symmetric with the far-left panel — same magnitude, opposite sign, no Y at all.