浏览代码

Improve responsive scrolling for URL hashes (#81)

George Cushen 8 年之前
父节点
当前提交
641c699899
共有 2 个文件被更改,包括 86 次插入108 次删除
  1. 0 15
      static/css/hugo-academic.css
  2. 86 93
      static/js/hugo-academic.js

+ 0 - 15
static/css/hugo-academic.css

@@ -785,15 +785,6 @@ footer a#back_to_top i {
   min-height: 70px !important;
 }
 
-/* Prevent navbar hiding initial content when jumping to in-page anchor. */
-*[id]:not([id^="fn"]):before {
-  display: block;
-  content: " ";
-  margin-top: -70px;
-  height: 70px;
-  visibility: hidden;
-}
-
 .navbar-default {
   background: #fff;
   box-shadow: 0 0.125rem 0.25rem 0 rgba(0,0,0,.11)
@@ -860,12 +851,6 @@ nav#navbar-main li {
     min-height: 50px !important;
   }
 
-  /* Prevent navbar hiding initial content when jumping to in-page anchor. */
-  *[id]:not([id^="fn"]):before {
-    margin-top: -50px;
-    height: 50px;
-  }
-
   .navbar-brand,
   .navbar-nav li a {
     height: inherit;

+ 86 - 93
static/js/hugo-academic.js

@@ -1,38 +1,73 @@
 /*************************************************
- *  Hugo Academic: an academic theme for Hugo.
+ *  Academic: the personal website framework for Hugo.
  *  https://github.com/gcushen/hugo-academic
  **************************************************/
 
 (function($){
 
   /* ---------------------------------------------------------------------------
-   * Add smooth scrolling to all links inside the main navbar.
+   * Responsive scrolling for URL hashes.
    * --------------------------------------------------------------------------- */
 
-  $('#navbar-main li.nav-item a').on('click', function(event){
+  // Dynamically get responsive navigation bar offset.
+  let $navbar = $('.navbar-header');
+  let navbar_offset = $navbar.innerHeight();
+
+  /**
+   * Responsive hash scrolling.
+   * Check for a URL hash as an anchor.
+   * If it exists on current page, scroll to it responsively.
+   * If `target` argument omitted (e.g. after event), assume it's the window's hash.
+   */
+  function scrollToAnchor(target) {
+    // If `target` is undefined or HashChangeEvent object, set it to window's hash.
+    target = (typeof target === 'undefined' || typeof target === 'object') ? window.location.hash : target;
+    // Escape colons from IDs, such as those found in Markdown footnote links.
+    target = target.replace(/:/g, '\\:');
+
+    // If target element exists, scroll to it taking into account fixed navigation bar offset.
+    if($(target).length) {
+      $('body').addClass('scrolling');
+      $('html, body').animate({
+        scrollTop: $(target).offset().top - navbar_offset
+      }, 600, function () {
+        $('body').removeClass('scrolling');
+      });
+    }
+  }
+
+  // Make Scrollspy responsive.
+  function fixScrollspy() {
+    let $body = $('body');
+    let data = $body.data('bs.scrollspy');
+    if (data) {
+      data.options.offset = navbar_offset;
+      $body.data('bs.scrollspy', data);
+      $body.scrollspy('refresh');
+    }
+  }
+
+  // Check for hash change event and fix responsive offset for hash links (e.g. Markdown footnotes).
+  window.addEventListener("hashchange", scrollToAnchor);
+
+  /* ---------------------------------------------------------------------------
+   * Add smooth scrolling to all links inside the main navbar.
+   * --------------------------------------------------------------------------- */
 
+  $('#navbar-main li.nav-item a').on('click', function(event) {
     // Store requested URL hash.
-    var hash = this.hash;
+    let hash = this.hash;
 
     // If we are on the homepage and the navigation bar link is to a homepage section.
-    if( hash && $(hash).length && ($("#homepage").length > 0)){
-      // Prevent default click behavior
+    if ( hash && $(hash).length && ($("#homepage").length > 0)) {
+      // Prevent default click behavior.
       event.preventDefault();
 
-      var navbarHeight = $('.navbar-header').innerHeight();
-
       // Use jQuery's animate() method for smooth page scrolling.
       // The numerical parameter specifies the time (ms) taken to scroll to the specified hash.
       $('html, body').animate({
-        scrollTop: $(hash).offset().top - navbarHeight
-      }, 800, function () {
-        // Add hash (#) to URL once finished scrolling to hash position
-        if (hash == "#top"){
-          window.location.hash = ""
-        }else {
-          window.location.hash = hash;
-        }
-      });
+        scrollTop: $(hash).offset().top - navbar_offset
+      }, 800);
     }
   });
 
@@ -40,51 +75,21 @@
    * Smooth scrolling for Back To Top link.
    * --------------------------------------------------------------------------- */
 
-  $('#back_to_top').on('click', function(event){
+  $('#back_to_top').on('click', function(event) {
     event.preventDefault();
-
     $('html, body').animate({
       'scrollTop': 0
-    }, 800, function(){
-      window.location.hash = ""
+    }, 800, function() {
+      window.location.hash = "";
     });
   });
 
-  /* ---------------------------------------------------------------------------
-   * Smooth scrolling for mouse wheel.
-   * --------------------------------------------------------------------------- */
-
-  function smoothScroll(scrollTime, scrollDistance){
-
-    if (navigator.userAgent.indexOf('Mac') != -1 || navigator.userAgent.indexOf('Firefox') > -1 || jQuery('body').hasClass('is-horizontal')){
-      return;
-    }
-
-    jQuery(window).on("mousewheel DOMMouseScroll", function(event){
-
-      event.preventDefault();
-
-      var delta = event.originalEvent.wheelDelta/120 || -event.originalEvent.detail/3;
-      var scrollTop = jQuery(window).scrollTop();
-      var finalScroll = scrollTop - parseInt(delta*scrollDistance);
-
-      TweenMax.to(jQuery(window), scrollTime, {
-        scrollTo : { y: finalScroll, autoKill:true },
-        ease: Expo.easeOut,
-        autoKill: true,
-        overwrite: 5
-      });
-
-    });
-
-  }
-
   /* ---------------------------------------------------------------------------
    * Hide mobile collapsable menu on clicking a link.
    * --------------------------------------------------------------------------- */
 
-  $(document).on('click','.navbar-collapse.in',function(e){
-    if( $(e.target).is('a') && $(e.target).attr('class') != 'dropdown-toggle' ){
+  $(document).on('click', '.navbar-collapse.in', function(e) {
+    if ( $(e.target).is('a') && $(e.target).attr('class') != 'dropdown-toggle' ) {
       $(this).collapse('hide');
     }
   });
@@ -93,7 +98,7 @@
    * Filter projects.
    * --------------------------------------------------------------------------- */
 
-  var $grid_projects = $('#container-projects');
+  let $grid_projects = $('#container-projects');
   $grid_projects.imagesLoaded(function () {
     // Initialize Isotope after all images have loaded.
     $grid_projects.isotope({
@@ -103,18 +108,18 @@
 
     // Filter items when filter link is clicked.
     $('#filters a').click(function () {
-     var selector = $(this).attr('data-filter');
+      let selector = $(this).attr('data-filter');
       $grid_projects.isotope({filter: selector});
-     $(this).removeClass('active').addClass('active').siblings().removeClass('active all');
-     return false;
-     });
+      $(this).removeClass('active').addClass('active').siblings().removeClass('active all');
+      return false;
+    });
   });
 
   /* ---------------------------------------------------------------------------
    * Filter publications.
    * --------------------------------------------------------------------------- */
 
-  var $grid_pubs = $('#container-publications');
+  let $grid_pubs = $('#container-publications');
   $grid_pubs.isotope({
     itemSelector: '.isotope-item',
     percentPosition: true,
@@ -125,14 +130,14 @@
   });
 
   // Bind publication filter on dropdown change.
-  $('.pub-filters-select').on( 'change', function() {
+  $('.pub-filters-select').on('change', function() {
     // Get filter value from option value.
-    var filterValue = this.value;
+    let filterValue = this.value;
     // Apply filter to Isotope.
     $grid_pubs.isotope({ filter: filterValue });
 
     // Set hash URL to current filter.
-    var url = $(this).val();
+    let url = $(this).val();
     if (url.substr(0, 9) == '.pubtype-') {
       window.location.hash = url.substr(9);
     } else {
@@ -142,8 +147,8 @@
 
   // Filter publications according to hash in URL.
   function filter_publications() {
-    var urlHash = window.location.hash.replace('#','');
-    var filterValue = '*';
+    let urlHash = window.location.hash.replace('#','');
+    let filterValue = '*';
 
     // Check if hash is numeric.
     if (urlHash != '' && !isNaN(urlHash)) {
@@ -158,48 +163,36 @@
    * On window load.
    * --------------------------------------------------------------------------- */
 
-  $(window).load(function(){
+  $(window).on('load', function() {
 
-    // When accessing publication index, enable filtering.
-    if ($('.pub-filters-select')) {
-      filter_publications();
-
-      // Useful for changing hash manually (e.g. in development):
-      // window.addEventListener('hashchange', filter_publications, false);
-    }
-
-    // Enable smooth scrolling with mouse wheel
-    smoothScroll(1.3, 220);
-
-    // When accessing homepage from another page and `#top` hash is set, show top of page (no hash).
-    if (window.location.hash == "#top") {
-      window.location.hash = ""
+    if (window.location.hash) {
+      // When accessing homepage from another page and `#top` hash is set, show top of page (no hash).
+      if (window.location.hash == "#top") {
+        window.location.hash = ""
+      } else {
+        // If URL contains a hash, scroll to target ID taking into account responsive offset.
+        scrollToAnchor();
+      }
     }
 
     // Initialize Scrollspy.
-    var $body = $('body');
-    var $navbar = $('.navbar-header');
-    var navbar_offset = $navbar.innerHeight() + 1;
+    let $body = $('body');
     $body.scrollspy({offset: navbar_offset });
 
-    // Make Scrollspy responsive.
-    function fixScrollspy() {
-      var data = $body.data('bs.scrollspy');
-      if (data) {
-        navbar_offset = $navbar.innerHeight() + 1;
-        data.options.offset = navbar_offset;
-        $body.data('bs.scrollspy', data);
-        $body.scrollspy('refresh');
-      }
-    }
-
     // Call `fixScrollspy` when window is resized.
-    var resizeTimer;
+    let resizeTimer;
     $(window).resize(function() {
       clearTimeout(resizeTimer);
       resizeTimer = setTimeout(fixScrollspy, 200);
     });
 
+    // Enable publication filter for publication index page.
+    if ($('.pub-filters-select')) {
+      filter_publications();
+      // Useful for changing hash manually (e.g. in development):
+      // window.addEventListener('hashchange', filter_publications, false);
+    }
+
   });
 
 })(jQuery);