offsetLeft property

double get offsetLeft

Implementation

double get offsetLeft {
  double offset = 0.0;
  if (!isRendererAttached) {
    return offset;
  }
  Element? offsetParent = this.offsetParent;
  RenderBoxModel? ancestor = offsetParent?.attachedRenderer;
  if (offsetParent?.hasScroll == true) {
    ancestor = offsetParent?.attachedRendererWrapper;
  }

  // For sticky positioned elements with body as offsetParent,
  // we need to account for scroll position
  if (renderStyle.position == CSSPositionType.sticky &&
      offsetParent is BodyElement) {
    // For sticky elements, we need to calculate their position including scroll
    // Get total scroll offset by checking all scroll containers
    double totalScrollX = 0.0;

    // Check if documentElement has scroll
    Element? docElement = ownerDocument.documentElement;
    if (docElement != null && docElement.attachedRenderer != null) {
      totalScrollX = docElement.scrollLeft;
    }

    // If no scroll on documentElement, check body
    if (totalScrollX == 0.0) {
      Element? body = ownerDocument.documentElement?.querySelector(['body']);
      if (body != null && body.attachedRenderer != null) {
        totalScrollX = body.scrollLeft;
      }
    }

    // Get the sticky element's current position relative to the viewport
    RenderBoxModel? renderer = attachedRenderer;
    if (renderer != null && renderer.hasSize) {
      // For sticky elements, we need to calculate their actual visual position
      // Get the position placeholder to find original position
      RenderPositionPlaceholder? placeholder =
          renderStyle.getSelfPositionPlaceHolder();
      if (placeholder != null && placeholder.attached) {
        // Get the placeholder's position (original position before sticky)
        Offset placeholderOffset = placeholder.getOffsetToAncestor(
            Offset.zero, offsetParent.attachedRenderer!,
            excludeScrollOffset: true);

        // Calculate where the element should be without sticky
        double naturalPosition = placeholderOffset.dx - totalScrollX;

        // Get sticky constraints
        double stickyLeft = renderStyle.left.computedValue;

        // Check if element should be stuck
        if (naturalPosition < stickyLeft) {
          // Element should be stuck at sticky position
          return totalScrollX + stickyLeft;
        } else {
          // Element is in its natural position
          return placeholderOffset.dx;
        }
      }

      // Fallback: calculate based on current visual position
      RenderBox? viewport = getRootViewport();
      if (viewport != null) {
        // Get position relative to viewport
        Offset viewportOffset =
            renderer.localToGlobal(Offset.zero, ancestor: viewport);

        // For sticky elements, we need to handle the case where they're stuck
        // If the element is at its sticky position (e.g., left: 50px), it's stuck
        if (viewportOffset.dx == renderStyle.left.computedValue) {
          // Element is stuck at its sticky position
          return totalScrollX + viewportOffset.dx;
        } else {
          // Element is not stuck, calculate its natural position
          return viewportOffset.dx + totalScrollX;
        }
      }
    }
  }

  Offset relative = renderStyle.getOffset(
      ancestorRenderBox: ancestor, excludeScrollOffset: true);
  offset += relative.dx;
  return offset;
}