How should the Site Converter carry a source button's hover animation — reproduce its CSS verbatim, or classify it into the theme's named hover-effect vocabulary?
The question: A converted button (scandi-haven-shop's hero "Shop Now") dropped its hover
animation — a translucent overlay that rises from the bottom to fill the button. The effect lives
entirely on .btn-premium::after + .btn-premium:hover::after, which getComputedStyle(el) never
exposes. Once we teach the capture to harvest those rules, what do we DO with them: reproduce the
source CSS verbatim on the button, or map it to one of the theme's named hover-effect presets?
Context. The button shortcode already ships a hover_animation field backed by ~35 named
.btnfx-* effects (fill-up, fill-right, fill-center, grow, lift, sweep, shine, glow,
underline, tilt, skew, rotate, …) in hover-fx.css. So the theme has a real, finite
vocabulary of hover motions — the same kind of native target the converter already maps colours and
sizes onto. The scandi effect (::after overlay, translateY(100%) → 0 on hover) is visually
identical to btnfx-fill-up (::before overlay, scaleY(0) → 1 from the bottom edge) even though
the underlying CSS differs.
Two structural facts shaped the decision:
- Computed styles can't see it. The earlier "stamp
transition/transformon every element" fix still wouldn't catch this — hover motion is a:hover+ pseudo-element phenomenon, invisible togetComputedStyle. So either answer needs a new capture capability: harvest the stylesheet rules whose selectors match a button's own classes in their:hover/::before/::aftervariants. - Tailwind transforms are composed from
--tw-*vars. The rawtransform:translate(var(--tw-…))is meaningless without the vars, so "verbatim" isn't even literally verbatim — it needs reconstruction.
Options considered.
- Reproduce verbatim, always. Carry the source
::before/::after/:hoverrules onto the button, rewritten to{{SELECTOR}}. Pro: pixel-faithful to any effect. Con: produces opaque, un-editable CSS blobs on every button; fights the theme's own hover system; brittle across framework-specific idioms (Tailwind var composition, keyframes, custom properties that don't resolve in the child theme). The user can never pick a different effect from a dropdown — they inherit a frozen CSS lump. - Classify into a
btnfx-*preset, verbatim only as a fallback. Fingerprint the harvested rules against the finite effect vocabulary; sethover_animation: btnfx-fill-upwhen a signature matches; carry reconstructed verbatim CSS only when nothing is close. Pro: the result is a real, editable Theme-Settings value; consistent with how the converter maps colours/sizes to presets; the classifier is a closed, deterministic problem (bucket into ~35 known shapes, not "reproduce arbitrary CSS"). Con: needs a signature per effect; a novel effect falls through to the blob. - Do nothing — treat hover animation as out of scope because it isn't in the computed style. Rejected outright: the whole point is fidelity, and the effect is a prominent part of the design.
Decision. Classify first, reproduce as a fallback. Capture harvests each button's own-class
hover/pseudo rules into data-sc-hover; classify_hover_animation() fingerprints them into the
nearest .btnfx-* preset (overlay-reveal direction → fill-up/fill-right/fill-center;
element-level scale/translateY/skew/rotate/shadow → grow/lift/skew/rotate/glow;
growing ::after bar → underline); when no signature matches but the source did declare a hover
effect, the rules are reconstructed (rebuilding transform from the --tw-* vars) and emitted as
{{SELECTOR}}-scoped Custom CSS. Every button therefore either gets a named, editable preset or
an exact reproduction — never a dropped animation.
Why. The theme owning a finite, named hover vocabulary is exactly what makes the deterministic
approach stronger than verbatim here: classification into a closed set is tractable and produces a
first-class Theme-Settings value the user can re-pick, restyle or turn off — whereas a verbatim blob
is a dead end. The verbatim path still exists as a safety net so bespoke effects aren't lost, which
means the classifier can stay conservative (only fire on high-confidence signatures) without ever
sacrificing fidelity. And the capture capability it required — "the CSS rules for an element's own
classes, including states and pseudo-elements" — is the same primitive the mega-menu detection
needs (JS-mounted dropdown panels), so the investment compounds. Verified end-to-end: the scandi
"Shop Now" button classifies to btnfx-fill-up, and its two outline siblings (a hover
background-colour change, no preset match) reproduce verbatim.
