Skip to content

(style): #main :has() rules make each terminal switch force ~2 s of style recalc #541

Closed

Description

@devsuitup

Two :has() rules added by #511 (#506) to public/style.css make every DOM insertion under #main invalidate style on the whole subtree:

  • style.css:5543 #main:has(#terminal-area:not([style*="display: none"])) { min-width: var(--tool-main-floor) }
  • style.css:5547 #main:has(#terminal-area:not([style*="display: none"]) #file-panel.open) { min-width: min(...) }

Measured live on main a02f96c (isolated test instance, 5 terminals with 30,000 lines each):

  • Each tab switch was one ~2 s long animation frame, almost all of it style and layout (styleAndLayoutStart ≈ 1.9 s, no script attribution).
  • CPU profile: 2163 ms of self time in xterm's CharSizeService _measure. Stack: showSession → suspendTerminalWebgl → WebGL addon dispose → DOM renderer renderRows → 59 × createRow → _measure.
  • Every row forces a synchronous layout, and the :has() rules make each forced recalc cost 25–35 ms.
Live stylesheet Switch times (ms)
As shipped 2052, 2242, 2079, 2217
Both rules removed 86, 81, 84, 89
Only the first rule 1841, 1815, 2079
Only the second rule 1417, 1361, 1600

Before #511: 67–79 ms.

#532 hides most of it by keeping three warm WebGL contexts, but any path that still builds DOM rows under #main pays the cost: a cold terminal, a fourth terminal beyond the warm cap, the grid.

Fix: drive the two rules from a class toggled where #terminal-area display and #file-panel.open already change, e.g. #main.terminal-area-shown and #main.terminal-area-shown.file-panel-open, and drop :has() on #main. Keep the min-width behaviour #506 wanted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions