Switch to navigation-first DOM order under `$wgVectorIsSearchInHeader` feature flag

This moves the header, navigation, sidebar, and article toolbar to be
before the content in the DOM. As a result, a lot of absolute
positioning logic can be removed and styles can be simplified.

Note that although the sidebar was moved from the header into the
workspace container allowing it to de-absolutely positioned, its
absolute positioning was kept intact as it has a fair amount of
complexity that should be handled in a separate task.

To activate, set  `$wgVectorIsSearchInHeader = true;`

Changes that could cause concern:

* The "jump to search" link was removed as the search is now much
earlier in the DOM and I questioned the value of keeping this. However,
it can be added back in if this change is contentious.

* A "jump to content" link was added to account for the new DOM order.

* Because the sidebar was taken out of the header, users will not be
able to tab from the sidebar button into the sidebar without additional
tweaking (e.g. should we add JS to enable this?). It was deemed that
this work can be saved as a follow-up task.

* I applied `overflow-y: auto` to the `mw-page-container` because the
header's top margin was collapsing and caused whitespace to appear
between the viewport and the header. Alternatively, we could apply a top
padding to the page container and remove the header's top margin. I went
for the simplest solution but am open to alternatives.

* I left the footer as-is in this patch to minimize risk. It might be
cleaner later on to move the footer inside the workspace container which
would leave only one workspace container.

Bug: T261802
Change-Id: Ic553fab3bde25769b103d899b92b3b694c00c384
This commit is contained in:
Nicholas Ray 2020-09-08 17:20:58 -06:00 committed by Jdlrobson
parent 7e1be551e7
commit 78787d9665
11 changed files with 131 additions and 107 deletions

View File

@ -5,7 +5,7 @@
},
{
"resourceModule": "skins.vector.styles",
"maxSize": "9.1 kB"
"maxSize": "9.2 kB"
},
{
"resourceModule": "skins.vector.styles.responsive",

View File

@ -24,6 +24,7 @@
"vector-view-viewsource": "View source",
"vector-jumptonavigation": "Jump to navigation",
"vector-jumptosearch": "Jump to search",
"vector-jumptocontent": "Jump to content",
"vector-more-actions": "More",
"vector-search-loader": "Loading search suggestions"
}

View File

@ -35,6 +35,7 @@
"vector-view-viewsource": "Tab label in the Vector skin.\n{{Identical|View source}}",
"vector-jumptonavigation": "Accessibility link for jumping to the navigation links. Visually hidden by default.\n\nSee also\n* {{msg-mw|Navigation}}",
"vector-jumptosearch": "Accessibility link for jumping to the site search. Visually hidden by default.\n\nSee also\n* {{msg-mw|Search}}",
"vector-jumptocontent": "Accessibility link for jumping to the content and skipping the navigation. Visually hidden by default.",
"vector-more-actions": "Label in the Vector skin's menu for the less-important or rarer actions which are not shown as tabs (like moving the page, or for sysops deleting or protecting the page), as well as (for users with a narrow viewing window in their browser) the less-important tab actions which the user's browser is unable to fit in. {{Identical|More}}",
"vector-search-loader": "Text to display below search input while the search suggestion module is loading"
}

View File

@ -0,0 +1,22 @@
<header class="mw-header">
<label
id="mw-sidebar-button"
class="mw-checkbox-hack-button mw-ui-icon mw-ui-icon-element"
for="mw-sidebar-checkbox"
role="button"
aria-controls="mw-panel"
data-event-name="ui.sidebar"
tabindex="0">
{{msg-vector-action-toggle-sidebar}}
</label>
{{^is-search-in-header}}
<div class="mw-workspace-container mw-sidebar-container">
{{#data-sidebar}}{{>Sidebar}}{{/data-sidebar}}
</div>
{{/is-search-in-header}}
{{>Logo}}
{{#is-search-in-header}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
{{/is-search-in-header}}
</header>

View File

@ -0,0 +1,21 @@
<div id="mw-navigation">
<h2>{{msg-navigation-heading}}</h2>
<div id="mw-head">
{{^is-search-in-header}}
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
{{/is-search-in-header}}
<div class="{{^is-search-in-header}}mw-content-container {{/is-search-in-header}}mw-article-toolbar-container">
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{^is-search-in-header}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
{{/is-search-in-header}}
</div>
</div>
</div>
</div>

View File

@ -12,6 +12,7 @@
string html-newtalk
string msg-vector-jumptonavigation
string msg-vector-jumptosearch
string msg-vector-jumptocontent
string html-body-content
string html-categories
string html-after-content
@ -30,9 +31,14 @@
object data-footer for footer template partial. see Footer.mustache for documentation.
}}
<div class="mw-page-container">
{{#is-search-in-header}}
<a class="mw-jump-link" href="#content">{{msg-vector-jumptocontent}}</a>
{{/is-search-in-header}}
<div class="mw-page-container-inner">
{{^is-search-in-header}}
<div id="mw-page-base" class="mw-header-placeholder noprint"></div>
{{/is-search-in-header}}
<input
type="checkbox"
@ -40,7 +46,15 @@
class="mw-checkbox-hack-checkbox"
{{#sidebar-visible}}checked{{/sidebar-visible}}>
{{#is-search-in-header}}
{{>Header}}
{{/is-search-in-header}}
<div class="mw-workspace-container">
{{#is-search-in-header}}
{{#data-sidebar}}{{>Sidebar}}{{/data-sidebar}}
{{>Navigation}}
{{/is-search-in-header}}
<div class="mw-content-container">
{{! `role` is unnecessary but kept to support selectors in any gadgets or user styles. }}
<!-- Please do not use role attribute as CSS selector, it is deprecated. -->
@ -59,8 +73,10 @@
using this place to insert extra elements before.
}}
<div id="jump-to-nav"></div>
{{^is-search-in-header}}
<a class="mw-jump-link" href="#mw-sidebar-button">{{msg-vector-jumptonavigation}}</a>
<a class="mw-jump-link" href="#searchInput">{{msg-vector-jumptosearch}}</a>
{{/is-search-in-header}}
{{{html-body-content}}}
{{{html-categories}}}
</div>
@ -69,48 +85,10 @@
</div> {{! END mw-content-container }}
</div> {{! END mw-workspace-container }}
<header class="mw-header">
<label
id="mw-sidebar-button"
class="mw-checkbox-hack-button mw-ui-icon mw-ui-icon-element"
for="mw-sidebar-checkbox"
role="button"
aria-controls="mw-panel"
data-event-name="ui.sidebar"
tabindex="0">
{{msg-vector-action-toggle-sidebar}}
</label>
<div class="mw-workspace-container mw-sidebar-container">
{{#data-sidebar}}{{>Sidebar}}{{/data-sidebar}}
</div>
{{>Logo}}
{{#is-search-in-header}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
{{/is-search-in-header}}
</header>
<div id="mw-navigation">
<h2>{{msg-navigation-heading}}</h2>
<div id="mw-head">
{{^is-search-in-header}}
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
{{/is-search-in-header}}
<div class="mw-content-container mw-article-toolbar-container">
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{^is-search-in-header}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
{{/is-search-in-header}}
</div>
</div>
</div>
</div>
{{^is-search-in-header}}
{{>Header}}
{{>Navigation}}
{{/is-search-in-header}}
<div class="mw-workspace-container mw-footer-container">
<div class="mw-content-container">

View File

@ -61,7 +61,8 @@
// Use the MediaWiki checkbox hack class from checkboxHack.less. This class exists on the
// checkbox input for the menu panel.
#mw-sidebar-checkbox:not( :checked ) ~ .mw-header .mw-sidebar {
.skin-vector-search-header-legacy #mw-sidebar-checkbox:not( :checked ) ~ .mw-header .mw-sidebar,
.skin-vector-search-header #mw-sidebar-checkbox:not( :checked ) ~ .mw-workspace-container .mw-sidebar {
// Turn off presentation so that screen readers get the same effect as visually hiding.
// Visibility and opacity can be animated. If animation is unnecessary, use `display: none`
// instead to avoid hidden rendering.

View File

@ -33,19 +33,22 @@ body {
}
/* Space for header above content */
.mw-header-placeholder {
.skin-vector-search-header-legacy .mw-header-placeholder {
// Reserve space for the absolute positioned header and tabs.
height: @height-header + @height-tabs;
}
/* Header layout */
.mw-header {
.skin-vector-search-header-legacy .mw-header {
position: absolute;
top: 0;
left: 0;
right: 0;
// A height is set to account for projects where no icon is set.
height: @height-logo-icon;
}
.mw-header {
// A min-height is set to account for projects where no icon is set.
min-height: @height-logo-icon;
margin: @margin-top-header 0 @margin-bottom-header;
padding: @padding-vertical-header @padding-horizontal-header;
// Vertical centering of header elements (IE>=11), requires flex.
@ -94,7 +97,7 @@ body {
}
/* Tabs */
#mw-head {
.skin-vector-search-header-legacy #mw-head {
position: absolute;
top: 0;
right: 0;
@ -102,8 +105,12 @@ body {
}
/* Navigation Containers */
#left-navigation {
float: left;
.mw-article-toolbar-container {
// Clear the floats on #left-navigation and #right-navigation.
.mixin-clearfix();
}
.skin-vector-search-header-legacy #left-navigation {
margin-top: @height-header;
/* When right nav would overlap left nav, it's placed below it
(normal CSS floats behavior). This rule ensures that no empty space
@ -113,9 +120,16 @@ body {
margin-bottom: -@height-header;
}
#left-navigation {
float: left;
}
.skin-vector-search-header-legacy #right-navigation {
margin-top: @height-header;
}
#right-navigation {
float: right;
margin-top: @height-header;
}
.skin-vector-search-header-legacy #p-personal {
@ -143,12 +157,15 @@ body {
margin-right: @margin-horizontal-sidebar-button-icon; // Accidentally the same.
}
#mw-panel {
position: absolute;
.skin-vector-search-header-legacy #mw-panel {
// The sidebar is absolutely positioned inside the header which applies a top
// margin so we need to subtract this top margin in order to get the correct
// sidebar position.
top: @height-header - @margin-top-header;
}
#mw-panel {
position: absolute;
left: 0;
width: @width-grid-column-one;
.box-sizing( border-box );
@ -157,6 +174,6 @@ body {
z-index: @z-index-sidebar;
}
.mw-footer {
.skin-vector-search-header-legacy .mw-footer {
margin-top: 0;
}

View File

@ -56,26 +56,26 @@
margin-left: 0;
}
#mw-head {
&.skin-vector-search-header-legacy #mw-head {
width: auto;
left: 0;
right: 0;
}
#left-navigation {
&.skin-vector-search-header-legacy #left-navigation {
margin-top: 0;
margin-bottom: 0;
}
#right-navigation {
&.skin-vector-search-header-legacy #right-navigation {
margin-top: 0;
}
#p-personal {
&.skin-vector-search-header-legacy #p-personal {
right: 0;
}
#p-search {
&.skin-vector-search-header-legacy #p-search {
margin-right: 0;
}
@ -117,6 +117,13 @@
background-color: @background-color-page-container;
}
&.skin-vector-search-header .mw-page-container {
// Establish a new block formatting context to prevent header top margin
// collapsing and causing whitespace to appear between the header and
// viewport.
overflow-y: auto;
}
// Used as a container for absolutely positioned elements.
.mw-page-container-inner {
position: relative;
@ -128,16 +135,30 @@
margin-right: auto;
}
&.skin-vector-search-header .mw-workspace-container {
// The sidebar is absolutely positioned relative to the
// mw-workspace-container.
position: relative;
}
.mw-content-container {
max-width: @max-width-content-container;
margin-left: auto;
margin-right: auto;
}
.mw-article-toolbar-container {
&.skin-vector-search-header-legacy .mw-article-toolbar-container {
margin-top: @height-header;
// Clear the floats on #left-navigation and #right-navigation.
.mixin-clearfix();
}
&.skin-vector-search-header .mw-article-toolbar-container {
// We want to keep the max-width of the article-toolbar-container the
// same max-width as the article page's content container in order to
// prevent it from moving when going from an article page to a
// history/special page.
max-width: @max-width-content-container;
margin-left: auto;
margin-right: auto;
}
.mw-sidebar-container {
@ -165,7 +186,7 @@
// same max-width as the article page's content container in order to
// prevent it from moving when going from an article page to a
// history/special page.
.mw-article-toolbar-container {
&.skin-vector-search-header-legacy .mw-article-toolbar-container {
max-width: @max-width-content-container;
}
@ -180,7 +201,8 @@
// `.mw-page-container` because that will cut off the sidebar. Therefore, we
// calculate the maximum distance from the start of `mw-page-container` to the
// start of the sidebar.
#mw-sidebar-checkbox:not( :checked ) ~ .mw-header .mw-sidebar {
&.skin-vector-search-header-legacy #mw-sidebar-checkbox:not( :checked ) ~ .mw-header .mw-sidebar,
&.skin-vector-search-header #mw-sidebar-checkbox:not( :checked ) ~ .mw-workspace-container .mw-sidebar {
.transform( translateX( -( @max-width-page-container - @max-width-workspace-container ) / 2 ) );
}
@ -197,7 +219,8 @@
@media ( max-width: @max-width-margin-start-content ) {
// Adjusts the content and mw-article-toolbar-container.
.mw-checkbox-hack-checkbox:checked ~ .mw-workspace-container .mw-content-container,
.mw-checkbox-hack-checkbox:checked ~ #mw-navigation .mw-content-container {
&.skin-vector-search-header-legacy .mw-checkbox-hack-checkbox:checked ~ #mw-navigation .mw-content-container,
&.skin-vector-search-header .mw-checkbox-hack-checkbox:checked ~ .mw-workspace-container .mw-article-toolbar-container {
margin-left: @margin-start-content;
}

View File

@ -54,47 +54,6 @@
// Support IE9: This is reset in @support query below if Flexbox is available.
float: right;
}
// If we don't have the space adjust header.
// Increase height and margins to accommodate personal tools underneath.
@media ( max-width: @width-comfortable ) {
@height-header-adjusted: @height-header + @height-personal-tools;
#mw-panel {
top: @height-header-adjusted - @margin-top-header;
}
.mw-header-placeholder {
height: @height-header-adjusted + @height-tabs;
}
#left-navigation {
margin-top: @height-header-adjusted;
margin-bottom: 0;
}
#right-navigation {
margin-top: -@height-tabs;
clear: left;
}
}
}
// when max-width is also enabled...
.skin-vector-search-header.skin-vector-max-width {
#left-navigation {
margin-top: 0;
}
.mw-article-toolbar-container {
margin-top: @height-header + @height-personal-tools;
}
@media ( min-width: @width-comfortable ) {
.mw-article-toolbar-container {
margin-top: @height-header;
}
}
}
// If flexbox supported reset the floats that are supporting IE9

View File

@ -35,6 +35,7 @@
"vector-action-toggle-sidebar",
"vector-jumptonavigation",
"vector-jumptosearch",
"vector-jumptocontent",
"sitesubtitle",
"sitetitle",
"tagline"