patternjavascriptMinor
Locking viewport to the top element on window resize
Viewed 0 times
thetopresizelockingelementwindowviewport
Problem
On a responsive website where elements may shrink/expand according to the size of your viewport, the elements that was at the top of your viewport at the time may get pushed down/up as the elements above them get squished/expanded. Forcing you to scroll down/up again in order to get to the same area you were looking at.
This javascript code attempts to get rid of this problem by finding and updating the element at/near the top of the viewport on load and on scroll. Then it performs a scroll towards the current top element when the size of the viewport changes.
Based heavily on the answer I've received in my SO question for this, I got the following code in the end:
```
// Define detection area (where to pick element that we will lock on to)
var DETECT_TOP = 5,
DETECT_SIDE = 60,
DETECT_HEIGHT = 60;
// Step between each check in the detection box
// laggy if too small
var DETECT_STEP_X = 50,
DETECT_STEP_Y = 10;
// Cut-off is when the element we detected is sliced
// in-between by the top of the viewport
var CUTOFF_ADJUST = true;
var viewportWidth = $(window).width();
function Node () {
var that = this;
this.element = null;
// data
this.documentOffset = {
// jQuery element.offset().top is funny in old Safari
top: function () {
if (!that.element) { return 0; }
return that.element.offsetTop + that.element.offsetParent.offsetTop;
},
bottom: function () {
if (!that.element) { return 0; }
return this.top() + $(that.element).height();
}
};
this.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner increases its height due to word-wrap, etc.)
oldTop: 0,
oldBottom: 0,
top: function () {
this.oldTop = that.documentOffset.top() - $(window).scrollTop();
return this.oldTop;
},
bottom: function () {
This javascript code attempts to get rid of this problem by finding and updating the element at/near the top of the viewport on load and on scroll. Then it performs a scroll towards the current top element when the size of the viewport changes.
Based heavily on the answer I've received in my SO question for this, I got the following code in the end:
```
// Define detection area (where to pick element that we will lock on to)
var DETECT_TOP = 5,
DETECT_SIDE = 60,
DETECT_HEIGHT = 60;
// Step between each check in the detection box
// laggy if too small
var DETECT_STEP_X = 50,
DETECT_STEP_Y = 10;
// Cut-off is when the element we detected is sliced
// in-between by the top of the viewport
var CUTOFF_ADJUST = true;
var viewportWidth = $(window).width();
function Node () {
var that = this;
this.element = null;
// data
this.documentOffset = {
// jQuery element.offset().top is funny in old Safari
top: function () {
if (!that.element) { return 0; }
return that.element.offsetTop + that.element.offsetParent.offsetTop;
},
bottom: function () {
if (!that.element) { return 0; }
return this.top() + $(that.element).height();
}
};
this.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner increases its height due to word-wrap, etc.)
oldTop: 0,
oldBottom: 0,
top: function () {
this.oldTop = that.documentOffset.top() - $(window).scrollTop();
return this.oldTop;
},
bottom: function () {
Solution
I just saw this
I think that you can remove
Less variables being declared means less memory being taken up by the website equals a faster, more responsive website.
This could be a little shorter and more to the point
By using a ternary expression
But this is Silly as @Konijn pointed out just set it
It will evaluate the conditional and set
Edit
Where you use this function can also be cleaned up by using a ternary statement
Would become this (one line statement spread across lines for viewing)
Another thing that you could do is to get rid of the function altogether, you are only using it in this one place, so you could write the ternary statement like this instead
This lowers the code count quite a bit.
this.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner increases its height due to word-wrap, etc.)
oldTop: 0,
oldBottom: 0,
top: function () {
this.oldTop = that.documentOffset.top() - $(window).scrollTop();
return this.oldTop;
},
bottom: function () {
this.oldBottom = that.documentOffset.bottom() - $(window).scrollTop();
return this.oldBottom;
}
};I think that you can remove
this.oldTop and this.oldBottom by writing it like thisthis.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner increases its height due to word-wrap, etc.)
top: function () {
return that.documentOffset.top() - $(window).scrollTop();
},
bottom: function () {
return that.documentOffset.bottom() - $(window).scrollTop();
}
};Less variables being declared means less memory being taken up by the website equals a faster, more responsive website.
This could be a little shorter and more to the point
this.wasBelowViewportTop = function () {
if (this.viewportOffset.oldTop >= 0) {
return true;
}
return false;
};By using a ternary expression
this.wasBelowViewportTop = function () { this.viewportOffset.oldTop >= 0 ? true : false; };But this is Silly as @Konijn pointed out just set it
this.wasBelowViewportTop = function () { this.viewportOffset.oldTop >= 0;};It will evaluate the conditional and set
this.wasBelowViewportTop to a true/false value.Edit
Where you use this function can also be cleaned up by using a ternary statement
if (that.wasBelowViewportTop()) {
scrollAmount -= that.viewportOffset.oldTop;
} else {
scrollAmount = that.documentOffset.bottom() - that.viewportOffset.oldBottom;
}Would become this (one line statement spread across lines for viewing)
scrollAmount = that.wasBelowViewportTop()
? scrollAmount - that.viewportOffset.oldTop
: that.documentOffset.bottom() - that.viewportOffset.oldBottom;Another thing that you could do is to get rid of the function altogether, you are only using it in this one place, so you could write the ternary statement like this instead
scrollAmount = this.viewportOffset.oldTop >= 0
? scrollAmount - that.viewportOffset.oldTop
: that.documentOffset.bottom() - that.viewportOffset.oldBottom;This lowers the code count quite a bit.
Code Snippets
this.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner <p> increases its height due to word-wrap, etc.)
oldTop: 0,
oldBottom: 0,
top: function () {
this.oldTop = that.documentOffset.top() - $(window).scrollTop();
return this.oldTop;
},
bottom: function () {
this.oldBottom = that.documentOffset.bottom() - $(window).scrollTop();
return this.oldBottom;
}
};this.viewportOffset = {
//offsets before and after resizing may be different in a responsive website
// (thinner <p> increases its height due to word-wrap, etc.)
top: function () {
return that.documentOffset.top() - $(window).scrollTop();
},
bottom: function () {
return that.documentOffset.bottom() - $(window).scrollTop();
}
};this.wasBelowViewportTop = function () {
if (this.viewportOffset.oldTop >= 0) {
return true;
}
return false;
};this.wasBelowViewportTop = function () { this.viewportOffset.oldTop >= 0 ? true : false; };this.wasBelowViewportTop = function () { this.viewportOffset.oldTop >= 0;};Context
StackExchange Code Review Q#59877, answer score: 6
Revisions (0)
No revisions yet.