Change smooth scroll script

This commit is contained in:
Maria Rushkova 2021-08-05 11:40:22 +02:00
parent db6a41c04d
commit 99a41cca04
4 changed files with 676 additions and 14 deletions

View File

@ -74,11 +74,7 @@
{% for nav in site.data.navigation %}
<li class="hover:opacity-50">
{% if nav.path %}
<a
class="nav__link"
href="{{site.url}}{{ site.baseurl }}/{{ nav.path }}"
>{{ nav.title }}</a
>
<a class="nav__link" href="{{ nav.path }}">{{ nav.title }}</a>
{% endif %} {% if nav.link %}
<a href="{{ nav.link }}" target="_blank">{{ nav.title }}</a>
{% endif %}
@ -145,11 +141,7 @@
{% for nav in site.data.navigation %}
<li class="leading-loose hover:opacity-50">
{% if nav.path %}
<a
class="nav__link"
href="{{site.url}}{{ site.baseurl }}/{{ nav.path }}"
>{{ nav.title }}</a
>
<a class="nav__link" href="{{ nav.path }}">{{ nav.title }}</a>
{% endif %} {% if nav.link %}
<a href="{{ nav.link }}" target="_blank">{{ nav.title }}</a>
{% endif %}

View File

@ -37,5 +37,6 @@
{% include footer.html %}
<script src="{{ '/assets/js/main.js' | relative_url }}"></script>
<script src="{{ '/assets/js/smooth-scroll.js' | relative_url }}"></script>
</body>
</html>

View File

