[2.x] fix: stop the header overlapping itself when it runs out of room - #4906
Conversation
On a tablet-width screen the header had no way to give up space. The navigation, the logo and the session controls each held their full width, so once an extension added a few links the row simply overflowed and the controls painted over each other — a username cut mid-word on an iPad in portrait, or nav links sitting on top of the search icon. Three things were behind it: - `.container` was pinned to the width that opened each breakpoint, so at 820px the layout was still 768px wide and 52px of screen went unused. The bands above 1100px were already fixed this way; this extends the same clamp down to tablet and desktop. - `.Header-primary` declared no flex behaviour at all, so it could neither shrink nor grow, and `.Header-secondary` used an auto margin — which takes free space before flex distributes any, pooling all the slack into one gap mid-row. - Nothing ever moved out of the way. Navigation now collapses what does not fit into a menu at the end of the row, via a new `OverflowingList`. The header search made this worse than it needed to be. Since search moved into a modal it has been a `readonly` text field that cannot be typed into — reserving a text field's width for a control that only ever behaved as a button, and announcing itself to assistive technology as a textbox that refuses input. It is now a button, with the same icon-and-label markup as the notification and message controls, so it collapses to its icon in the header and keeps its label in the drawer. The locale selector gains an icon for the same reason. The fitting arithmetic lives in `countItemsThatFit` rather than inside the component, so the awkward cases can be tested directly: boundaries where an item exactly fits, keeping room for the toggle that is about to appear, and the monotonicity that stops the row oscillating between two states. `OverflowingList` measures real layout, which jsdom cannot provide, so the component tests cover the markup either side of the decision and the sums are covered on their own.
|
About Search is now a button: However, we lost the cancel button, so after we cancel search, page continue shows us search results, unless we click a discussion in list and back...It's necessary to ensure we still able to cancel search session. @imorland |
Complete oversight on my part here! I do think a button is the way to go here, especially for space saving and aesthetics, but for sure the cancel flow needs some attention! |
The problem
On a tablet-width screen the header has no way to give up space. Navigation, logo and session controls each hold their full width, so once an extension adds a few links the row overflows and controls paint over one another.
Reported on an iPad in portrait (820px): the username was cut mid-word, and with
fof/linksinstalled the nav pushed the session controls off the edge entirely.Why it happened
Three separate causes, all needed fixing:
1. The container wasn't using the viewport.
.containerwas pinned to the width that opened each breakpoint —width: @screen-tabletis literally768pxfor everything from 768 to 991px. At 820px the layout stayed 768px wide with 52px of screen unused; at 991px, 223px unused. The bands above 1100px were already fixed this way in earlier work; this extends the samemin(…, 100%)clamp down to tablet and desktop.2. Nothing could flex.
.Header-primarydeclared no flex behaviour at all, so it could neither shrink nor grow..Header-secondaryusedmargin-left: auto— and auto margins consume free space before flex distributes any, so all slack pooled into a single conspicuous gap mid-row rather than being usable.3. Nothing ever moved out of the way. Navigation now collapses whatever doesn't fit into a menu at the end of the row, via a new
OverflowingListcomponent.Search is now a button
Since search moved into a modal, the header control has been a
readonlytext field that cannot be typed into. Every path through it — click, Enter, the drawer — blurs the field and opensSearchModal.That cost the header a text field's width (195px at desktop) for something that only ever behaved as a button, and announced itself to assistive technology as a textbox that refuses input.
It is now a
<button>carrying the same icon-and-label markup as the notification and message controls, so it collapses to its icon in the header and keeps its label in the drawer. The locale selector gains an icon for the same reason — something has to identify it once the label is hidden.Testing
countItemsThatFitis extracted from the component so the arithmetic can be tested directly: boundaries where an item exactly fits, reserving room for the toggle that is about to appear, and the monotonicity that stops the row oscillating between two states.52 new tests, 373 passing overall.
OverflowingListmeasures real layout, which jsdom cannot provide — so the component tests cover the markup either side of the decision, and the sums are covered on their own.Verified
Measured in Chrome at 768 / 820 / 900 / 991 / 992 / 1100 / 1400 / 1920px, logged in and out: no overlap at any width, items collapse only when they genuinely do not fit and return when space allows, and the row settles in one pass with no flicker. Live resizing recalculates without a reload. The drawer renders everything, since a vertical column has no width pressure.
Notes for reviewers
OverflowingListis a new public component. Extensions will subclass it, so the API is worth scrutiny mid-RC..Search-inputis now a<button>, not an<input>. Extensions styling or extending it may need adjusting —fof/ui-kitscopes to its own.UiKit-Searchand is unaffected.