diff --git a/README.md b/README.md
index 2a251271b..7b7fcec8c 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ export const App = () => {
   return (
     <div style={{ overflowY: "auto", height: 800 }}>
       <div style={{ height: 40 }}>header</div>
-      <Virtualizer startMargin={40}>
+      <Virtualizer startOffset="static">
         {Array.from({ length: 1000 }).map((_, i) => (
           <div
             key={i}
diff --git a/src/core/scroller.ts b/src/core/scroller.ts
index dd48b23e6..efc8b753e 100644
--- a/src/core/scroller.ts
+++ b/src/core/scroller.ts
@@ -15,7 +15,7 @@ import {
   ACTION_BEFORE_MANUAL_SMOOTH_SCROLL,
   ACTION_START_OFFSET_CHANGE,
 } from "./store";
-import { type ScrollToIndexOpts } from "./types";
+import { type ScrollToIndexOpts, StartOffsetType } from "./types";
 import { debounce, timeout, clamp, microtask } from "./utils";
 
 /**
@@ -34,6 +34,32 @@ const normalizeOffset = (offset: number, isHorizontal: boolean): number => {
   }
 };
 
+const calcOffsetToViewport = (
+  node: HTMLElement,
+  viewport: HTMLElement,
+  isHorizontal: boolean,
+  offset: number = 0
+): number => {
+  // TODO calc offset only when it changes (maybe impossible)
+  const offsetSum =
+    offset +
+    (isHorizontal && isRTLDocument()
+      ? viewport.offsetWidth - node.offsetLeft - node.offsetWidth
+      : node[isHorizontal ? "offsetLeft" : "offsetTop"]);
+
+  const parent = node.offsetParent;
+  if (node === viewport || !parent) {
+    return offsetSum;
+  }
+
+  return calcOffsetToViewport(
+    parent as HTMLElement,
+    viewport,
+    isHorizontal,
+    offsetSum
+  );
+};
+
 const createScrollObserver = (
   store: VirtualStore,
   viewport: HTMLElement | Window,
@@ -121,6 +147,10 @@ const createScrollObserver = (
     }
   };
 
+  if (getStartOffset) {
+    store._update(ACTION_START_OFFSET_CHANGE, getStartOffset());
+  }
+
   viewport.addEventListener("scroll", onScroll);
   viewport.addEventListener("wheel", onWheel, { passive: true });
   viewport.addEventListener("touchstart", onTouchStart, { passive: true });
@@ -159,7 +189,10 @@ type ScrollObserver = ReturnType<typeof createScrollObserver>;
  * @internal
  */
 export type Scroller = {
-  _observe: (viewportElement: HTMLElement) => void;
+  _observe: (
+    viewportElement: HTMLElement,
+    containerElement: HTMLElement
+  ) => void;
   _dispose(): void;
   _scrollTo: (offset: number) => void;
   _scrollBy: (offset: number) => void;
@@ -172,7 +205,8 @@ export type Scroller = {
  */
 export const createScroller = (
   store: VirtualStore,
-  isHorizontal: boolean
+  isHorizontal: boolean,
+  startOffset?: StartOffsetType
 ): Scroller => {
   let viewportElement: HTMLElement | undefined;
   let scrollObserver: ScrollObserver | undefined;
@@ -264,9 +298,24 @@ export const createScroller = (
   };
 
   return {
-    _observe(viewport) {
+    _observe(viewport, container) {
       viewportElement = viewport;
 
+      let getStartOffset: (() => number) | undefined;
+      if (startOffset === "dynamic") {
+        getStartOffset = () =>
+          calcOffsetToViewport(container, viewport, isHorizontal);
+      } else if (startOffset === "static") {
+        const staticStartOffset = calcOffsetToViewport(
+          container,
+          viewport,
+          isHorizontal
+        );
+        getStartOffset = () => staticStartOffset;
+      } else if (typeof startOffset === "number") {
+        getStartOffset = () => startOffset;
+      }
+
       scrollObserver = createScrollObserver(
         store,
         viewport,
@@ -293,7 +342,8 @@ export const createScroller = (
           } else {
             viewport[scrollOffsetKey] += jump;
           }
-        }
+        },
+        getStartOffset
       );
     },
     _dispose() {
@@ -371,33 +421,6 @@ export const createWindowScroller = (
       const window = getCurrentWindow(document);
       const documentBody = document.body;
 
-      const calcOffsetToViewport = (
-        node: HTMLElement,
-        viewport: HTMLElement,
-        isHorizontal: boolean,
-        offset: number = 0
-      ): number => {
-        // TODO calc offset only when it changes (maybe impossible)
-        const offsetKey = isHorizontal ? "offsetLeft" : "offsetTop";
-        const offsetSum =
-          offset +
-          (isHorizontal && isRTLDocument()
-            ? window.innerWidth - node[offsetKey] - node.offsetWidth
-            : node[offsetKey]);
-
-        const parent = node.offsetParent;
-        if (node === viewport || !parent) {
-          return offsetSum;
-        }
-
-        return calcOffsetToViewport(
-          parent as HTMLElement,
-          viewport,
-          isHorizontal,
-          offsetSum
-        );
-      };
-
       scrollObserver = createScrollObserver(
         store,
         window,
@@ -429,7 +452,10 @@ export const createWindowScroller = (
  * @internal
  */
 export type GridScroller = {
-  _observe: (viewportElement: HTMLElement) => void;
+  _observe: (
+    viewportElement: HTMLElement,
+    containerElement: HTMLElement
+  ) => void;
   _dispose(): void;
   _scrollTo: (offsetX: number, offsetY: number) => void;
   _scrollBy: (offsetX: number, offsetY: number) => void;
@@ -447,9 +473,9 @@ export const createGridScroller = (
   const vScroller = createScroller(vStore, false);
   const hScroller = createScroller(hStore, true);
   return {
-    _observe(viewportElement) {
-      vScroller._observe(viewportElement);
-      hScroller._observe(viewportElement);
+    _observe(viewportElement, containerElement) {
+      vScroller._observe(viewportElement, containerElement);
+      hScroller._observe(viewportElement, containerElement);
     },
     _dispose() {
       vScroller._dispose();
diff --git a/src/core/store.ts b/src/core/store.ts
index af183c377..48a6e039b 100644
--- a/src/core/store.ts
+++ b/src/core/store.ts
@@ -140,13 +140,13 @@ export const createVirtualStore = (
   itemSize: number = 40,
   ssrCount: number = 0,
   cacheSnapshot?: CacheSnapshot | undefined,
-  shouldAutoEstimateItemSize: boolean = false,
-  startSpacerSize: number = 0
+  shouldAutoEstimateItemSize: boolean = false
 ): VirtualStore => {
   let isSSR = !!ssrCount;
   let stateVersion: StateVersion = [];
   let viewportSize = 0;
   let scrollOffset = 0;
+  let startOffset = 0;
   let jumpCount = 0;
   let jump = 0;
   let pendingJump = 0;
@@ -165,7 +165,7 @@ export const createVirtualStore = (
     cacheSnapshot as unknown as InternalCacheSnapshot | undefined
   );
   const subscribers = new Set<[number, Subscriber]>();
-  const getRelativeScrollOffset = () => scrollOffset - startSpacerSize;
+  const getRelativeScrollOffset = () => scrollOffset - startOffset;
   const getRange = (offset: number) => {
     return computeRange(cache, offset, _prevRange[0], viewportSize);
   };
@@ -240,7 +240,7 @@ export const createVirtualStore = (
       return viewportSize;
     },
     _getStartSpacerSize() {
-      return startSpacerSize;
+      return startOffset;
     },
     _getTotalSize: getTotalSize,
     _getJumpCount() {
@@ -418,7 +418,7 @@ export const createVirtualStore = (
           break;
         }
         case ACTION_START_OFFSET_CHANGE: {
-          startSpacerSize = payload;
+          startOffset = payload;
           break;
         }
         case ACTION_MANUAL_SCROLL: {
diff --git a/src/core/types.ts b/src/core/types.ts
index 956c2434e..d532ca7d8 100644
--- a/src/core/types.ts
+++ b/src/core/types.ts
@@ -42,3 +42,5 @@ export interface ScrollToIndexOpts {
    */
   offset?: number;
 }
+
+export type StartOffsetType = "dynamic" | "static" | number;
diff --git a/src/react/VGrid.tsx b/src/react/VGrid.tsx
index bfdea797a..823e39e95 100644
--- a/src/react/VGrid.tsx
+++ b/src/react/VGrid.tsx
@@ -25,6 +25,7 @@ import { ViewportComponentAttributes } from "./types";
 import { flushSync } from "react-dom";
 import { isRTLDocument } from "../core/environment";
 import { useRerender } from "./useRerender";
+
 const genKey = (i: number, j: number) => `${i}-${j}`;
 
 /**
@@ -250,9 +251,11 @@ export const VGrid = forwardRef<VGridHandle, VGridProps>(
     const height = getScrollSize(vStore);
     const width = getScrollSize(hStore);
     const rootRef = useRef<HTMLDivElement>(null);
+    const containerRef = useRef<HTMLDivElement>(null);
 
     useIsomorphicLayoutEffect(() => {
       const root = rootRef[refKey]!;
+      const container = containerRef[refKey]!;
       // store must be subscribed first because others may dispatch update on init depending on implementation
       const unsubscribeVStore = vStore._subscribe(
         UPDATE_VIRTUAL_STATE,
@@ -275,7 +278,7 @@ export const VGrid = forwardRef<VGridHandle, VGridProps>(
         }
       );
       resizer._observeRoot(root);
-      scroller._observe(root);
+      scroller._observe(root, container);
       return () => {
         unsubscribeVStore();
         unsubscribeHStore();
diff --git a/src/react/Virtualizer.tsx b/src/react/Virtualizer.tsx
index 4ff19f6d2..7781c425b 100644
--- a/src/react/Virtualizer.tsx
+++ b/src/react/Virtualizer.tsx
@@ -24,7 +24,11 @@ import { useStatic } from "./useStatic";
 import { useLatestRef } from "./useLatestRef";
 import { createResizer } from "../core/resizer";
 import { ListItem } from "./ListItem";
-import { CacheSnapshot, ScrollToIndexOpts } from "../core/types";
+import {
+  CacheSnapshot,
+  ScrollToIndexOpts,
+  StartOffsetType,
+} from "../core/types";
 import { flushSync } from "react-dom";
 import { useRerender } from "./useRerender";
 import { useChildren } from "./useChildren";
@@ -120,8 +124,10 @@ export interface VirtualizerProps {
   cache?: CacheSnapshot;
   /**
    * If you put an element before virtualizer, you have to define its height with this prop.
+   *
+   * TODO
    */
-  startMargin?: number;
+  startOffset?: StartOffsetType;
   /**
    * A prop for SSR. If set, the specified amount of items will be mounted in the initial rendering regardless of the container size until hydrated.
    */
@@ -178,7 +184,7 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(
       shift,
       horizontal: horizontalProp,
       cache,
-      startMargin,
+      startOffset,
       ssrCount,
       as: Element = "div",
       item: ItemElement = "div",
@@ -207,13 +213,12 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(
         itemSize,
         ssrCount,
         cache,
-        !itemSize,
-        startMargin
+        !itemSize
       );
       return [
         _store,
         createResizer(_store, _isHorizontal),
-        createScroller(_store, _isHorizontal),
+        createScroller(_store, _isHorizontal, startOffset),
         _isHorizontal,
       ];
     });
@@ -281,15 +286,16 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(
           onScrollEnd[refKey] && onScrollEnd[refKey]();
         }
       );
+      const container = containerRef[refKey]!;
       const assignScrollableElement = (e: HTMLElement) => {
         resizer._observeRoot(e);
-        scroller._observe(e);
+        scroller._observe(e, container);
       };
       if (scrollRef) {
         // parent's ref doesn't exist when useLayoutEffect is called
         microtask(() => assignScrollableElement(scrollRef[refKey]!));
       } else {
-        assignScrollableElement(containerRef[refKey]!.parentElement!);
+        assignScrollableElement(container.parentElement!);
       }
 
       return () => {
diff --git a/src/solid/Virtualizer.tsx b/src/solid/Virtualizer.tsx
index d0623fc2d..5b3fe70c7 100644
--- a/src/solid/Virtualizer.tsx
+++ b/src/solid/Virtualizer.tsx
@@ -225,7 +225,7 @@ export const Virtualizer = <T,>(props: VirtualizerProps<T>): JSX.Element => {
 
     const scrollable = containerRef!.parentElement!;
     resizer._observeRoot(scrollable);
-    scroller._observe(scrollable);
+    scroller._observe(scrollable, containerRef!);
 
     onCleanup(() => {
       if (props.ref) {
diff --git a/src/svelte/VList.svelte b/src/svelte/VList.svelte
index c8dfde8d6..5ed366857 100644
--- a/src/svelte/VList.svelte
+++ b/src/svelte/VList.svelte
@@ -123,8 +123,9 @@
   );
 
   onMount(() => {
+    const container = containerRef!;
     const root = containerRef.parentElement!;
-    virtualizer[ON_MOUNT](root);
+    virtualizer[ON_MOUNT](root, container);
   });
   onDestroy(() => {
     virtualizer[ON_UN_MOUNT]();
diff --git a/src/svelte/core.ts b/src/svelte/core.ts
index 0ddfbdd4c..9b2a0c86c 100644
--- a/src/svelte/core.ts
+++ b/src/svelte/core.ts
@@ -73,9 +73,9 @@ export const createVirtualizer = (
   );
 
   return {
-    [ON_MOUNT]: (scrollable: HTMLElement) => {
+    [ON_MOUNT]: (scrollable: HTMLElement, container: HTMLElement) => {
       resizer._observeRoot(scrollable);
-      scroller._observe(scrollable);
+      scroller._observe(scrollable, container);
     },
     [ON_UN_MOUNT]: () => {
       unsubscribeStore();
diff --git a/src/vue/Virtualizer.tsx b/src/vue/Virtualizer.tsx
index 280490e39..a6d805ed0 100644
--- a/src/vue/Virtualizer.tsx
+++ b/src/vue/Virtualizer.tsx
@@ -24,7 +24,7 @@ import {
 } from "../core/store";
 import { createResizer } from "../core/resizer";
 import { createScroller } from "../core/scroller";
-import { ScrollToIndexOpts } from "../core/types";
+import { ScrollToIndexOpts, StartOffsetType } from "../core/types";
 import { ListItem } from "./ListItem";
 import { getKey } from "./utils";
 import { microtask } from "../core/utils";
@@ -92,8 +92,10 @@ const props = {
   horizontal: Boolean,
   /**
    * If you put an element before virtualizer, you have to define its height with this prop.
+   *
+   * TODO
    */
-  startMargin: Number,
+  startOffset: [String, Number] as PropType<StartOffsetType>,
   /**
    * A prop for SSR. If set, the specified amount of items will be mounted in the initial rendering regardless of the container size until hydrated.
    */
@@ -117,11 +119,10 @@ export const Virtualizer = /*#__PURE__*/ defineComponent({
       props.itemSize ?? 40,
       props.ssrCount,
       undefined,
-      !props.itemSize,
-      props.startMargin
+      !props.itemSize
     );
     const resizer = createResizer(store, isHorizontal);
-    const scroller = createScroller(store, isHorizontal);
+    const scroller = createScroller(store, isHorizontal, props.startOffset);
 
     const rerender = ref(store._getStateVersion());
     const unsubscribeStore = store._subscribe(UPDATE_VIRTUAL_STATE, () => {
@@ -142,15 +143,16 @@ export const Virtualizer = /*#__PURE__*/ defineComponent({
       isSSR = false;
 
       microtask(() => {
+        const container = containerRef.value!;
         const assignScrollableElement = (e: HTMLElement) => {
           resizer._observeRoot(e);
-          scroller._observe(e);
+          scroller._observe(e, container);
         };
         if (props.scrollRef) {
           // parent's ref doesn't exist when onMounted is called
           assignScrollableElement(props.scrollRef!);
         } else {
-          assignScrollableElement(containerRef.value!.parentElement!);
+          assignScrollableElement(container.parentElement!);
         }
       });
     });
diff --git a/stories/react/basics/Virtualizer.stories.tsx b/stories/react/basics/Virtualizer.stories.tsx
index fb4a037cf..28afe2920 100644
--- a/stories/react/basics/Virtualizer.stories.tsx
+++ b/stories/react/basics/Virtualizer.stories.tsx
@@ -38,7 +38,6 @@ const createRows = (num: number) => {
 
 export const HeaderAndFooter: StoryObj = {
   render: () => {
-    const headerHeight = 400;
     return (
       <div
         style={{
@@ -49,19 +48,63 @@ export const HeaderAndFooter: StoryObj = {
           overflowAnchor: "none",
         }}
       >
-        <div style={{ backgroundColor: "burlywood", height: headerHeight }}>
-          header
-        </div>
-        <Virtualizer startMargin={headerHeight}>{createRows(1000)}</Virtualizer>
+        <div style={{ backgroundColor: "burlywood", height: 400 }}>header</div>
+        <Virtualizer startOffset="static">{createRows(1000)}</Virtualizer>
         <div style={{ backgroundColor: "steelblue", height: 600 }}>footer</div>
       </div>
     );
   },
 };
 
+const createColumns = (num: number) => {
+  return Array.from({ length: num }).map((_, i) => {
+    return (
+      <div
+        key={i}
+        style={{
+          width: i % 3 === 0 ? 100 : 60,
+          borderRight: "solid 1px #ccc",
+          background: "#fff",
+        }}
+      >
+        Column {i}
+      </div>
+    );
+  });
+};
+
+export const HeaderAndFooterHorizontal: StoryObj = {
+  render: () => {
+    const ref = useRef<HTMLDivElement>(null);
+    return (
+      <div
+        ref={ref}
+        style={{
+          width: "100%",
+          height: "400px",
+          overflowX: "auto",
+          // opt out browser's scroll anchoring on header/footer because it will conflict to scroll anchoring of virtualizer
+          overflowAnchor: "none",
+        }}
+      >
+        <div style={{ display: "flex", height: "100%" }}>
+          <div style={{ backgroundColor: "burlywood", minWidth: 400 }}>
+            header
+          </div>
+          <Virtualizer horizontal startOffset="static" scrollRef={ref}>
+            {createColumns(1000)}
+          </Virtualizer>
+          <div style={{ backgroundColor: "steelblue", minWidth: 600 }}>
+            footer
+          </div>
+        </div>
+      </div>
+    );
+  },
+};
+
 export const StickyHeaderAndFooter: StoryObj = {
   render: () => {
-    const headerHeight = 40;
     return (
       <div
         style={{
@@ -76,14 +119,14 @@ export const StickyHeaderAndFooter: StoryObj = {
           style={{
             position: "sticky",
             backgroundColor: "burlywood",
-            height: headerHeight,
+            height: 40,
             top: 0,
             zIndex: 1,
           }}
         >
           header
         </div>
-        <Virtualizer startMargin={headerHeight}>{createRows(1000)}</Virtualizer>
+        <Virtualizer startOffset="static">{createRows(1000)}</Virtualizer>
         <div
           style={{
             position: "sticky",
@@ -99,11 +142,40 @@ export const StickyHeaderAndFooter: StoryObj = {
   },
 };
 
+export const Padding: StoryObj = {
+  render: () => {
+    const ref = useRef<HTMLDivElement>(null);
+
+    return (
+      <div
+        ref={ref}
+        style={{
+          width: "100%",
+          height: "100vh",
+          overflowY: "auto",
+          // opt out browser's scroll anchoring on header/footer because it will conflict to scroll anchoring of virtualizer
+          overflowAnchor: "none",
+        }}
+      >
+        <div
+          style={{
+            paddingTop: 400,
+            paddingBottom: 400,
+          }}
+        >
+          <Virtualizer scrollRef={ref} startOffset="static">
+            {createRows(1000)}
+          </Virtualizer>
+        </div>
+      </div>
+    );
+  },
+};
+
 export const Nested: StoryObj = {
   render: () => {
     const ref = useRef<HTMLDivElement>(null);
-    const outerPadding = 40;
-    const innerPadding = 60;
+
     return (
       <div
         ref={ref}
@@ -115,12 +187,9 @@ export const Nested: StoryObj = {
           overflowAnchor: "none",
         }}
       >
-        <div style={{ backgroundColor: "burlywood", padding: outerPadding }}>
-          <div style={{ backgroundColor: "steelblue", padding: innerPadding }}>
-            <Virtualizer
-              scrollRef={ref}
-              startMargin={outerPadding + innerPadding}
-            >
+        <div style={{ backgroundColor: "burlywood", padding: 40 }}>
+          <div style={{ backgroundColor: "steelblue", padding: 60 }}>
+            <Virtualizer scrollRef={ref} startOffset="static">
               {createRows(1000)}
             </Virtualizer>
           </div>
@@ -179,8 +248,6 @@ export const BiDirectionalInfiniteScrolling: StoryObj = {
       ready.current = true;
     }, []);
 
-    const spinnerHeight = 100;
-
     return (
       <div
         style={{
@@ -190,14 +257,11 @@ export const BiDirectionalInfiniteScrolling: StoryObj = {
           overflowAnchor: "none",
         }}
       >
-        <Spinner
-          height={spinnerHeight}
-          style={startFetching ? undefined : { visibility: "hidden" }}
-        />
+        <Spinner style={startFetching ? undefined : { visibility: "hidden" }} />
         <Virtualizer
           ref={ref}
+          startOffset="static"
           shift={shifting ? true : false}
-          startMargin={spinnerHeight}
           onRangeChange={async (start, end) => {
             if (!ready.current) return;
             if (end + THRESHOLD > count && endFetchedCountRef.current < count) {
@@ -219,10 +283,7 @@ export const BiDirectionalInfiniteScrolling: StoryObj = {
         >
           {items}
         </Virtualizer>
-        <Spinner
-          height={spinnerHeight}
-          style={endFetching ? undefined : { visibility: "hidden" }}
-        />
+        <Spinner style={endFetching ? undefined : { visibility: "hidden" }} />
       </div>
     );
   },
@@ -349,12 +410,7 @@ export const TableElement: StoryObj = {
           overflow: "auto",
         }}
       >
-        <Virtualizer
-          count={1000}
-          as={Table}
-          item="tr"
-          startMargin={TABLE_HEADER_HEIGHT}
-        >
+        <Virtualizer count={1000} as={Table} item="tr" unbound>
           {(i) => (
             <Fragment key={i}>
               {COLUMN_WIDTHS.map((width, j) => (
diff --git a/stories/react/common.tsx b/stories/react/common.tsx
index 320fe7ab2..3a60e2fb1 100644
--- a/stories/react/common.tsx
+++ b/stories/react/common.tsx
@@ -8,17 +8,15 @@ export const delay = (ms: number) =>
 
 export const Spinner = ({
   style,
-  height = 100,
 }: {
   style?: CSSProperties;
-  height?: number;
 }) => {
   return (
     <>
       <div
         style={{
           ...style,
-          height: height,
+          height: 100,
           display: "flex",
           alignItems: "center",
           justifyContent: "center",
diff --git a/stories/vue/HeaderAndFooter.vue b/stories/vue/HeaderAndFooter.vue
index 3ee0766b0..bb50b7e57 100644
--- a/stories/vue/HeaderAndFooter.vue
+++ b/stories/vue/HeaderAndFooter.vue
@@ -5,8 +5,6 @@ const sizes = [20, 40, 180, 77];
 const createItem = (i: number) => ({ index: i, size: sizes[i % 4] + 'px' })
 
 const data = Array.from({ length: 1000 }).map((_, i) => createItem(i));
-
-const headerHeight = 400;
 </script>
 
 <template>
@@ -17,10 +15,10 @@ const headerHeight = 400;
     // opt out browser's scroll anchoring on header/footer because it will conflict to scroll anchoring of virtualizer
     overflowAnchor: 'none'
   }">
-    <div :style="{ backgroundColor: 'burlywood', height: headerHeight + 'px' }">
+    <div :style="{ backgroundColor: 'burlywood', height: '400px' }">
       header
     </div>
-    <Virtualizer :data="data" #default="item" :startMargin="headerHeight">
+    <Virtualizer :data="data" #default="item" :startOffset="'static'">
       <div :key="item.index" :style="{ height: item.size, background: 'white', borderBottom: 'solid 1px #ccc' }">
         {{ item.index }}
       </div>
diff --git a/stories/vue/Nested.vue b/stories/vue/Nested.vue
index b957e349b..8cadf77c7 100644
--- a/stories/vue/Nested.vue
+++ b/stories/vue/Nested.vue
@@ -7,8 +7,6 @@ const createItem = (i: number) => ({ index: i, size: sizes[i % 4] + 'px' })
 
 const data = Array.from({ length: 1000 }).map((_, i) => createItem(i));
 
-const outerPadding = 40;
-const innerPadding = 60;
 const scrollRef = ref<HTMLElement>();  
 </script>
 
@@ -20,9 +18,9 @@ const scrollRef = ref<HTMLElement>();
     // opt out browser's scroll anchoring on header/footer because it will conflict to scroll anchoring of virtualizer
     overflowAnchor: 'none'
   }">
-    <div :style="{ backgroundColor: 'burlywood', padding: outerPadding + 'px' }">
-      <div :style="{ backgroundColor: 'steelblue', padding: innerPadding + 'px' }">
-        <Virtualizer :data="data" #default="item" :scrollRef="scrollRef" :startMargin="outerPadding + innerPadding">
+    <div :style="{ backgroundColor: 'burlywood', padding: '60px' }">
+      <div :style="{ backgroundColor: 'steelblue', padding: '40px' }">
+        <Virtualizer :data="data" #default="item" :scrollRef="scrollRef" :startOffset="'static'">
           <div :key="item.index" :style="{ height: item.size, background: 'white', borderBottom: 'solid 1px #ccc' }">
             {{ item.index }}
           </div>