Testing a button that lost its CSS
| Symptom | |
| Check the served stylesheet | |
| Check computed styles | |
| Add a regression test | |
| Root cause in this repository | |
| Checklist |
Symptom: the markup is there, the styling is not
A CSS regression does not remove the button from the DOM.
The link is still clickable, the href still points to an
anchor, and the HTML still contains class="toTopButton".
What disappears is the box that makes the control look and behave like
a button.
Typical signs are:
- the control collapses to the size of its text or arrow;
- it sits in the document flow instead of a fixed corner;
- background, border, radius and shadow are gone;
- hover feedback and responsive hiding stop working.
The example in this article is the pair of controls on /misc/w11/ . The page uses .toTopButton and .toBottomButton inside .verticalNavButtonsDiv. In the 2026-10-20 regression the controls rendered as two bare arrows in the left column instead of fixed buttons at the bottom of the viewport.
First check: is the rule in the served stylesheet?
The browser can only apply rules that are present in the CSS file it actually downloaded. Start with the served file, not with the source tree. Count the selector in the sheet loaded by the page:
curl -sS http://127.0.0.1:8080/.css/output/aredel.css | grep -c toTopButton
0
Zero means the page received a stylesheet without a
.toTopButton rule. On the broken page this was the result.
After the fix the same command returns a positive count.
Also confirm that the stylesheet itself is served:
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/.css/output/aredel.css
200
A 200 response with a zero selector count points to the build, not to the web server. A 404 points to the link, the rewrite rules, or a missing output file.
Second check: inspect computed styles
The served file can contain a selector while the page still ignores it because the class name is misspelled, the rule is overridden, or a media query hides the control. Inspect the element in DevTools and read the computed values, not only the matched rules. The same check can be run from the console:
const button = document.querySelector(".toTopButton"); const style = getComputedStyle(button); const box = button.getBoundingClientRect(); console.log({ display: style.display, position: style.position, background: style.backgroundColor, borderTop: style.borderTopWidth, boxShadow: style.boxShadow, width: box.width, height: box.height });
On the healthy page the important values are:
- .verticalNavButtonsDiv has position: fixed and sits near the bottom of the viewport;
- each button has display: inline-block and position: relative;
- background-color is not transparent;
- border-top-width is at least 1px;
- box-shadow is not none;
- width and height are large enough to contain the arrow and padding.
On the broken page the same expression returned display: inline,
position: static, a transparent background, a zero border
and box-shadow: none. The controls were 13 by 17 pixels and
stayed in the page flow.
Repeat the check at the breakpoints that matter. These buttons are shown
on desktop widths, move at 600px to
800px, and are hidden at 599px and below.
A test at one width only can miss a broken media query.
Third check: turn the observation into a regression test
A manual computed-style check is enough to diagnose one page. Add a test
so the same regression cannot return unnoticed. The test for this page is
container/tests/ui/buttons_css_test.py. It opens
/misc/w11/, reads computed styles with Playwright, and
asserts the button chrome, the fixed container, the anchor targets, and
the mobile hiding rule.
Run it from the container/ directory against a server that
serves the current source tree and built CSS:
pytest tests/ui/buttons_css_test.py -v
Before the CSS fix the test must fail. If it passes on the broken page, the test is checking the wrong property. After the fix it must pass at both the desktop and mobile widths. Keep the failure visible: do not weaken the assertion or skip the case to get a green run.
Root cause in this repository
The old hand-maintained aredel.css contained these rules,
but the current sheet is assembled by
container/tools/css/build-css.sh from
source/core/core.css plus shared partials and a
site-specific file. The editable source
source/_to_top_button.css existed, but it was not listed in
container/tools/css/targets.conf. The build never read it,
so the served stylesheet was missing the selectors even though the
source file was present.
The fix is to list the partial in each target that needs it, after the
shared layout partials:
aredel output/aredel.css source/core/core.css source/_homeblock.css source/_asides.css source/_to_top_button.css source/sites/aredel/site_specific.css
Then rebuild the served sheets:
container/tools/css/build-css.sh
Do not edit .css/output/*.css by hand. The output is a build artifact; the next rebuild would overwrite the edit. Also run container/tools/css/build-css.sh --check before committing to confirm that every output matches its sources.
Checklist
- the markup is present and the class names match the selectors;
- the stylesheet responds with 200 and contains the selector;
- computed styles show the expected box, position and hover state;
- the control is checked at desktop and mobile breakpoints;
- the anchor targets used by the links exist;
- a regression test fails before the fix and passes after it;
- the CSS source is listed in targets.conf and the output is rebuilt with build-css.sh.
Article author: Andrei Olegovich
| Software Testing | |
| UI Basic Test Page | |
| API Testing Lessons |