REFACTOR: Remove position fixed from the header and use sticky instead (#10781)

This removes fixed positioning from d-header and the topic timeline.

Plugins, themes and components that use the above/below header plugin outlet will likely need some margin/padding adjustments.
This commit is contained in:
Kris 2020-10-19 17:26:38 -04:00 committed by GitHub
parent a74805d3f8
commit da5841de0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 132 additions and 100 deletions

View File

@ -373,7 +373,9 @@ const SiteHeaderComponent = MountWidget.extend(Docking, PanEvents, {
}, },
}); });
export default SiteHeaderComponent; export default SiteHeaderComponent.extend({
classNames: ["d-header-wrap"],
});
export function headerHeight() { export function headerHeight() {
const $header = $("header.d-header"); const $header = $("header.d-header");

View File

@ -3,31 +3,29 @@ export function scrollTopFor(y) {
} }
export function minimumOffset() { export function minimumOffset() {
const $header = $("header.d-header"); const header = document.querySelector("header.d-header");
const headerHeight = $header.outerHeight(true) || 0; return header ? header.offsetHeight : 0;
const headerPositionTop = $header.position().top;
return headerHeight + headerPositionTop;
} }
export default function offsetCalculator() { export default function offsetCalculator() {
const min = minimumOffset(); const min = minimumOffset();
// on mobile, just use the header // on mobile, just use the header
if ($("html").hasClass("mobile-view")) { if (document.querySelector("html").classList.contains("mobile-view")) {
return min; return min;
} }
const $window = $(window); const windowHeight = window.innerHeight;
const windowHeight = $window.height(); const documentHeight = document.body.clientHeight;
const documentHeight = $(document).height(); const topicBottomOffsetTop = document.getElementById("topic-bottom")
const topicBottomOffsetTop = $("#topic-bottom").offset().top; .offsetTop;
// the footer is bigger than the window, we can scroll down past the last post // the footer is bigger than the window, we can scroll down past the last post
if (documentHeight - windowHeight > topicBottomOffsetTop) { if (documentHeight - windowHeight > topicBottomOffsetTop) {
return min; return min;
} }
const scrollTop = $window.scrollTop(); const scrollTop = window.scrollY;
const visibleBottomHeight = scrollTop + windowHeight - topicBottomOffsetTop; const visibleBottomHeight = scrollTop + windowHeight - topicBottomOffsetTop;
if (visibleBottomHeight > 0) { if (visibleBottomHeight > 0) {

View File

@ -128,7 +128,7 @@
}} }}
</div> </div>
{{#topic-navigation topic=model jumpToDate=(action "jumpToDate") jumpToIndex=(action "jumpToIndex") as |info|}} {{#topic-navigation class="topic-navigation" topic=model jumpToDate=(action "jumpToDate") jumpToIndex=(action "jumpToIndex") as |info|}}
{{#if info.renderTimeline}} {{#if info.renderTimeline}}
{{topic-timeline {{topic-timeline
topic=model topic=model
@ -299,41 +299,6 @@
categoryId=model.topic_timer.category_id categoryId=model.topic_timer.category_id
removeTopicTimer=(action "removeTopicTimer" model.topic_timer.status_type "topic_timer")}} removeTopicTimer=(action "removeTopicTimer" model.topic_timer.status_type "topic_timer")}}
{{#if session.showSignupCta}}
{{! replace "Log In to Reply" with the infobox }}
{{signup-cta}}
{{else}}
{{#if currentUser}}
{{plugin-outlet name="topic-above-footer-buttons" args=(hash model=model)}}
{{topic-footer-buttons
topic=model
toggleMultiSelect=(action "toggleMultiSelect")
showTopicSlowModeUpdate=(route-action "showTopicSlowModeUpdate")
deleteTopic=(action "deleteTopic")
recoverTopic=(action "recoverTopic")
toggleClosed=(action "toggleClosed")
toggleArchived=(action "toggleArchived")
toggleVisibility=(action "toggleVisibility")
showTopicStatusUpdate=(route-action "showTopicStatusUpdate")
showFeatureTopic=(route-action "showFeatureTopic")
showChangeTimestamp=(route-action "showChangeTimestamp")
resetBumpDate=(action "resetBumpDate")
convertToPublicTopic=(action "convertToPublicTopic")
convertToPrivateMessage=(action "convertToPrivateMessage")
toggleBookmark=(action "toggleBookmark")
showFlagTopic=(route-action "showFlagTopic")
toggleArchiveMessage=(action "toggleArchiveMessage")
editFirstPost=(action "editFirstPost")
deferTopic=(action "deferTopic")
replyToPost=(action "replyToPost")}}
{{else}}
<div id="topic-footer-buttons">
{{d-button icon="reply" class="btn-primary pull-right" action=(route-action "showLogin") label="topic.reply.title"}}
</div>
{{/if}}
{{/if}}
{{#if showSelectedPostsAtBottom}} {{#if showSelectedPostsAtBottom}}
<div class="selected-posts {{unless multiSelect "hidden"}}"> <div class="selected-posts {{unless multiSelect "hidden"}}">
{{selected-posts {{selected-posts
@ -353,15 +318,6 @@
</div> </div>
{{/if}} {{/if}}
{{plugin-outlet name="topic-above-suggested" args=(hash model=model)}}
<div class="{{if model.relatedMessages.length "related-messages-wrapper"}} {{if model.suggestedTopics.length "suggested-topics-wrapper"}}">
{{#if model.relatedMessages.length}}
{{related-messages topic=model}}
{{/if}}
{{#if model.suggestedTopics.length}}
{{suggested-topics topic=model}}
{{/if}}
</div>
{{/if}} {{/if}}
{{/conditional-loading-spinner}} {{/conditional-loading-spinner}}
@ -369,6 +325,52 @@
</div> </div>
</div> </div>
{{#if loadedAllPosts}}
{{#if session.showSignupCta}}
{{! replace "Log In to Reply" with the infobox }}
{{signup-cta}}
{{else}}
{{#if currentUser}}
{{plugin-outlet name="topic-above-footer-buttons" args=(hash model=model)}}
{{topic-footer-buttons
topic=model
toggleMultiSelect=(action "toggleMultiSelect")
showTopicSlowModeUpdate=(route-action "showTopicSlowModeUpdate")
deleteTopic=(action "deleteTopic")
recoverTopic=(action "recoverTopic")
toggleClosed=(action "toggleClosed")
toggleArchived=(action "toggleArchived")
toggleVisibility=(action "toggleVisibility")
showTopicStatusUpdate=(route-action "showTopicStatusUpdate")
showFeatureTopic=(route-action "showFeatureTopic")
showChangeTimestamp=(route-action "showChangeTimestamp")
resetBumpDate=(action "resetBumpDate")
convertToPublicTopic=(action "convertToPublicTopic")
convertToPrivateMessage=(action "convertToPrivateMessage")
toggleBookmark=(action "toggleBookmark")
showFlagTopic=(route-action "showFlagTopic")
toggleArchiveMessage=(action "toggleArchiveMessage")
editFirstPost=(action "editFirstPost")
deferTopic=(action "deferTopic")
replyToPost=(action "replyToPost")}}
{{else}}
<div id="topic-footer-buttons">
{{d-button icon="reply" class="btn-primary pull-right" action=(route-action "showLogin") label="topic.reply.title"}}
</div>
{{/if}}
{{/if}}
{{plugin-outlet name="topic-above-suggested" args=(hash model=model)}}
<div class="{{if model.relatedMessages.length "related-messages-wrapper"}} {{if model.suggestedTopics.length "suggested-topics-wrapper"}}">
{{#if model.relatedMessages.length}}
{{related-messages topic=model}}
{{/if}}
{{#if model.suggestedTopics.length}}
{{suggested-topics topic=model}}
{{/if}}
</div>
{{/if}}
{{else}} {{else}}
<div class="container"> <div class="container">
{{#conditional-loading-spinner condition=noErrorYet}} {{#conditional-loading-spinner condition=noErrorYet}}

View File

@ -320,12 +320,6 @@ createWidget("topic-timeline-container", {
} }
}, },
buildAttributes(attrs) {
if (attrs.top) {
return { style: `top: ${attrs.top}px` };
}
},
html(attrs) { html(attrs) {
return this.attach("topic-timeline", attrs); return this.attach("topic-timeline", attrs);
}, },

View File

@ -580,7 +580,11 @@ table {
} }
// Special elements // Special elements
// Special elements
#main-outlet {
padding-top: 1.8em;
}
#main { #main {
img.avatar { img.avatar {
&.header { &.header {

View File

@ -1,12 +1,17 @@
.d-header-wrap {
@include sticky;
top: 0;
z-index: z("header");
}
.d-header { .d-header {
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%; width: 100%;
position: absolute;
top: 0;
z-index: z("header"); z-index: z("header");
background-color: var(--header_background); background-color: var(--header_background);
box-shadow: shadow("header"); box-shadow: shadow("header");
backface-visibility: hidden; /** do magic for scrolling performance **/
> .wrap { > .wrap {
width: calc(100% - 16px); // accommodates for 8px vertical padding width: calc(100% - 16px); // accommodates for 8px vertical padding
@ -35,11 +40,6 @@
} }
} }
.docked & {
position: fixed;
backface-visibility: hidden; /** do magic for scrolling performance **/
}
.title { .title {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -16,6 +16,51 @@
} }
} }
.container.posts {
display: grid;
grid-template-areas: "posts timeline";
grid-template-columns: auto auto;
> .row {
grid-area: posts;
max-width: 100%;
overflow: hidden;
}
.timeline-container {
margin-left: unset !important;
/* This is a temporary override to ease the transition
to the sticky position timeline for themes with custom timeline positioning.
Without this those themes would render topics unreadable. */
}
// timeline
@media screen and (min-width: 925px) {
// at 925px viewport width and above the timeline is visible (see topic-navigation.js)
.topic-navigation {
grid-area: timeline;
align-self: start;
@include sticky;
top: 6em;
margin-left: 1em;
z-index: z("timeline");
}
}
// progress bar
@media screen and (max-width: 924px) {
// at 924px viewport width and below the progress bar is visible (see topic-navigation.js)
grid-template-areas: "posts posts";
.timeline-container:not(.timeline-fullscreen) {
display: none; // hiding this because sometimes the JS switch lags and causes layout issues
}
.timeline-container {
.timeline-scroller-content {
position: relative;
}
}
}
}
.progress-back-container { .progress-back-container {
z-index: z("dropdown"); z-index: z("dropdown");
margin-right: 0; margin-right: 0;

View File

@ -75,6 +75,11 @@ $breakpoints: (
// //
// -------------------------------------------------- // --------------------------------------------------
@mixin sticky {
position: -webkit-sticky;
position: sticky;
}
// Unselectable (avoids unwanted selections with iPad, touch laptops, etc) // Unselectable (avoids unwanted selections with iPad, touch laptops, etc)
@mixin user-select($mode) { @mixin user-select($mode) {

View File

@ -5,22 +5,8 @@
.timeline-container { .timeline-container {
box-sizing: border-box; box-sizing: border-box;
z-index: z("timeline"); z-index: z("timeline");
margin-left: 757px;
@include breakpoint(extra-large, min-width) {
margin-left: 820px;
}
@media all and (min-width: 1250px) {
margin-left: 900px;
}
position: fixed;
-webkit-transform: translate3d(0, 0, 0); -webkit-transform: translate3d(0, 0, 0);
&.timeline-docked {
position: absolute;
}
&.timeline-docked-bottom { &.timeline-docked-bottom {
.timeline-footer-controls { .timeline-footer-controls {
opacity: 0; opacity: 0;
@ -173,7 +159,6 @@
} }
.topic-timeline { .topic-timeline {
margin-left: 3em;
transition: opacity 0.2s ease-in; transition: opacity 0.2s ease-in;
touch-action: none; touch-action: none;
@ -181,6 +166,11 @@
margin-bottom: 1em; margin-bottom: 1em;
} }
.timeline-date-wrapper {
max-width: 9em;
overflow-wrap: anywhere;
}
.timeline-footer-controls { .timeline-footer-controls {
margin-top: 1.5em; margin-top: 1.5em;
transition: opacity 0.2s ease-in; transition: opacity 0.2s ease-in;
@ -228,6 +218,7 @@
.timeline-scroller-content { .timeline-scroller-content {
padding-left: 1em; padding-left: 1em;
position: absolute; // prevents text length from impacting width
} }
.timeline-ago { .timeline-ago {

View File

@ -168,9 +168,6 @@ input {
} }
/* bootstrap columns */ /* bootstrap columns */
.row {
@include clearfix;
}
.offset { .offset {
&2 { &2 {

View File

@ -5,7 +5,6 @@
.d-header { .d-header {
left: 0; left: 0;
height: 4em; height: 4em;
margin-bottom: 15px;
#site-logo { #site-logo {
height: 2.667em; // 40px with default 15px font size height: 2.667em; // 40px with default 15px font size
} }
@ -32,10 +31,6 @@
position: relative; position: relative;
} }
#main-outlet {
padding-top: 5.8572em;
}
.search-link .blurb { .search-link .blurb {
color: var(--secondary-medium); color: var(--secondary-medium);
display: block; display: block;

View File

@ -207,13 +207,13 @@
z-index: z("dropdown"); z-index: z("dropdown");
} }
@media all and (min-width: 400px) { #topic-progress,
#topic-progress, #topic-progress-expanded {
#topic-progress-expanded { right: 0;
right: 0; left: 0;
left: 0; }
}
@media all and (min-width: 400px) {
#topic-footer-main-buttons { #topic-footer-main-buttons {
max-width: 70%; max-width: 70%;
} }

View File

@ -84,7 +84,6 @@
} }
#main-outlet { #main-outlet {
padding-top: 4.2857em;
@media only screen and (orientation: landscape) { @media only screen and (orientation: landscape) {
padding-right: env(safe-area-inset-right); padding-right: env(safe-area-inset-right);
padding-left: env(safe-area-inset-left); padding-left: env(safe-area-inset-left);