Reduced repaints for header and sidebars

This commit is contained in:
squidfunk 2017-03-03 21:57:15 +01:00 committed by Martin Donath
parent 0fa899fe0b
commit d12f17e520
13 changed files with 64 additions and 27 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -32,7 +32,7 @@
<script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script> <script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script>
{% endblock %} {% endblock %}
{% block styles %} {% block styles %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-2193a9b229.css"> <link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-248e5b02e7.css">
{% if config.extra.palette %} {% if config.extra.palette %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-892b79c5c5.palette.css"> <link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-892b79c5c5.palette.css">
{% endif %} {% endif %}
@ -154,7 +154,7 @@
{% endblock %} {% endblock %}
</div> </div>
{% block scripts %} {% block scripts %}
<script src="{{ base_url }}/assets/javascripts/application-30ac6a1727.js"></script> <script src="{{ base_url }}/assets/javascripts/application-3873210def.js"></script>
<script>app.initialize({url:{base:"{{ base_url }}"}})</script> <script>app.initialize({url:{base:"{{ base_url }}"}})</script>
{% for path in extra_javascript %} {% for path in extra_javascript %}
<script src="{{ path }}"></script> <script src="{{ path }}"></script>

View File

@ -1,4 +1,4 @@
<header class="md-header"> <header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid"> <nav class="md-header-nav md-grid">
<div class="md-flex"> <div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink"> <div class="md-flex__cell md-flex__cell--shrink">

View File

@ -38,7 +38,7 @@ theme_dir: material
# Options # Options
extra: extra:
feature: feature:
tabs: true tabs: false
palette: palette:
primary: indigo primary: indigo
accent: indigo accent: indigo

View File

@ -87,7 +87,9 @@ function initialize(config) { // eslint-disable-line func-style
new Material.Event.MatchMedia("(min-width: 1220px)", new Material.Event.MatchMedia("(min-width: 1220px)",
new Material.Event.Listener(window, [ new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange" "scroll", "resize", "orientationchange"
], new Material.Header.Shadow("[data-md-component=container]"))) ], new Material.Header.Shadow(
"[data-md-component=container]",
"[data-md-component=header]")))
/* Component: tabs visibility toggle */ /* Component: tabs visibility toggle */
if (document.querySelector("[data-md-component=tabs]")) if (document.querySelector("[data-md-component=tabs]"))
@ -99,18 +101,24 @@ function initialize(config) { // eslint-disable-line func-style
new Material.Event.MatchMedia("(min-width: 1220px)", new Material.Event.MatchMedia("(min-width: 1220px)",
new Material.Event.Listener(window, [ new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange" "scroll", "resize", "orientationchange"
], new Material.Sidebar.Position("[data-md-component=navigation]"))) ], new Material.Sidebar.Position(
"[data-md-component=navigation]",
"[data-md-component=header]")))
/* Component: sidebar with table of contents - register two separate /* Component: sidebar with table of contents - register two separate
listeners, as the offset at the top might change */ listeners, as the offset at the top might change */
new Material.Event.MatchMedia("(min-width: 960px) and (max-width: 1219px)", new Material.Event.MatchMedia("(min-width: 960px) and (max-width: 1219px)",
new Material.Event.Listener(window, [ new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange" "scroll", "resize", "orientationchange"
], new Material.Sidebar.Position("[data-md-component=toc]"))) ], new Material.Sidebar.Position(
"[data-md-component=toc]",
"[data-md-component=header]")))
new Material.Event.MatchMedia("(min-width: 1220px)", new Material.Event.MatchMedia("(min-width: 1220px)",
new Material.Event.Listener(window, [ new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange" "scroll", "resize", "orientationchange"
], new Material.Sidebar.Position("[data-md-component=toc]"))) ], new Material.Sidebar.Position(
"[data-md-component=toc]",
"[data-md-component=header]")))
/* Component: link blurring for table of contents */ /* Component: link blurring for table of contents */
new Material.Event.MatchMedia("(min-width: 960px)", new Material.Event.MatchMedia("(min-width: 960px)",

View File

@ -37,21 +37,24 @@ export default class Shadow {
* @property {boolean} active_ - Header shadow state * @property {boolean} active_ - Header shadow state
* *
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(string|HTMLElement)} header - Selector or HTML element
*/ */
constructor(el) { constructor(el, header) {
const ref = (typeof el === "string") let ref = (typeof el === "string")
? document.querySelector(el) ? document.querySelector(el)
: el : el
if (!(ref instanceof HTMLElement) || if (!(ref instanceof HTMLElement) ||
!(ref.parentNode instanceof HTMLElement)) !(ref.parentNode instanceof HTMLElement))
throw new ReferenceError throw new ReferenceError
/* Grab parent and header */
this.el_ = ref.parentNode this.el_ = ref.parentNode
if (!(this.el_.parentNode instanceof HTMLElement) ||
!(this.el_.parentNode.previousElementSibling instanceof HTMLElement)) /* Retrieve header */
ref = (typeof header === "string")
? document.querySelector(header)
: header
if (!(ref instanceof HTMLElement))
throw new ReferenceError throw new ReferenceError
this.header_ = this.el_.parentNode.previousElementSibling this.header_ = ref
/* Initialize height and state */ /* Initialize height and state */
this.height_ = 0 this.height_ = 0

View File

@ -33,22 +33,32 @@ export default class Position {
* *
* @property {HTMLElement} el_ - Sidebar * @property {HTMLElement} el_ - Sidebar
* @property {HTMLElement} parent_ - Sidebar container * @property {HTMLElement} parent_ - Sidebar container
* @property {HTMLElement} header_ - Header
* @property {number} height_ - Current sidebar height * @property {number} height_ - Current sidebar height
* @property {number} offset_ - Current page y-offset * @property {number} offset_ - Current page y-offset
* *
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(string|HTMLElement)} header - Selector or HTML element
*/ */
constructor(el) { constructor(el, header) {
const ref = (typeof el === "string") let ref = (typeof el === "string")
? document.querySelector(el) ? document.querySelector(el)
: el : el
if (!(ref instanceof HTMLElement) || if (!(ref instanceof HTMLElement) ||
!(ref.parentNode instanceof HTMLElement)) !(ref.parentNode instanceof HTMLElement))
throw new ReferenceError throw new ReferenceError
this.el_ = ref this.el_ = ref
/* Initialize parent container and current height */
this.parent_ = ref.parentNode this.parent_ = ref.parentNode
/* Retrieve header */
ref = (typeof header === "string")
? document.querySelector(header)
: header
if (!(ref instanceof HTMLElement))
throw new ReferenceError
this.header_ = ref
/* Initialize current height */
this.height_ = 0 this.height_ = 0
} }
@ -56,7 +66,13 @@ export default class Position {
* Initialize sidebar state * Initialize sidebar state
*/ */
setup() { setup() {
this.offset_ = this.el_.offsetTop - 56 const top = Array.prototype.reduce.call(
this.parent_.children, (offset, child) => {
return Math.max(offset, child.offsetTop)
}, 0)
/* Set lock offset for element with largest top offset */
this.offset_ = top - this.header_.offsetHeight
this.update() this.update()
} }
@ -68,15 +84,21 @@ export default class Position {
* by the height of the fixed header (56px). Depending on the page y-offset, * by the height of the fixed header (56px). Depending on the page y-offset,
* the top offset of the sidebar must be taken into account, as well as the * the top offset of the sidebar must be taken into account, as well as the
* case where the window is scrolled beyond the sidebar container. * case where the window is scrolled beyond the sidebar container.
*
* @param {Event?} ev - Event
*/ */
update() { update(ev) {
const offset = window.pageYOffset const offset = window.pageYOffset
const visible = window.innerHeight const visible = window.innerHeight
/* Update offset, in case window is resized */
if (ev && ev.type === "resize")
this.setup()
/* Set bounds of sidebar container - must be calculated on every run, as /* Set bounds of sidebar container - must be calculated on every run, as
the height of the content might change due to loading images etc. */ the height of the content might change due to loading images etc. */
const bounds = { const bounds = {
top: 56, top: this.header_.offsetHeight,
bottom: this.parent_.offsetTop + this.parent_.offsetHeight bottom: this.parent_.offsetTop + this.parent_.offsetHeight
} }

View File

@ -37,6 +37,8 @@
background-color: $md-color-primary; background-color: $md-color-primary;
color: $md-color-white; color: $md-color-white;
z-index: 1; z-index: 1;
// Hack: putting the header on the GPU avoids unnecessary repaints
backface-visibility: hidden;
// Always show shadow, in case JavaScript is not available // Always show shadow, in case JavaScript is not available
.no-js & { .no-js & {

View File

@ -88,6 +88,8 @@
// Align SVG, do not scale, as this will incur strange formatting bugs // Align SVG, do not scale, as this will incur strange formatting bugs
// in Internet Explorer and Edge // in Internet Explorer and Edge
svg { svg {
width: 2.4rem;
height: 2.4rem;
margin-top: 1.2rem; margin-top: 1.2rem;
margin-left: 1.2rem; margin-left: 1.2rem;
} }

View File

@ -21,7 +21,7 @@
--> -->
<!-- Application header --> <!-- Application header -->
<header class="md-header"> <header class="md-header" data-md-component="header">
<!-- Top-level navigation --> <!-- Top-level navigation -->
<nav class="md-header-nav md-grid"> <nav class="md-header-nav md-grid">