Fix height when main content is shorter than sidebar

This commit is contained in:
squidfunk 2016-12-24 08:10:55 +01:00
parent 13b55fa165
commit d86dadf4bd
9 changed files with 198 additions and 86 deletions

View File

@ -30,7 +30,7 @@
{% endif %}
{% endblock %}
{% block libs %}
<script src="{{ base_url }}/assets/javascripts/modernizr-dede1352ed.js"></script>
<script src="{{ base_url }}/assets/javascripts/modernizr-c5e6000d9f.js"></script>
{% endblock %}
{% block styles %}
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700">
@ -62,7 +62,7 @@
{% endblock %}
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid">
<div class="md-main__inner md-grid" data-md-container>
{% block site_nav %}
{% if nav %}
<div class="md-sidebar md-sidebar--primary" data-md-sidebar="primary">
@ -124,7 +124,7 @@
<script src="https://cdn.mathjax.org/{{ path }}"></script>
{% endif %}
{% endfor %}
<script src="{{ base_url }}/assets/javascripts/application-697e84d406.js"></script>
<script src="{{ base_url }}/assets/javascripts/application-d61fcbb674.js"></script>
<script>
/* Configuration for application */
var config = {

View File

@ -94,17 +94,23 @@ export default class Application {
return string
}
/* Component: sidebar container */
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(window, [
"resize", "orientationchange"
], new Material.Sidebar.Container("[data-md-container]")))
/* Component: sidebar with navigation */
new Material.Event.MatchMedia("(min-width: 1200px)",
new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange"
], new Material.Sidebar("[data-md-sidebar=primary]")))
], new Material.Sidebar.Position("[data-md-sidebar=primary]")))
/* Component: sidebar with table of contents */
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange"
], new Material.Sidebar("[data-md-sidebar=secondary]")))
], new Material.Sidebar.Position("[data-md-sidebar=secondary]")))
/* Component: link blurring for table of contents */
new Material.Event.MatchMedia("(min-width: 960px)",

View File

@ -60,6 +60,10 @@ export default class Blur {
update() {
const offset = window.pageYOffset
/* Exit when there are no anchors */
if (this.anchors_.length === 0)
return
/* Scroll direction is down */
if (this.offset_ <= offset) {
for (let i = this.index_ + 1; i < this.els_.length; i++) {
@ -74,7 +78,7 @@ export default class Blur {
/* Scroll direction is up */
} else {
for (let i = this.index_; i > 0; i--) {
for (let i = this.index_; i >= 0; i--) {
if (this.anchors_[i].offsetTop > offset) {
if (i > 0)
delete this.els_[i - 1].dataset.mdState

View File

@ -20,79 +20,14 @@
* IN THE SOFTWARE.
*/
import Container from "./Sidebar/Container"
import Position from "./Sidebar/Position"
/* ----------------------------------------------------------------------------
* Class
* Module
* ------------------------------------------------------------------------- */
export default class Sidebar {
/**
* Set sidebars to locked state and limit height to parent node
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
/* Retrieve inner and outer container */
const inner = this.el_.parentNode
const outer = this.el_.parentNode.parentNode
/* Get top and bottom bounds */
this.offset_ = outer.offsetTop
this.bounds_ = {
top: inner.offsetTop,
bottom: inner.offsetTop + inner.offsetHeight
}
/* Initialize current height */
this.height_ = 0
}
/**
* Initialize sidebar state
*/
setup() {
this.update()
}
/**
* Update locked state and height
*/
update() {
const scroll = window.pageYOffset
const expand = window.innerHeight
/* Calculate new bounds */
const offset = this.bounds_.top - scroll
const height = expand
- Math.max(0, scroll + expand - this.bounds_.bottom)
- Math.max(offset, this.offset_)
/* If height changed, update element */
if (height !== this.height_)
this.el_.style.height = `${this.height_ = height}px`
/* Sidebar should be locked, as we're below parent offset */
if (offset < this.offset_) {
if (this.el_.dataset.mdState !== "lock")
this.el_.dataset.mdState = "lock"
/* Sidebar should be unlocked, if locked */
} else if (this.el_.dataset.mdState === "lock") {
delete this.el_.dataset.mdState
}
}
/**
* Reset locked state and height
*/
reset() {
delete this.el_.dataset.mdState
this.el_.style.height = ""
this.height_ = 0
}
export default {
Container,
Position
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
export default class Container {
/**
* Monitor window height to stretch sidebar container to viewport
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
/* Retrieve parent node */
this.parent_ = this.el_.parentNode
}
/**
* Initialize container state
*/
setup() {
this.update()
}
/**
* Update minimum height
*/
update() {
const height = window.innerHeight - this.parent_.offsetTop
const margin = this.parent_.offsetHeight - this.el_.offsetHeight
/* Set new minimum height */
this.el_.style.minHeight = `${height - margin}px`
}
/**
* Reset minimum height
*/
reset() {
this.el_.style.minHeight = ""
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2016 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
export default class Position {
/**
* Set sidebars to locked state and limit height to parent node
*
* @constructor
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
this.el_ = (typeof el === "string")
? document.querySelector(el)
: el
/* Retrieve inner and outer container */
this.inner_ = this.el_.parentNode
this.outer_ = this.el_.parentNode.parentNode
/* Initialize top offset and current height */
this.offset_ = this.outer_.offsetTop
this.height_ = 0
}
/**
* Initialize sidebar state
*/
setup() {
this.update()
}
/**
* Update locked state and height
*/
update() {
const scroll = window.pageYOffset
const expand = window.innerHeight
/* Calculate bounds of sidebar container */
this.bounds_ = {
top: this.inner_.offsetTop,
bottom: this.inner_.offsetTop + this.inner_.offsetHeight
}
/* Calculate new offset and height */
const offset = this.bounds_.top - scroll
const height = expand
- Math.max(0, scroll + expand - this.bounds_.bottom)
- Math.max(offset, this.offset_)
/* If height changed, update element */
if (height !== this.height_)
this.el_.style.height = `${this.height_ = height}px`
/* Sidebar should be locked, as we're below parent offset */
if (offset < this.offset_) {
if (this.el_.dataset.mdState !== "lock")
this.el_.dataset.mdState = "lock"
/* Sidebar should be unlocked, if locked */
} else if (this.el_.dataset.mdState === "lock") {
delete this.el_.dataset.mdState
}
}
/**
* Reset locked state and height
*/
reset() {
delete this.el_.dataset.mdState
this.el_.style.height = ""
this.height_ = 0
}
}

View File

@ -54,10 +54,11 @@ export default class Abstract {
if (typeof cached !== "undefined") {
resolve(cached)
/* If the data is not cached in a cookie, invoke fetch */
/* If the data is not cached in a cookie, invoke fetch and set
a cookie that automatically expires in 15 minutes */
} else {
this.fetch_().then(data => {
Cookies.set(".cache-source", data)
Cookies.set(".cache-source", data, { expires: 1 / 96 })
resolve(data)
})
}

View File

@ -132,7 +132,7 @@
<!-- Main container -->
<main class="md-main">
<div class="md-main__inner md-grid">
<div class="md-main__inner md-grid" data-md-container>
<!-- Block: navigation -->
{% block site_nav %}