Skip to content

CSS: apply position: relative with top / left / right / bottom offsets #34

Closed

Description

@vietnguyentuan2019

Current behaviour

position is stored in ComputedStyle but nothing in the render path reads it, so position: relative with top / left / right / bottom does not move the element. (absolute / fixed are out of scope for the single-RenderObject design; see doc/LIMITATIONS.md.)

Expected

A position: relative element is laid out in normal flow, then painted (and hit-tested, and selected) shifted by its offsets, without affecting the layout of its siblings.

Notes

  • Docs already say "not applied" (doc/CSS_PROPERTIES_MATRIX.md, doc/SUPPORTED_HTML.md, doc/LIMITATIONS.md); test/docs_matrix_sync_test.dart pins the row as not ✅. Flip them together with the implementation.
  • Selection and hit-testing read fragment.offset, so a paint-only shift would draw text where hit-testing and selection handles do not find it. Either apply the shift to fragment offsets after layout, or shift paint, hit-test and selection together.
  • Inline relative spans (e.g. sup-style tweaks) and block relative containers behave differently; decide the scope first.
  • Add a pixel or fragment-offset test, not just a no-exception test.

Activity

  1. vietnguyentuan2019 commented on Nov 4, 2026

    @vietnguyentuan2019
    ContributorAuthor

    Looked into this. A correction first: position and top / left / right / bottom aren't parsed today, the field always stays static.

    Shifting fragment.offset alone isn't enough. Hit-testing, selection and paint culling all find the line by y first, so text moved vertically into another line's band couldn't be clicked, and might not be painted.

    Plan: cover both block and inline relative, applied as a post-layout pass that leaves sibling layout and box height unchanged, with hit-testing, selection and culling updated to match. Flex and grid items use Transform.translate.

    Known limits for this round:

    • % offsets aren't supported.
    • Content is clipped to the render box, so untrusted HTML can't paint over the host app. The sanitizer doesn't filter CSS properties, so this matters.
    • A relative element's background still paints below normal text, because there's no stacking context.
  2. vietnguyentuan2019 commented on Nov 5, 2026

    @vietnguyentuan2019
    ContributorAuthor

    Correction to my earlier comment: I said moved content is clipped to the render box, so untrusted HTML can't paint over the host app. Review of PR #36 showed that wasn't true yet. Flex and grid items and moved block backgrounds could still escape.

    That's now fixed in the PR and covered by pixel tests. Moved content paints in its own clipped pass above normal content, so other content isn't cropped. This also removes a limit I listed: a relative element's background now paints above normal text.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions