v6.0.0-alpha.1: :has() control-state rules cause multi-second style recalculation on pages with many form controls (switch/check/radio/range/form-field)

Aperta
#43,003 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
15/100
Tipo di issue
Bug
Chiarezza
Da chiarire
Stato di attività
Attiva
Stack tecnologico
bootstrap, css

Direzione di ricerca

The report names the :has() control-state selectors in bootstrap.css, such as :has(input:checked), :has(input:disabled) and :has(.check:checked), and says the cost appears when a theme variable or the html attribute changes. Start by building a repro that reproduces the slowdown, since the reporter's minimal page did not, by varying control count, nesting and checked/disabled state. Done means a reproduction that shows the cost and a measured explanation of which rules cause it.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug css performance utility-api v6

Summary

On a real admin page that uses Bootstrap 6.0.0-alpha.1, changing one attribute on takes about 12 seconds before the next frame is painted. Removing only the Bootstrap rules that use :has() on form controls brings the same change down to about 1.9 seconds. Removing our own :has() rules changes nothing.

I have not yet reproduced this on a minimal page that uses only Bootstrap's stylesheet, so I am reporting it as a measured regression on a real page, with the page-level evidence below. I would welcome guidance on how to build a smaller repro.

Environment

Bootstrap: 6.0.0-alpha.1 (npm, [email protected])
Browser: Google Chrome (stable), Windows 11
Page: an admin dashboard with a sidebar, a topbar, a customizer panel (a drawer with radio inputs, switches, checkboxes and a range), and several cards containing form fields and tables
Stylesheet size: the compiled admin CSS contains about 130 :has() selectors, about 107 of them from Bootstrap

Steps to reproduce (on our page)

Open the page.
Open the customizer and click a different accent swatch (this changes data-accent on , which changes a set of custom properties used across the page).
Measure the time from the click to the next painted frame (two requestAnimationFrame callbacks after the click).

Measured results

Time from click to next painted frame, one accent change, 1440x900, median of repeated runs:

Condition Click-to-paint
Unmodified page about 12,800 ms
Only our own :has() rules removed (61 rules) about 12,850 ms
Only Bootstrap's :has() rules removed (107 rules) about 1,940 ms
Other measurements from the same page:

Removing only the validation-state rules (.is-invalid, .is-valid, :user-invalid, :user-valid): no change (about 12,600 ms).
Removing only the rules for switch, check, radio, range, form-field, form-adorn, chip-input and form-ghost: about 2,050 ms.
Page load to DOMContentLoaded on the same page: about 9 s (Bootstrap 5.3.8 on the same page: about 1.8 s).

Observations

The cost comes from a few hundred :has() selectors that test form-control state (for example :has(input:checked), :has(input:disabled), :has(.check:checked)) on ancestors such as form fields and switch wrappers.
Every time the accent changes, many custom properties change. Each element with a matching :has() rule then has to be re-checked, which is where the time goes.
The same family is present in Bootstrap 5.3.8 in a different form, but on this page 5.3.8 does not show the delay.

What I tried to reproduce it minimally, and what happened

I built a page with 2,000 .form-field > .check checkboxes, loaded only bootstrap.css from 6.0.0-alpha.1, and measured a click that changes an attribute on and a click that changes --primary-bg on . The click-to-paint time was about 6 to 13 ms for the attribute change and about 110 to 125 ms for the variable change, with and without the :has() rules. So the minimal page does not show the regression. The difference must come from something the minimal page lacks: the number and nesting of controls, the :checked / :disabled state of the matched inputs, or the variables that change. I have not identified which, and I'd value the maintainers' view.

Expected

Changing a theme variable or an attribute on should not take seconds on a page with a few thousand form controls.

Actual

About 12 seconds to the next painted frame on our page, reduced to about 2 seconds when Bootstrap's control-state :has() rules are not present.

Notes

I can share the page and the measuring script on request.
We are considering changing our own markup to set state classes from JavaScript, so this may be a non-issue for us in the long run, but the Bootstrap rules remain in the stylesheet for everyone else.

Lingua principale
MDX
Stelle
175k
Fork
78.7k
Merge medio
1g 10h
PR unite (30g)
98

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di twbs/bootstrap

Tutte le issue di twbs/bootstrap

Issue simili

Altre issue su Web Dev

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.