Skip to content

Commit

Permalink
Merge pull request #80 from imarc/sticky-element-cleanup
Browse files Browse the repository at this point in the history
Sticky element cleanup
  • Loading branch information
marcelmoreau authored Feb 10, 2017
2 parents 41b07f6 + 5ce870a commit ecf2604
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 54 deletions.
85 changes: 70 additions & 15 deletions components/sticky-element.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
<div class="container">
<div class="group">
<aside class="primary">
<section style="background-color: #EEE; width: 100%;">
<h3>Sidebar</h3>
<section style="background-color: #EEE; width: 100%; z-index: 1;">
<h3>Sticky Bar</h3>
<p>
This is a simple sticky bar.
</p>
</section>
</aside>
<main>
Expand All @@ -31,23 +34,75 @@ <h1>Sticky Element</h1>
</section>

<section>
<h2>
Amet velit labore?
</h2>
<h2>Usage</h2>

<p>
Elit velit perspiciatis et deserunt quo quos fugiat! Soluta odio hic quo ullam a! Dolorum assumenda nesciunt fuga distinctio labore.
</p>
To have an element scroll with the page until it reaches the top,
then stick to the page:
<p>
Lorem laborum labore beatae accusantium dolore quibusdam quibusdam culpa! Dolore voluptatibus iste quis eos nisi optio voluptates facere placeat repellat amet! Doloribus assumenda illo deleniti laboriosam eligendi sunt sit eius! Doloribus voluptates sapiente quis nulla adipisci ad quod earum labore!
</p>
<ul>
<li>Elit aperiam nam voluptates minima!</li>
<li>Amet nostrum voluptates aperiam laudantium.</li>
<li>Ipsum eius consectetur hic enim!</li>
</ul>

<pre><code>
$('aside.primary section.toc').fix();
</code></pre>

<br />
<br />

<p>
Ipsum dolorem beatae totam dolorem omnis exercitationem maiores eligendi. Est maiores recusandae commodi unde qui beatae laborum. Dolore quaerat tenetur magni quibusdam quia, ut! Possimus aliquam quam est dolorem optio?
To do the same but stick 100 pixels before it reaches the top of the page:
</p>

<pre><code>
$('aside.primary section.toc').fix({
startOffset: 100,
});
</code></pre>

<br /><br />

<h2>Options</h2>

<dl>
<dt>
startOffset (integer, default: 0)
</dt>
<dd>
How many pixels from the top of the viewport to start sticking.
</dd>

<dt>
endOffset (integer)
</dt>
<dd>
If specified and different than startOffset, the sticky element will
animate as you scroll from the startOffset to the endOffset
while the element is fixed.
</dd>

<dt>
duration (integer)
</dt>
<dd>
If specified, the element will unstick once this number of
pixels has been scrolled.
</dd>

<dt>
until (selector)
</dt>
<dd>
If specified, the sticky element unsticks when this element scrolls even
with the sticked element.
</dd>

<dt>
stopEarly (integer, default: 0)
</dt>
<dd>
If specified, unsticks the element when it reaches this distance
from the top of an 'until' element.
</dd>
</dl>
</section>
<section>
<aside class="sticky">
Expand Down
77 changes: 38 additions & 39 deletions js/stickyElement.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
* This jQuery plugin provides the ability to stick and unstick elements
* based on the current scroll position. For example,
*
* To have an element scroll with the page until reaches the top, then
* To have an element scroll with the page until it reaches the top, then
* stick to the page:
*
* $('aside.primary section.toc').fix();
*
* To do the same, but stick 100 pixels before it reaches the top of the page:
*
* $('aside.primary section.toc').fix({
* startOffset: 100
* });
* startOffset: 100
* });
*
* To stay stuck to the top of the page for 500 pixels of vertical scrolling:
*
* $('.sticky').fix({
* startOffset: 100,
* duration: 500
* });
* startOffset: 100,
* duration: 500
* });
*
*
*
Expand All @@ -40,7 +40,7 @@
* If specified, the sticky element unsticks when this element scrolls even
* with the sticked element.
*
* stopEarly (integer, default 0)
* stopEarly (integer, default: 0)
* If specified, unsticks the element when it reaches this distance
* from the top of an 'until' element.
*/
Expand All @@ -58,34 +58,34 @@

var that = this,
state = 'init',
elem = $(elem),
dupe = elem
$elem = $(elem),
$dupe = $elem
.clone()
.addClass('fixed-element-duplicate')
.css({
visibility: 'hidden'
})
.insertAfter(elem);
.insertAfter($elem);

if ('until' in options) {
options.until = $(options.until);
options.$until = $(options.until);
}

elem.css({
$elem.css({
position: 'absolute'
});

that.startAt = function() {
return dupe.offset().top - options.startOffset;
this.startAt = function() {
return $dupe.offset().top - options.startOffset;
};

that.endAt = function() {
var offset = that.startAt();
this.endAt = function() {
var offset = this.startAt();

if ('duration' in options) {
offset += options.duration;
} else if ('until' in options) {
offset = options.until.offset().top;
offset = options.$until.offset().top;
} else {
offset = $(document).height();
}
Expand All @@ -99,55 +99,54 @@
return offset - options.stopEarly;
};

that.release = function(top) {
this.release = function(top) {
state = 'released';
elem.css({
$elem.css({
position: 'absolute',
top: '',
transform: 'translateZ(0) translate(0, ' + top + 'px)'
});
};

that.fix = function(percentage) {
var offset = options.startOffset;

if (percentage !== undefined) {
offset += (options.endOffset - options.startOffset) * percentage;
}
this.fix = function(additionalOffset) {
var offset = options.startOffset + additionalOffset;

state = 'fixed';
requestAnimationFrame(function() {
elem.css({
$elem.css({
position: 'fixed',
top: offset,
transform: ''
});
});
};

that.update = function() {
var scrollTop = $(window).scrollTop();
var start = that.startAt(),
end = that.endAt();
this.update = function() {
var scrollTop = $(window).scrollTop();
var start = that.startAt();
var end = that.endAt();
var diff = end - start;
var currentDiff = scrollTop - start;
var diffOffsets = (options.endOffset - options.startOffset) || 0;

// Above start
if (scrollTop <= start) {
if (state == 'fixed' || state == 'init') {
that.release(0);
}

// Between start and end
} else if (scrollTop <= end) {
if ('endOffset' in options && options.endOffset != options.startOffset) {
var percentage = (scrollTop - start)/(end - start);
that.fix(percentage);
if (diffOffsets) {
that.fix(diffOffsets * currentDiff / diff);
} else if (state == 'released' || state == 'init') {
that.fix(percentage);
that.fix(0);
}

// Below end
} else {
if (state == 'fixed' || state == 'init') {
if ('endOffset' in options) {
that.release(end + options.endOffset - options.startOffset - start);
} else {
that.release(end - start);
}
that.release(diff + diffOffsets);
}
}
};
Expand Down

0 comments on commit ecf2604

Please sign in to comment.