1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
"""
The first band's opaque ring falls on page background, never on page content.
A pinned band paints a ring of page colour around itself, `--band-margin` wide,
so the gap it keeps in the flow is still there once it pins and nothing shifts
at the moment it does (style.css, "Sticky chrome"). The ring is drawn on all
four sides — it has to be, or the corners a border radius leaves stay
transparent and a row slides visibly through them.
So a band needs that much clearance *above* it as well as below. Every band but
the first has it for free: what is above it is the band it pins under, at a
higher z-index, which a ring cannot paint over. The first band has the page's
own content above it, and for a while nothing made the two agree — the
join-code form under a group's title leaves 12px, the tab bar's ring is 16px,
and the form came back with the bottom 4px of its field and its button painted
over. Reported as "the form is slightly cut off", which is exactly what it
looks like and says nothing about a stylesheet to whoever reports it.
Both halves are asserted, and the second is the one with teeth. A margin-top on
a *lower* band is not a harmless extra: the gap between two bands is the upper
one's `--band-margin` and nothing else — the number `--chrome-h` carries and
the offset the lower band pins at — and two adjoining margins collapse to the
larger, so a lower band's own margin-top wins wherever it is bigger and leaves
the flow a couple of pixels wider than the pinned layout. That is what writing
this rule for all six bands did, in every media view at every phone width,
before `test_sticky_header.py` measured it.
Read out of the stylesheet rather than measured in a browser, deliberately.
A browser shows the 4px at one width, in one of the states that happen to put
something above a band; what has to hold is which bands are in which of two
lists, and that is a fact about the source. `docs/MESHBAY_DESIGN.md` §9.2 sends
the author of a new application here to make its toolbar pin, and this is what
says whether the toolbar they add needs the gap — it does not, and it must not
have it.
"""
import re
from pathlib import Path
import pytest
STYLE = (Path(__file__).resolve().parents[1] / "src" / "meshbay_hub"
/ "static" / "style.css")
pytestmark = pytest.mark.skipif(not STYLE.exists(),
reason="the stylesheet is not in this checkout")
COMMENT = re.compile(r"/\*.*?\*/", re.S)
RULE = re.compile(r"([^{}]+)\{([^{}]*)\}", re.S)
# `.sticky-chrome > .group-tabs` and `.sticky-chrome > * + .group-tabs` name the
# same band; which of them is written says which list the band is in.
BAND = re.compile(r"^\.sticky-chrome\s*>\s*(?:\*\s*\+\s*)?(\S+)$")
def _bands(declares) -> set[str]:
"""The bands named by every rule whose body `declares` says yes to."""
source = COMMENT.sub("", STYLE.read_text(encoding="utf-8"))
found = set()
for selectors, body in RULE.findall(source):
if not declares(body):
continue
for selector in selectors.split(","):
match = BAND.match(" ".join(selector.split()))
if match:
found.add(match.group(1))
return found
def _ringed() -> set[str]:
return _bands(lambda body: "box-shadow" in body
and "var(--band-margin)" in body)
def _first_bands() -> set[str]:
"""The bands that pin against the navigation bar rather than another band.
`top: var(--nav-h)` on its own, where every band below one of these pins at
a `calc()` that adds the heights above it.
"""
return _bands(lambda body: re.search(
r"top:\s*var\(--nav-h\)\s*;", body))
def _gapped() -> set[str]:
return _bands(lambda body: re.search(
r"margin-top:\s*var\(--band-margin\)", body))
def test_the_band_under_the_navigation_bar_reserves_the_gap_its_ring_needs():
ringed, first = _ringed(), _first_bands()
assert ringed and first, (
"no band paints a ring, or none pins against the navigation bar — "
"either the mechanism is gone, in which case this test should be too, "
"or it was renamed and nothing here is being checked")
unguarded = sorted((ringed & first) - _gapped())
assert not unguarded, (
"these bands have the page's own content above them and paint a ring "
"of page colour on all four sides, but nothing keeps that much room "
"above them, so the ring lands on the content: " + ", ".join(unguarded))
def test_no_band_under_another_band_reserves_one():
"""The gap between two bands is the upper one's, and only the upper one's."""
lower = sorted(_gapped() - _first_bands())
assert not lower, (
"these bands pin under another band, so nothing can paint over them "
"and they need no room above — and the margin-top they have collapses "
"with the upper band's, taking the flow layout wider than the pinned "
"one wherever it is the larger of the two: " + ", ".join(lower))
|