@ -17,19 +17,21 @@ const closeMobileMenu = () => {
};
burger.addEventListener("click", function (e) {
e.preventDefault();
closeMobileMenu();
});
overlay.addEventListener("click", function (e) {
closeMobileMenu();
});
menuLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
closeMobileMenu();
const id = e.target.getAttribute("href").slice(1);
console.log(document.querySelector(id));
const id = e.target.getAttribute("href");
document.querySelector(id).scrollIntoView({
behavior: "smooth",
});
});
closeMobileMenu();
});
form.addEventListener("submit", function (e) {

667
assets/js/smooth-scroll.js Normal file
View File

@ -0,0 +1,667 @@
/*!
* smooth-scroll v12.1.5: Animate scrolling to anchor links
* (c) 2017 Chris Ferdinandi
* MIT License
* http://github.com/cferdinandi/smooth-scroll
*/
/**
* closest() polyfill
* @link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
*/
if (window.Element && !Element.prototype.closest) {
Element.prototype.closest = function (s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i,
el = this;
do {
i = matches.length;
while (--i >= 0 && matches.item(i) !== el) {}
} while (i < 0 && (el = el.parentElement));
return el;
};
}
/**
* requestAnimationFrame() polyfill
* By Erik Möller. Fixes from Paul Irish and Tino Zijdel.
* @link http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* @link http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
* @license MIT
*/
(function () {
var lastTime = 0;
var vendors = ["ms", "moz", "webkit", "o"];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"];
window.cancelAnimationFrame =
window[vendors[x] + "CancelAnimationFrame"] ||
window[vendors[x] + "CancelRequestAnimationFrame"];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
})();
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define([], function () {
return factory(root);
});
} else if (typeof exports === "object") {
module.exports = factory(root);
} else {
root.SmoothScroll = factory(root);
}
})(
typeof global !== "undefined"
? global
: typeof window !== "undefined"
? window
: this,
function (window) {
"use strict";
//
// Feature Test
//
var supports =
"querySelector" in document &&
"addEventListener" in window &&
"requestAnimationFrame" in window &&
"closest" in window.Element.prototype;
//
// Default settings
//
var defaults = {
// Selectors
ignore: "[data-scroll-ignore]",
header: null,
// Speed & Easing
speed: 600,
offset: 50,
easing: "easeInOutQuart",
customEasing: null,
// Callback API
before: function () {},
after: function () {},
};
//
// Utility Methods
//
/**
* Merge two or more objects. Returns a new object.
* @param {Object} objects The objects to merge together
* @returns {Object} Merged values of defaults and options
*/
var extend = function () {
// Variables
var extended = {};
var deep = false;
var i = 0;
var length = arguments.length;
// Merge the object into the extended object
var merge = function (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
extended[prop] = obj[prop];
}
}
};
// Loop through each object and conduct a merge
for (; i < length; i++) {
var obj = arguments[i];
merge(obj);
}
return extended;
};
/**
* Get the height of an element.
* @param {Node} elem The element to get the height of
* @return {Number} The element's height in pixels
*/
var getHeight = function (elem) {
return parseInt(window.getComputedStyle(elem).height, 10);
};
/**
* Escape special characters for use with querySelector
* @param {String} id The anchor ID to escape
* @author Mathias Bynens
* @link https://github.com/mathiasbynens/CSS.escape
*/
var escapeCharacters = function (id) {
// Remove leading hash
if (id.charAt(0) === "#") {
id = id.substr(1);
}
var string = String(id);
var length = string.length;
var index = -1;
var codeUnit;
var result = "";
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then throw an
// `InvalidCharacterError` exception and terminate these steps.
if (codeUnit === 0x0000) {
throw new InvalidCharacterError(
"Invalid character: the input contains U+0000."
);
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001f) ||
codeUnit == 0x007f ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(index === 1 &&
codeUnit >= 0x0030 &&
codeUnit <= 0x0039 &&
firstCodeUnit === 0x002d)
) {
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
result += "\\" + codeUnit.toString(16) + " ";
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit === 0x002d ||
codeUnit === 0x005f ||
(codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
(codeUnit >= 0x0041 && codeUnit <= 0x005a) ||
(codeUnit >= 0x0061 && codeUnit <= 0x007a)
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// http://dev.w3.org/csswg/cssom/#escape-a-character
result += "\\" + string.charAt(index);
}
return "#" + result;
};
/**
* Calculate the easing pattern
* @link https://gist.github.com/gre/1650294
* @param {String} type Easing pattern
* @param {Number} time Time animation should take to complete
* @returns {Number}
*/
var easingPattern = function (settings, time) {
var pattern;
// Default Easing Patterns
if (settings.easing === "easeInQuad") pattern = time * time; // accelerating from zero velocity
if (settings.easing === "easeOutQuad") pattern = time * (2 - time); // decelerating to zero velocity
if (settings.easing === "easeInOutQuad")
pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
if (settings.easing === "easeInCubic") pattern = time * time * time; // accelerating from zero velocity
if (settings.easing === "easeOutCubic")
pattern = --time * time * time + 1; // decelerating to zero velocity
if (settings.easing === "easeInOutCubic")
pattern =
time < 0.5
? 4 * time * time * time
: (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
if (settings.easing === "easeInQuart")
pattern = time * time * time * time; // accelerating from zero velocity
if (settings.easing === "easeOutQuart")
pattern = 1 - --time * time * time * time; // decelerating to zero velocity
if (settings.easing === "easeInOutQuart")
pattern =
time < 0.5
? 8 * time * time * time * time
: 1 - 8 * --time * time * time * time; // acceleration until halfway, then deceleration
if (settings.easing === "easeInQuint")
pattern = time * time * time * time * time; // accelerating from zero velocity
if (settings.easing === "easeOutQuint")
pattern = 1 + --time * time * time * time * time; // decelerating to zero velocity
if (settings.easing === "easeInOutQuint")
pattern =
time < 0.5
? 16 * time * time * time * time * time
: 1 + 16 * --time * time * time * time * time; // acceleration until halfway, then deceleration
// Custom Easing Patterns
if (!!settings.customEasing) pattern = settings.customEasing(time);
return pattern || time; // no easing, no acceleration
};
/**
* Determine the document's height
* @returns {Number}
*/
var getDocumentHeight = function () {
return Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.body.clientHeight,
document.documentElement.clientHeight
);
};
/**
* Calculate how far to scroll
* @param {Element} anchor The anchor element to scroll to
* @param {Number} headerHeight Height of a fixed header, if any
* @param {Number} offset Number of pixels by which to offset scroll
* @returns {Number}
*/
var getEndLocation = function (anchor, headerHeight, offset) {
var location = 0;
if (anchor.offsetParent) {
do {
location += anchor.offsetTop;
anchor = anchor.offsetParent;
} while (anchor);
}
location = Math.max(location - headerHeight - offset, 0);
return location;
};
/**
* Get the height of the fixed header
* @param {Node} header The header
* @return {Number} The height of the header
*/
var getHeaderHeight = function (header) {
return !header ? 0 : getHeight(header) + header.offsetTop;
};
/**
* Bring the anchored element into focus
* @param {Node} anchor The anchor element
* @param {Number} endLocation The end location to scroll to
* @param {Boolean} isNum If true, scroll is to a position rather than an element
*/
var adjustFocus = function (anchor, endLocation, isNum) {
// Don't run if scrolling to a number on the page
if (isNum) return;
// Otherwise, bring anchor element into focus
anchor.focus();
if (document.activeElement.id !== anchor.id) {
anchor.setAttribute("tabindex", "-1");
anchor.focus();
anchor.style.outline = "none";
}
window.scrollTo(0, endLocation);
};
/**
* Check to see if user prefers reduced motion
* @param {Object} settings Script settings
*/
var reduceMotion = function (settings) {
if (
"matchMedia" in window &&
window.matchMedia("(prefers-reduced-motion)").matches
) {
return true;
}
return false;
};
//
// SmoothScroll Constructor
//
var SmoothScroll = function (selector, options) {
//
// Variables
//
var smoothScroll = {}; // Object for public APIs
var settings,
anchor,
toggle,
fixedHeader,
headerHeight,
eventTimeout,
animationInterval;
//
// Methods
//
/**
* Cancel a scroll-in-progress
*/
smoothScroll.cancelScroll = function () {
// clearInterval(animationInterval);
cancelAnimationFrame(animationInterval);
};
/**
* Start/stop the scrolling animation
* @param {Node|Number} anchor The element or position to scroll to
* @param {Element} toggle The element that toggled the scroll event
* @param {Object} options
*/
smoothScroll.animateScroll = function (anchor, toggle, options) {
// Local settings
var animateSettings = extend(settings || defaults, options || {}); // Merge user options with defaults
// Selectors and variables
var isNum =
Object.prototype.toString.call(anchor) === "[object Number]"
? true
: false;
var anchorElem = isNum || !anchor.tagName ? null : anchor;
if (!isNum && !anchorElem) return;
var startLocation = window.pageYOffset; // Current location on the page
if (animateSettings.header && !fixedHeader) {
// Get the fixed header if not already set
fixedHeader = document.querySelector(animateSettings.header);
}
if (!headerHeight) {
// Get the height of a fixed header if one exists and not already set
headerHeight = getHeaderHeight(fixedHeader);
}
var endLocation = isNum
? anchor
: getEndLocation(
anchorElem,
headerHeight,
parseInt(
typeof animateSettings.offset === "function"
? animateSettings.offset()
: animateSettings.offset,
10
)
); // Location to scroll to
var distance = endLocation - startLocation; // distance to travel
var documentHeight = getDocumentHeight();
var timeLapsed = 0;
var start, percentage, position;
/**
* Stop the scroll animation when it reaches its target (or the bottom/top of page)
* @param {Number} position Current position on the page
* @param {Number} endLocation Scroll to location
* @param {Number} animationInterval How much to scroll on this loop
*/
var stopAnimateScroll = function (position, endLocation) {
// Get the current location
var currentLocation = window.pageYOffset;
// Check if the end location has been reached yet (or we've hit the end of the document)
if (
position == endLocation ||
currentLocation == endLocation ||
(startLocation < endLocation &&
window.innerHeight + currentLocation) >= documentHeight
) {
// Clear the animation timer
smoothScroll.cancelScroll();
// Bring the anchored element into focus
adjustFocus(anchor, endLocation, isNum);
// Run callback after animation complete
animateSettings.after(anchor, toggle);
// Reset start
start = null;
return true;
}
};
/**
* Loop scrolling animation
*/
var loopAnimateScroll = function (timestamp) {
if (!start) {
start = timestamp;
}
timeLapsed += timestamp - start;
percentage = timeLapsed / parseInt(animateSettings.speed, 10);
percentage = percentage > 1 ? 1 : percentage;
position =
startLocation +
distance * easingPattern(animateSettings, percentage);
window.scrollTo(0, Math.floor(position));
if (!stopAnimateScroll(position, endLocation)) {
window.requestAnimationFrame(loopAnimateScroll);
start = timestamp;
}
};
/**
* Reset position to fix weird iOS bug
* @link https://github.com/cferdinandi/smooth-scroll/issues/45
*/
if (window.pageYOffset === 0) {
window.scrollTo(0, 0);
}
// Run callback before animation starts
animateSettings.before(anchor, toggle);
// Start scrolling animation
smoothScroll.cancelScroll();
window.requestAnimationFrame(loopAnimateScroll);
};
/**
* Handle has change event
*/
var hashChangeHandler = function (event) {
// Only run if there's an anchor element to scroll to
if (!anchor) return;
// Reset the anchor element's ID
anchor.id = anchor.getAttribute("data-scroll-id");
// Scroll to the anchored content
smoothScroll.animateScroll(anchor, toggle);
// Reset anchor and toggle
anchor = null;
toggle = null;
};
/**
* If smooth scroll element clicked, animate scroll
*/
var clickHandler = function (event) {
// Don't run if the user prefers reduced motion
if (reduceMotion(settings)) return;
// Don't run if right-click or command/control + click
if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
// Check if a smooth scroll link was clicked
toggle = event.target.closest(selector);
if (
!toggle ||
toggle.tagName.toLowerCase() !== "a" ||
event.target.closest(settings.ignore)
)
return;
// Only run if link is an anchor and points to the current page
if (
toggle.hostname !== window.location.hostname ||
toggle.pathname !== window.location.pathname ||
!/#/.test(toggle.href)
)
return;
// Get the sanitized hash
var hash;
try {
hash = escapeCharacters(decodeURIComponent(toggle.hash));
} catch (e) {
hash = escapeCharacters(toggle.hash);
}
// If the hash is empty, scroll to the top of the page
if (hash === "#") {
// Prevent default link behavior
event.preventDefault();
// Set the anchored element
anchor = document.body;
// Save or create the ID as a data attribute and remove it (prevents scroll jump)
var id = anchor.id ? anchor.id : "smooth-scroll-top";
anchor.setAttribute("data-scroll-id", id);
anchor.id = "";
// If no hash change event will happen, fire manually
// Otherwise, update the hash
if (window.location.hash.substring(1) === id) {
hashChangeHandler();
} else {
window.location.hash = id;
}
return;
}
// Get the anchored element
anchor = document.querySelector(hash);
// If anchored element exists, save the ID as a data attribute and remove it (prevents scroll jump)
if (!anchor) return;
anchor.setAttribute("data-scroll-id", anchor.id);
anchor.id = "";
// If no hash change event will happen, fire manually
if (toggle.hash === window.location.hash) {
event.preventDefault();
hashChangeHandler();
}
};
/**
* On window scroll and resize, only run events at a rate of 15fps for better performance
*/
var resizeThrottler = function (event) {
if (!eventTimeout) {
eventTimeout = setTimeout(function () {
eventTimeout = null; // Reset timeout
headerHeight = getHeaderHeight(fixedHeader); // Get the height of a fixed header if one exists
}, 66);
}
};
/**
* Destroy the current initialization.
*/
smoothScroll.destroy = function () {
// If plugin isn't already initialized, stop
if (!settings) return;
// Remove event listeners
document.removeEventListener("click", clickHandler, false);
window.removeEventListener("resize", resizeThrottler, false);
// Cancel any scrolls-in-progress
smoothScroll.cancelScroll();
// Reset variables
settings = null;
anchor = null;
toggle = null;
fixedHeader = null;
headerHeight = null;
eventTimeout = null;
animationInterval = null;
};
/**
* Initialize Smooth Scroll
* @param {Object} options User settings
*/
smoothScroll.init = function (options) {
// feature test
if (!supports) return;
// Destroy any existing initializations
smoothScroll.destroy();
// Selectors and variables
settings = extend(defaults, options || {}); // Merge user options with defaults
fixedHeader = settings.header
? document.querySelector(settings.header)
: null; // Get the fixed header
headerHeight = getHeaderHeight(fixedHeader);
// When a toggle is clicked, run the click handler
document.addEventListener("click", clickHandler, false);
// Listen for hash changes
window.addEventListener("hashchange", hashChangeHandler, false);
// If window is resized and there's a fixed header, recalculate its size
if (fixedHeader) {
window.addEventListener("resize", resizeThrottler, false);
}
};
//
// Initialize plugin
//
smoothScroll.init(options);
//
// Public APIs
//
return smoothScroll;
};
return SmoothScroll;
}
);
var scroll = new SmoothScroll('a[href*="#"]');