From 9e1ceb13eae9d323b9f0496f1be55eccae262e25 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Thu, 1 Nov 2018 20:33:00 +0000 Subject: [PATCH 01/11] Make local copy of stick-at-top JS --- .../stick-at-top-when-scrolling.js | 128 ++++++++++++++++++ gulpfile.babel.js | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/stick-at-top-when-scrolling.js diff --git a/app/assets/javascripts/stick-at-top-when-scrolling.js b/app/assets/javascripts/stick-at-top-when-scrolling.js new file mode 100644 index 000000000..9cb9421f8 --- /dev/null +++ b/app/assets/javascripts/stick-at-top-when-scrolling.js @@ -0,0 +1,128 @@ +;(function (global) { + 'use strict' + + var $ = global.jQuery + var GOVUK = global.GOVUK || {} + + // Stick elements to top of screen when you scroll past, documentation is in the README.md + var sticky = { + _hasScrolled: false, + _scrollTimeout: false, + _hasResized: false, + _resizeTimeout: false, + + getWindowDimensions: function () { + return { + height: $(global).height(), + width: $(global).width() + } + }, + getWindowPositions: function () { + return { + scrollTop: $(global).scrollTop() + } + }, + getElementOffset: function ($el) { + return $el.offset() + }, + init: function () { + var $els = $('.js-stick-at-top-when-scrolling') + + if ($els.length > 0) { + sticky.$els = $els + + if (sticky._scrollTimeout === false) { + $(global).scroll(sticky.onScroll) + sticky._scrollTimeout = global.setInterval(sticky.checkScroll, 50) + } + + if (sticky._resizeTimeout === false) { + $(global).resize(sticky.onResize) + sticky._resizeTimeout = global.setInterval(sticky.checkResize, 50) + } + } + if (GOVUK.stopScrollingAtFooter) { + $els.each(function (i, el) { + var $img = $(el).find('img') + if ($img.length > 0) { + var image = new global.Image() + image.onload = function () { + GOVUK.stopScrollingAtFooter.addEl($(el), $(el).outerHeight()) + } + image.src = $img.attr('src') + } else { + GOVUK.stopScrollingAtFooter.addEl($(el), $(el).outerHeight()) + } + }) + } + }, + onScroll: function () { + sticky._hasScrolled = true + }, + onResize: function () { + sticky._hasResized = true + }, + checkScroll: function () { + if (sticky._hasScrolled === true) { + sticky._hasScrolled = false + + var windowVerticalPosition = sticky.getWindowPositions().scrollTop + + var windowDimensions = sticky.getWindowDimensions() + + sticky.$els.each(function (i, el) { + var $el = $(el) + var scrolledFrom = $el.data('scrolled-from') + + if (scrolledFrom && windowVerticalPosition < scrolledFrom) { + sticky.release($el) + } else if (windowDimensions.width > 768 && windowVerticalPosition >= sticky.getElementOffset($el).top) { + sticky.stick($el) + } + }) + } + }, + checkResize: function () { + if (sticky._hasResized === true) { + sticky._hasResized = false + + var windowDimensions = sticky.getWindowDimensions() + + sticky.$els.each(function (i, el) { + var $el = $(el) + + var elResize = $el.hasClass('js-sticky-resize') + if (elResize) { + var $shim = $('.shim') + var $elParent = $el.parent('div') + var elParentWidth = $elParent.width() + $shim.css('width', elParentWidth) + $el.css('width', elParentWidth) + } + + if (windowDimensions.width <= 768) { + sticky.release($el) + } + }) + } + }, + stick: function ($el) { + if (!$el.hasClass('content-fixed')) { + $el.data('scrolled-from', sticky.getElementOffset($el).top) + var height = Math.max($el.height(), 1) + var width = $el.width() + $el.before('
 
') + $el.css('width', width + 'px').addClass('content-fixed') + } + }, + release: function ($el) { + if ($el.hasClass('content-fixed')) { + $el.data('scrolled-from', false) + $el.removeClass('content-fixed').css('width', '') + $el.siblings('.shim').remove() + } + } + } + GOVUK.stickAtTopWhenScrolling = sticky + global.GOVUK = GOVUK +})(window) diff --git a/gulpfile.babel.js b/gulpfile.babel.js index a7da1e92e..1bd4b0a6f 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -60,7 +60,7 @@ gulp.task('javascripts', () => gulp paths.toolkit + 'javascripts/govuk/modules.js', paths.toolkit + 'javascripts/govuk/show-hide-content.js', paths.toolkit + 'javascripts/govuk/stop-scrolling-at-footer.js', - paths.toolkit + 'javascripts/govuk/stick-at-top-when-scrolling.js', + paths.src + 'javascripts/stick-at-top-when-scrolling.js', paths.src + 'javascripts/detailsPolyfill.js', paths.src + 'javascripts/apiKey.js', paths.src + 'javascripts/autofocus.js', From 53d43073efdee56d6889255dd5c287ad180ce6e0 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Thu, 1 Nov 2018 20:58:35 +0000 Subject: [PATCH 02/11] Refactor stick-at-top to remove top-specific code --- .../stick-at-top-when-scrolling.js | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/stick-at-top-when-scrolling.js b/app/assets/javascripts/stick-at-top-when-scrolling.js index 9cb9421f8..42636c47d 100644 --- a/app/assets/javascripts/stick-at-top-when-scrolling.js +++ b/app/assets/javascripts/stick-at-top-when-scrolling.js @@ -31,6 +31,12 @@ if ($els.length > 0) { sticky.$els = $els + $els.each(function (i, el) { + var $el = $(el) + + $el.data('scrolled-from', sticky.getElementOffset($el).top) + }) + if (sticky._scrollTimeout === false) { $(global).scroll(sticky.onScroll) sticky._scrollTimeout = global.setInterval(sticky.checkScroll, 50) @@ -62,21 +68,24 @@ onResize: function () { sticky._hasResized = true }, + scrolledFromInsideWindow: function (scrolledFrom) { + var windowVerticalPosition = sticky.getWindowPositions().scrollTop + + return windowVerticalPosition < scrolledFrom + }, checkScroll: function () { if (sticky._hasScrolled === true) { sticky._hasScrolled = false - var windowVerticalPosition = sticky.getWindowPositions().scrollTop - var windowDimensions = sticky.getWindowDimensions() sticky.$els.each(function (i, el) { var $el = $(el) var scrolledFrom = $el.data('scrolled-from') - if (scrolledFrom && windowVerticalPosition < scrolledFrom) { + if (scrolledFrom && sticky.scrolledFromInsideWindow(scrolledFrom)) { sticky.release($el) - } else if (windowDimensions.width > 768 && windowVerticalPosition >= sticky.getElementOffset($el).top) { + } else if (windowDimensions.width > 768 && !sticky.scrolledFromInsideWindow(scrolledFrom)) { sticky.stick($el) } }) @@ -106,18 +115,20 @@ }) } }, + addShimForEl: function ($el, width, height) { + $el.before('
 
') + }, stick: function ($el) { if (!$el.hasClass('content-fixed')) { - $el.data('scrolled-from', sticky.getElementOffset($el).top) var height = Math.max($el.height(), 1) var width = $el.width() - $el.before('
 
') + + sticky.addShimForEl($el, width, height) $el.css('width', width + 'px').addClass('content-fixed') } }, release: function ($el) { if ($el.hasClass('content-fixed')) { - $el.data('scrolled-from', false) $el.removeClass('content-fixed').css('width', '') $el.siblings('.shim').remove() } From ef76d4eeb3e71d81cb4f397e3820a1840cfb9875 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Sun, 4 Nov 2018 21:10:02 +0000 Subject: [PATCH 03/11] Record height of each sticky element Function borrowed from stop-at-bottom JS. --- .../stick-at-top-when-scrolling.js | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/stick-at-top-when-scrolling.js b/app/assets/javascripts/stick-at-top-when-scrolling.js index 42636c47d..964ba2b9b 100644 --- a/app/assets/javascripts/stick-at-top-when-scrolling.js +++ b/app/assets/javascripts/stick-at-top-when-scrolling.js @@ -10,6 +10,7 @@ _scrollTimeout: false, _hasResized: false, _resizeTimeout: false, + _els: [], getWindowDimensions: function () { return { @@ -25,15 +26,35 @@ getElementOffset: function ($el) { return $el.offset() }, + setElHeight: function (el) { + var fixedOffset = parseInt(el.$fixedEl.css('top'), 10) + var $el = el.$fixedEl + var $img = $el.find('img') + + fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset + + if ($img.length > 0) { + var image = new global.Image() + image.onload = function () { + el.height = $el.outerHeight() + fixedOffset + } + image.src = $img.attr('src') + } else { + el.height = $el.outerHeight() + fixedOffset + } + }, init: function () { var $els = $('.js-stick-at-top-when-scrolling') if ($els.length > 0) { - sticky.$els = $els - $els.each(function (i, el) { var $el = $(el) - + var el = { + $fixedEl: $el + } + + sticky.setElHeight(el) + sticky._els.push(el) $el.data('scrolled-from', sticky.getElementOffset($el).top) }) @@ -47,20 +68,6 @@ sticky._resizeTimeout = global.setInterval(sticky.checkResize, 50) } } - if (GOVUK.stopScrollingAtFooter) { - $els.each(function (i, el) { - var $img = $(el).find('img') - if ($img.length > 0) { - var image = new global.Image() - image.onload = function () { - GOVUK.stopScrollingAtFooter.addEl($(el), $(el).outerHeight()) - } - image.src = $img.attr('src') - } else { - GOVUK.stopScrollingAtFooter.addEl($(el), $(el).outerHeight()) - } - }) - } }, onScroll: function () { sticky._hasScrolled = true @@ -79,8 +86,8 @@ var windowDimensions = sticky.getWindowDimensions() - sticky.$els.each(function (i, el) { - var $el = $(el) + $.each(sticky._els, function (i, el) { + var $el = el.$fixedEl var scrolledFrom = $el.data('scrolled-from') if (scrolledFrom && sticky.scrolledFromInsideWindow(scrolledFrom)) { @@ -97,8 +104,8 @@ var windowDimensions = sticky.getWindowDimensions() - sticky.$els.each(function (i, el) { - var $el = $(el) + $.each(sticky._els, function (i, el) { + var $el = el.$fixedEl var elResize = $el.hasClass('js-sticky-resize') if (elResize) { From deaa253e658adae04c0e6caf1443a862fcc3f2a5 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Mon, 5 Nov 2018 17:47:25 +0000 Subject: [PATCH 04/11] Add stop-at-bottom functionality Detach all methods from sticky reference so they can be attached to different objects. Split sticky into stickAtTop and stickAtBottom and make new versions of all methods and properties specific to stickAtBottom. Add CSS for stickAtBottom and call on load --- app/assets/javascripts/main.js | 1 + .../stick-at-top-when-scrolling.js | 349 +++++++++++------- .../stick-at-top-when-scrolling.scss | 47 ++- 3 files changed, 263 insertions(+), 134 deletions(-) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index c04229cac..33ef38a0c 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -1,6 +1,7 @@ $(() => $("time.timeago").timeago()); $(() => GOVUK.stickAtTopWhenScrolling.init()); +$(() => GOVUK.stickAtBottomWhenScrolling.init()); var showHideContent = new GOVUK.ShowHideContent(); showHideContent.init(); diff --git a/app/assets/javascripts/stick-at-top-when-scrolling.js b/app/assets/javascripts/stick-at-top-when-scrolling.js index 964ba2b9b..8541d8a09 100644 --- a/app/assets/javascripts/stick-at-top-when-scrolling.js +++ b/app/assets/javascripts/stick-at-top-when-scrolling.js @@ -5,142 +5,243 @@ var GOVUK = global.GOVUK || {} // Stick elements to top of screen when you scroll past, documentation is in the README.md - var sticky = { - _hasScrolled: false, - _scrollTimeout: false, - _hasResized: false, - _resizeTimeout: false, - _els: [], + var Sticky = function (selector) { + this._hasScrolled: false + this._scrollTimeout: false + this._hasResized: false + this._resizeTimeout: false + this._els: [] - getWindowDimensions: function () { - return { - height: $(global).height(), - width: $(global).width() - } - }, - getWindowPositions: function () { - return { - scrollTop: $(global).scrollTop() - } - }, - getElementOffset: function ($el) { - return $el.offset() - }, - setElHeight: function (el) { - var fixedOffset = parseInt(el.$fixedEl.css('top'), 10) - var $el = el.$fixedEl - var $img = $el.find('img') + this.CSS_SELECTOR: selector + } + Sticky.prototype.getWindowDimensions = function () { + return { + height: $(global).height(), + width: $(global).width() + } + } + Sticky.prototype.getWindowPositions = function () { + return { + scrollTop: $(global).scrollTop() + } + } + Sticky.prototype.setFixedTop = function (el) { + var $siblingEl = $('
') + $siblingEl.insertBefore(el.$fixedEl) + var fixedTop = $siblingEl.offset().top - $siblingEl.position().top + $siblingEl.remove() - fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset + el.fixedTop = fixedTop + } + Sticky.prototype.setElHeight = function (el) { + var self = this + var fixedOffset = parseInt(el.$fixedEl.css('top'), 10) + var $el = el.$fixedEl + var $img = $el.find('img') - if ($img.length > 0) { - var image = new global.Image() - image.onload = function () { - el.height = $el.outerHeight() + fixedOffset - } - image.src = $img.attr('src') - } else { + fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset + + if ($img.length > 0) { + var image = new global.Image() + image.onload = function () { el.height = $el.outerHeight() + fixedOffset + el.scrolledTo = self.getScrollingTo(el) } - }, - init: function () { - var $els = $('.js-stick-at-top-when-scrolling') + image.src = $img.attr('src') + } else { + el.height = $el.outerHeight() + fixedOffset + el.scrolledTo = self.getScrollingTo(el) + } + } + Sticky.prototype.init = function () { + var self = this + var $els = $(self.CSS_SELECTOR) - if ($els.length > 0) { - $els.each(function (i, el) { - var $el = $(el) - var el = { - $fixedEl: $el - } - - sticky.setElHeight(el) - sticky._els.push(el) - $el.data('scrolled-from', sticky.getElementOffset($el).top) - }) - - if (sticky._scrollTimeout === false) { - $(global).scroll(sticky.onScroll) - sticky._scrollTimeout = global.setInterval(sticky.checkScroll, 50) + if ($els.length > 0) { + $els.each(function (i, el) { + var $el = $(el) + var el = { + $fixedEl: $el, + scrolledFrom: self.getScrolledFrom($el), + stopped: false } - if (sticky._resizeTimeout === false) { - $(global).resize(sticky.onResize) - sticky._resizeTimeout = global.setInterval(sticky.checkResize, 50) - } + self.setFixedTop(el) + self.setElHeight(el) + self._els.push(el) + }) + + if (self._scrollTimeout === false) { + $(global).scroll(function (e) { self.onScroll() }) + self._scrollTimeout = global.setInterval(function (e) { self.checkScroll() }, 50) } - }, - onScroll: function () { - sticky._hasScrolled = true - }, - onResize: function () { - sticky._hasResized = true - }, - scrolledFromInsideWindow: function (scrolledFrom) { - var windowVerticalPosition = sticky.getWindowPositions().scrollTop - return windowVerticalPosition < scrolledFrom - }, - checkScroll: function () { - if (sticky._hasScrolled === true) { - sticky._hasScrolled = false - - var windowDimensions = sticky.getWindowDimensions() - - $.each(sticky._els, function (i, el) { - var $el = el.$fixedEl - var scrolledFrom = $el.data('scrolled-from') - - if (scrolledFrom && sticky.scrolledFromInsideWindow(scrolledFrom)) { - sticky.release($el) - } else if (windowDimensions.width > 768 && !sticky.scrolledFromInsideWindow(scrolledFrom)) { - sticky.stick($el) - } - }) - } - }, - checkResize: function () { - if (sticky._hasResized === true) { - sticky._hasResized = false - - var windowDimensions = sticky.getWindowDimensions() - - $.each(sticky._els, function (i, el) { - var $el = el.$fixedEl - - var elResize = $el.hasClass('js-sticky-resize') - if (elResize) { - var $shim = $('.shim') - var $elParent = $el.parent('div') - var elParentWidth = $elParent.width() - $shim.css('width', elParentWidth) - $el.css('width', elParentWidth) - } - - if (windowDimensions.width <= 768) { - sticky.release($el) - } - }) - } - }, - addShimForEl: function ($el, width, height) { - $el.before('
 
') - }, - stick: function ($el) { - if (!$el.hasClass('content-fixed')) { - var height = Math.max($el.height(), 1) - var width = $el.width() - - sticky.addShimForEl($el, width, height) - $el.css('width', width + 'px').addClass('content-fixed') - } - }, - release: function ($el) { - if ($el.hasClass('content-fixed')) { - $el.removeClass('content-fixed').css('width', '') - $el.siblings('.shim').remove() + if (self._resizeTimeout === false) { + $(global).resize(function (e) { self.onResize() }) + self._resizeTimeout = global.setInterval(function (e) { self.checkResize() }, 50) } } } - GOVUK.stickAtTopWhenScrolling = sticky + Sticky.prototype.onScroll = function () { + this._hasScrolled = true + } + Sticky.prototype.onResize = function () { + this._hasResized = true + } + Sticky.prototype.viewportIsWideEnough = function (windowWidth) { + return windowWidth > 768 + } + Sticky.prototype.checkScroll = function () { + var self = this + + if (self._hasScrolled === true) { + self._hasScrolled = false + + $.each(self._els, function (i, el) { + var $el = el.$fixedEl + + var windowDimensions = self.getWindowDimensions() + + if (self.scrolledFromInsideWindow(el.scrolledFrom)) { + self.release($el) + } else { + if (self.scrolledToOutsideWindow(el, windowDimensions.height)) { + self.stop(el) + } else if (self.viewportIsWideEnough(windowDimensions.width)) { + if (el.stopped) { + self.unstop(el) + } + self.stick($el) + } + } + }) + } + } + Sticky.prototype.checkResize = function () { + var self = this + + if (self._hasResized === true) { + self._hasResized = false + + var windowDimensions = self.getWindowDimensions() + + $.each(self._els, function (i, el) { + var $el = el.$fixedEl + + var elResize = $el.hasClass('js-self-resize') + if (elResize) { + var $shim = $('.shim') + var $elParent = $el.parent('div') + var elParentWidth = $elParent.width() + $shim.css('width', elParentWidth) + $el.css('width', elParentWidth) + } + + if (windowDimensions.width <= 768) { + self.release($el) + } + }) + } + } + Sticky.prototype.stick = function ($el) { + if (!$el.hasClass('content-fixed')) { + var height = Math.max($el.height(), 1) + var width = $el.width() + + this.addShimForEl($el, width, height) + $el.css('width', width + 'px').addClass('content-fixed') + } + } + Sticky.prototype.release = function ($el) { + if ($el.hasClass('content-fixed')) { + $el.removeClass('content-fixed').css('width', '') + $el.siblings('.shim').remove() + } + } + + var stickAtTop = new Sticky('.js-stick-at-top-when-scrolling') + stickAtTop.getScrolledFrom = function ($el) { + return $el.offset().top + } + stickAtTop.getScrollingTo = function (el) { + var footer = $('.js-footer:eq(0)') + if (footer.length === 0) { + return 0 + } + return (footer.offset().top - 10) - el.height + } + stickAtTop.scrolledFromInsideWindow = function (scrolledFrom) { + var windowTop = this.getWindowPositions().scrollTop + + return scrolledFrom > windowTop + } + stickAtTop.scrolledToOutsideWindow = function (el, windowHeight) { + var windowTop = this.getWindowPositions().scrollTop + + return windowTop > el.scrolledTo + } + stickAtTop.addShimForEl = function ($el, width, height) { + $el.before('
 
') + } + stickAtTop.stop = function (el) { + if (!el.stopped) { + el.$fixedEl.css({ 'position': 'absolute', 'top': el.scrolledTo }) + el.stopped = true + } + } + stickAtTop.unstop = function (el) { + if (el.stopped) { + el.$fixedEl.css({ 'position': '', 'top': '' }) + el.stopped = false + } + } + + var stickAtBottom = new Sticky('.js-stick-at-bottom-when-scrolling') + stickAtBottom.getScrolledFrom = function ($el) { + return $el.offset().top + $el.outerHeight() + } + stickAtBottom.getScrollingTo = function (el) { + var header = $('.js-header:eq(0)') + if (header.length === 0) { + return 0 + } + return (header.offset().top + header.outerHeight() + 10) + el.height + } + stickAtBottom.scrolledFromInsideWindow = function (scrolledFrom) { + var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height + + return scrolledFrom < windowBottom + } + stickAtBottom.scrolledToOutsideWindow = function (el, windowHeight) { + var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height + + return windowBottom < el.scrolledTo + } + stickAtBottom.addShimForEl = function ($el, width, height) { + $el.after('
 
') + } + stickAtBottom.stop = function (el) { + if (!el.stopped) { + el.$fixedEl.css({ + 'position': 'absolute', + 'top': (el.scrolledTo - el.height), + 'bottom': 'auto' + }) + el.stopped = true + } + } + stickAtBottom.unstop = function (el) { + if (el.stopped) { + el.$fixedEl.css({ + 'position': '', + 'top': '', + 'bottom': '' + }) + el.stopped = false + } + } + + GOVUK.stickAtTopWhenScrolling = stickAtTop + GOVUK.stickAtBottomWhenScrolling = stickAtBottom global.GOVUK = GOVUK })(window) diff --git a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss index 77d076ff1..516e44a13 100644 --- a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss +++ b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss @@ -1,16 +1,13 @@ // CSS adapted from // https://github.com/alphagov/govuk_frontend_toolkit/blob/d9489a987086471fe30b4b925a81c12cd198c91d/docs/javascript.md#stick-at-top-when-scrolling -.js-stick-at-top-when-scrolling { +.js-stick-at-top-when-scrolling, +.js-stick-at-bottom-when-scrolling { overflow: hidden; margin-left: -$gutter-half; - margin-top: -10px; - margin-bottom: 5px; padding: 10px 0 0 $gutter-half; position: relative; - top: 5px; - transition: top 0.1s ease-out, box-shadow 1s ease-in-out; .form-group { margin-bottom: 20px; @@ -32,17 +29,27 @@ } +.js-stick-at-top-when-scrolling { + + margin-top: -10px; + margin-bottom: 5px; + top: 5px; + transition: top 0.1s ease-out, box-shadow 1s ease-in-out; + +} + +.js-stick-at-top-when-scrolling { + + transition: bottom 0.1s ease-out, box-shadow 1s ease-in-out; + +} + .content-fixed { position: fixed; - top: 0; background: $white; z-index: 100; - margin-top: 0; padding-right: $gutter-half; - border-bottom: 1px solid $border-colour; - box-shadow: 0 2px 0 0 rgba($border-colour, 0.2); - transition: background 0.6s ease-in-out, margin-top 0.4s ease-out; .back-to-top-link { opacity: 1; @@ -51,6 +58,26 @@ } +.js-stick-at-top-when-scrolling.content-fixed { + + top: 0; + margin-top: 0; + border-bottom: 1px solid $border-colour; + box-shadow: 0 2px 0 0 rgba($border-colour, 0.2); + transition: background 0.6s ease-in-out, margin-top 0.4s ease-out; + +} + +.js-stick-at-bottom-when-scrolling.content-fixed { + + top: auto; // cancel `top: 0;` inherited from govuk-template + bottom: 0; + border-top: 1px solid $border-colour; + box-shadow: 0 -2px 0 0 rgba($border-colour, 0.2); + transition: background 0.6s ease-in-out; + +} + .shim { display: block; margin-bottom: 5px; From fd7c03d22469b62969d7ab3985346f9088bd4d52 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Mon, 5 Nov 2018 13:13:31 +0000 Subject: [PATCH 05/11] Remove stop-at-footer JS This functionality will be included in the stick-to-top JS. Removing it here to start that work with a blank slate. --- gulpfile.babel.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 1bd4b0a6f..cfd537887 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -59,7 +59,6 @@ gulp.task('javascripts', () => gulp .src([ paths.toolkit + 'javascripts/govuk/modules.js', paths.toolkit + 'javascripts/govuk/show-hide-content.js', - paths.toolkit + 'javascripts/govuk/stop-scrolling-at-footer.js', paths.src + 'javascripts/stick-at-top-when-scrolling.js', paths.src + 'javascripts/detailsPolyfill.js', paths.src + 'javascripts/apiKey.js', From fa1d669f4f5d5a8a53916affdeba4d658ac81eb2 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Thu, 8 Nov 2018 12:20:57 +0000 Subject: [PATCH 06/11] Rename script to reflect what it now does --- ...-top-when-scrolling.js => stick-to-window-when-scrolling.js} | 0 gulpfile.babel.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename app/assets/javascripts/{stick-at-top-when-scrolling.js => stick-to-window-when-scrolling.js} (100%) diff --git a/app/assets/javascripts/stick-at-top-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js similarity index 100% rename from app/assets/javascripts/stick-at-top-when-scrolling.js rename to app/assets/javascripts/stick-to-window-when-scrolling.js diff --git a/gulpfile.babel.js b/gulpfile.babel.js index cfd537887..73d7e2375 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -59,7 +59,7 @@ gulp.task('javascripts', () => gulp .src([ paths.toolkit + 'javascripts/govuk/modules.js', paths.toolkit + 'javascripts/govuk/show-hide-content.js', - paths.src + 'javascripts/stick-at-top-when-scrolling.js', + paths.src + 'javascripts/stick-to-window-when-scrolling.js', paths.src + 'javascripts/detailsPolyfill.js', paths.src + 'javascripts/apiKey.js', paths.src + 'javascripts/autofocus.js', From 412b1f1117333024c760d65c0f80a9381faa3659 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Thu, 8 Nov 2018 12:41:00 +0000 Subject: [PATCH 07/11] Add extra checks for resize and onload Position of elements are normally checked when you scroll but we also need it to check when the page loads. Re-calculate element positions if window resizes. Adds a flag to mark if all elements have a height which will not change as their contents have loaded. --- .../stick-to-window-when-scrolling.js | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/stick-to-window-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js index 8541d8a09..f0e5cbe47 100644 --- a/app/assets/javascripts/stick-to-window-when-scrolling.js +++ b/app/assets/javascripts/stick-to-window-when-scrolling.js @@ -6,13 +6,14 @@ // Stick elements to top of screen when you scroll past, documentation is in the README.md var Sticky = function (selector) { - this._hasScrolled: false - this._scrollTimeout: false - this._hasResized: false - this._resizeTimeout: false - this._els: [] + this._hasScrolled = false + this._scrollTimeout = false + this._hasResized = false + this._resizeTimeout = false + this._elsLoaded = false + this._els = [] - this.CSS_SELECTOR: selector + this.CSS_SELECTOR = selector } Sticky.prototype.getWindowDimensions = function () { return { @@ -41,18 +42,23 @@ fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset - if ($img.length > 0) { + if ((!self._elsLoaded) && ($img.length > 0)) { var image = new global.Image() image.onload = function () { el.height = $el.outerHeight() + fixedOffset el.scrolledTo = self.getScrollingTo(el) + self.checkElementsLoaded() } image.src = $img.attr('src') } else { el.height = $el.outerHeight() + fixedOffset el.scrolledTo = self.getScrollingTo(el) + self.checkElementsLoaded() } } + Sticky.prototype.checkElementsLoaded = function () { + this._elsLoaded = $.grep(this._els, function (el) { return ('height' in el) }).length === this._els.length + } Sticky.prototype.init = function () { var self = this var $els = $(self.CSS_SELECTOR) @@ -80,6 +86,10 @@ $(global).resize(function (e) { self.onResize() }) self._resizeTimeout = global.setInterval(function (e) { self.checkResize() }, 50) } + + // fake scrolling to allow us to check the position of the elements + self._hasScrolled = true + self.checkScroll() } } Sticky.prototype.onScroll = function () { @@ -135,9 +145,10 @@ var elParentWidth = $elParent.width() $shim.css('width', elParentWidth) $el.css('width', elParentWidth) + self.setElHeight(el) } - if (windowDimensions.width <= 768) { + if (!self.viewportIsWideEnough(windowDimensions.width)) { self.release($el) } }) From c04c57b043b3822965c01e0de2a39a04f730ac76 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Thu, 8 Nov 2018 15:04:15 +0000 Subject: [PATCH 08/11] Fix linting errors --- .../stick-to-window-when-scrolling.js | 276 +++++++++--------- 1 file changed, 138 insertions(+), 138 deletions(-) diff --git a/app/assets/javascripts/stick-to-window-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js index f0e5cbe47..67c519820 100644 --- a/app/assets/javascripts/stick-to-window-when-scrolling.js +++ b/app/assets/javascripts/stick-to-window-when-scrolling.js @@ -1,258 +1,258 @@ ;(function (global) { - 'use strict' + 'use strict'; - var $ = global.jQuery - var GOVUK = global.GOVUK || {} + var $ = global.jQuery; + var GOVUK = global.GOVUK || {}; // Stick elements to top of screen when you scroll past, documentation is in the README.md var Sticky = function (selector) { - this._hasScrolled = false - this._scrollTimeout = false - this._hasResized = false - this._resizeTimeout = false - this._elsLoaded = false - this._els = [] + this._hasScrolled = false; + this._scrollTimeout = false; + this._hasResized = false; + this._resizeTimeout = false; + this._elsLoaded = false; + this._els = []; - this.CSS_SELECTOR = selector - } + this.CSS_SELECTOR = selector; + }; Sticky.prototype.getWindowDimensions = function () { return { height: $(global).height(), width: $(global).width() - } - } + }; + }; Sticky.prototype.getWindowPositions = function () { return { scrollTop: $(global).scrollTop() - } - } + }; + }; Sticky.prototype.setFixedTop = function (el) { - var $siblingEl = $('
') - $siblingEl.insertBefore(el.$fixedEl) - var fixedTop = $siblingEl.offset().top - $siblingEl.position().top - $siblingEl.remove() + var $siblingEl = $('
'); + $siblingEl.insertBefore(el.$fixedEl); + var fixedTop = $siblingEl.offset().top - $siblingEl.position().top; + $siblingEl.remove(); - el.fixedTop = fixedTop - } + el.fixedTop = fixedTop; + }; Sticky.prototype.setElHeight = function (el) { - var self = this - var fixedOffset = parseInt(el.$fixedEl.css('top'), 10) - var $el = el.$fixedEl - var $img = $el.find('img') + var self = this; + var fixedOffset = parseInt(el.$fixedEl.css('top'), 10); + var $el = el.$fixedEl; + var $img = $el.find('img'); - fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset + fixedOffset = isNaN(fixedOffset) ? 0 : fixedOffset; if ((!self._elsLoaded) && ($img.length > 0)) { - var image = new global.Image() + var image = new global.Image(); image.onload = function () { - el.height = $el.outerHeight() + fixedOffset - el.scrolledTo = self.getScrollingTo(el) - self.checkElementsLoaded() - } - image.src = $img.attr('src') + el.height = $el.outerHeight() + fixedOffset; + el.scrolledTo = self.getScrollingTo(el); + self.checkElementsLoaded(); + }; + image.src = $img.attr('src'); } else { - el.height = $el.outerHeight() + fixedOffset - el.scrolledTo = self.getScrollingTo(el) - self.checkElementsLoaded() + el.height = $el.outerHeight() + fixedOffset; + el.scrolledTo = self.getScrollingTo(el); + self.checkElementsLoaded(); } - } + }; Sticky.prototype.checkElementsLoaded = function () { - this._elsLoaded = $.grep(this._els, function (el) { return ('height' in el) }).length === this._els.length - } + this._elsLoaded = $.grep(this._els, function (el) { return ('height' in el); }).length === this._els.length; + }; Sticky.prototype.init = function () { - var self = this - var $els = $(self.CSS_SELECTOR) + var self = this; + var $els = $(self.CSS_SELECTOR); if ($els.length > 0) { $els.each(function (i, el) { - var $el = $(el) - var el = { + var $el = $(el); + var elObj = { $fixedEl: $el, scrolledFrom: self.getScrolledFrom($el), stopped: false - } + }; - self.setFixedTop(el) - self.setElHeight(el) - self._els.push(el) - }) + self.setFixedTop(elObj); + self.setElHeight(elObj); + self._els.push(elObj); + }); if (self._scrollTimeout === false) { - $(global).scroll(function (e) { self.onScroll() }) - self._scrollTimeout = global.setInterval(function (e) { self.checkScroll() }, 50) + $(global).scroll(function (e) { self.onScroll(); }); + self._scrollTimeout = global.setInterval(function (e) { self.checkScroll(); }, 50); } if (self._resizeTimeout === false) { - $(global).resize(function (e) { self.onResize() }) - self._resizeTimeout = global.setInterval(function (e) { self.checkResize() }, 50) + $(global).resize(function (e) { self.onResize(); }); + self._resizeTimeout = global.setInterval(function (e) { self.checkResize(); }, 50); } // fake scrolling to allow us to check the position of the elements - self._hasScrolled = true - self.checkScroll() + self._hasScrolled = true; + self.checkScroll(); } - } + }; Sticky.prototype.onScroll = function () { - this._hasScrolled = true - } + this._hasScrolled = true; + }; Sticky.prototype.onResize = function () { - this._hasResized = true - } + this._hasResized = true; + }; Sticky.prototype.viewportIsWideEnough = function (windowWidth) { - return windowWidth > 768 - } + return windowWidth > 768; + }; Sticky.prototype.checkScroll = function () { - var self = this + var self = this; if (self._hasScrolled === true) { - self._hasScrolled = false + self._hasScrolled = false; $.each(self._els, function (i, el) { - var $el = el.$fixedEl + var $el = el.$fixedEl; - var windowDimensions = self.getWindowDimensions() + var windowDimensions = self.getWindowDimensions(); if (self.scrolledFromInsideWindow(el.scrolledFrom)) { - self.release($el) + self.release($el); } else { if (self.scrolledToOutsideWindow(el, windowDimensions.height)) { - self.stop(el) + self.stop(el); } else if (self.viewportIsWideEnough(windowDimensions.width)) { if (el.stopped) { - self.unstop(el) + self.unstop(el); } - self.stick($el) + self.stick($el); } } - }) + }); } - } + }; Sticky.prototype.checkResize = function () { - var self = this + var self = this; if (self._hasResized === true) { - self._hasResized = false + self._hasResized = false; - var windowDimensions = self.getWindowDimensions() + var windowDimensions = self.getWindowDimensions(); $.each(self._els, function (i, el) { - var $el = el.$fixedEl + var $el = el.$fixedEl; - var elResize = $el.hasClass('js-self-resize') + var elResize = $el.hasClass('js-self-resize'); if (elResize) { - var $shim = $('.shim') - var $elParent = $el.parent('div') - var elParentWidth = $elParent.width() - $shim.css('width', elParentWidth) - $el.css('width', elParentWidth) - self.setElHeight(el) + var $shim = $('.shim'); + var $elParent = $el.parent('div'); + var elParentWidth = $elParent.width(); + $shim.css('width', elParentWidth); + $el.css('width', elParentWidth); + self.setElHeight(el); } if (!self.viewportIsWideEnough(windowDimensions.width)) { - self.release($el) + self.release($el); } - }) + }); } - } + }; Sticky.prototype.stick = function ($el) { if (!$el.hasClass('content-fixed')) { - var height = Math.max($el.height(), 1) - var width = $el.width() + var height = Math.max($el.height(), 1); + var width = $el.width(); - this.addShimForEl($el, width, height) - $el.css('width', width + 'px').addClass('content-fixed') + this.addShimForEl($el, width, height); + $el.css('width', width + 'px').addClass('content-fixed'); } - } + }; Sticky.prototype.release = function ($el) { if ($el.hasClass('content-fixed')) { - $el.removeClass('content-fixed').css('width', '') - $el.siblings('.shim').remove() + $el.removeClass('content-fixed').css('width', ''); + $el.siblings('.shim').remove(); } - } + }; - var stickAtTop = new Sticky('.js-stick-at-top-when-scrolling') + var stickAtTop = new Sticky('.js-stick-at-top-when-scrolling'); stickAtTop.getScrolledFrom = function ($el) { - return $el.offset().top - } + return $el.offset().top; + }; stickAtTop.getScrollingTo = function (el) { - var footer = $('.js-footer:eq(0)') + var footer = $('.js-footer:eq(0)'); if (footer.length === 0) { - return 0 + return 0; } - return (footer.offset().top - 10) - el.height - } + return (footer.offset().top - 10) - el.height; + }; stickAtTop.scrolledFromInsideWindow = function (scrolledFrom) { - var windowTop = this.getWindowPositions().scrollTop + var windowTop = this.getWindowPositions().scrollTop; - return scrolledFrom > windowTop - } + return scrolledFrom > windowTop; + }; stickAtTop.scrolledToOutsideWindow = function (el, windowHeight) { - var windowTop = this.getWindowPositions().scrollTop + var windowTop = this.getWindowPositions().scrollTop; - return windowTop > el.scrolledTo - } + return windowTop > el.scrolledTo; + }; stickAtTop.addShimForEl = function ($el, width, height) { - $el.before('
 
') - } + $el.before('
 
'); + }; stickAtTop.stop = function (el) { if (!el.stopped) { - el.$fixedEl.css({ 'position': 'absolute', 'top': el.scrolledTo }) - el.stopped = true + el.$fixedEl.css({ 'position': 'absolute', 'top': el.scrolledTo }); + el.stopped = true; } - } + }; stickAtTop.unstop = function (el) { if (el.stopped) { - el.$fixedEl.css({ 'position': '', 'top': '' }) - el.stopped = false + el.$fixedEl.css({ 'position': '', 'top': '' }); + el.stopped = false; } - } + }; - var stickAtBottom = new Sticky('.js-stick-at-bottom-when-scrolling') + var stickAtBottom = new Sticky('.js-stick-at-bottom-when-scrolling'); stickAtBottom.getScrolledFrom = function ($el) { - return $el.offset().top + $el.outerHeight() - } + return $el.offset().top + $el.outerHeight(); + }; stickAtBottom.getScrollingTo = function (el) { - var header = $('.js-header:eq(0)') + var header = $('.js-header:eq(0)'); if (header.length === 0) { - return 0 + return 0; } - return (header.offset().top + header.outerHeight() + 10) + el.height - } + return (header.offset().top + header.outerHeight() + 10) + el.height; + }; stickAtBottom.scrolledFromInsideWindow = function (scrolledFrom) { - var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height + var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height; - return scrolledFrom < windowBottom - } + return scrolledFrom < windowBottom; + }; stickAtBottom.scrolledToOutsideWindow = function (el, windowHeight) { - var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height + var windowBottom = this.getWindowPositions().scrollTop + this.getWindowDimensions().height; - return windowBottom < el.scrolledTo - } + return windowBottom < el.scrolledTo; + }; stickAtBottom.addShimForEl = function ($el, width, height) { - $el.after('
 
') - } + $el.after('
 
'); + }; stickAtBottom.stop = function (el) { if (!el.stopped) { el.$fixedEl.css({ 'position': 'absolute', 'top': (el.scrolledTo - el.height), 'bottom': 'auto' - }) - el.stopped = true + }); + el.stopped = true; } - } + }; stickAtBottom.unstop = function (el) { if (el.stopped) { el.$fixedEl.css({ 'position': '', 'top': '', 'bottom': '' - }) - el.stopped = false + }); + el.stopped = false; } - } + }; - GOVUK.stickAtTopWhenScrolling = stickAtTop - GOVUK.stickAtBottomWhenScrolling = stickAtBottom - global.GOVUK = GOVUK -})(window) + GOVUK.stickAtTopWhenScrolling = stickAtTop; + GOVUK.stickAtBottomWhenScrolling = stickAtBottom; + global.GOVUK = GOVUK; +})(window); From 55fa85d79ba8d8dceed84b4b955338380674b9c1 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Mon, 12 Nov 2018 09:54:25 +0000 Subject: [PATCH 09/11] Fix copypaste error --- .../stylesheets/components/stick-at-top-when-scrolling.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss index 516e44a13..492455fcc 100644 --- a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss +++ b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss @@ -38,7 +38,7 @@ } -.js-stick-at-top-when-scrolling { +.js-stick-at-bottom-when-scrolling { transition: bottom 0.1s ease-out, box-shadow 1s ease-in-out; From 8411598390a14c672d26875f1cc51c72a78d09b1 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Tue, 13 Nov 2018 14:08:06 +0000 Subject: [PATCH 10/11] Remove transition if element is stuck onload Fade-in and out for sticky elements should only be when they move from being in-page to stuck from a user interaction. --- .../stick-to-window-when-scrolling.js | 124 ++++++++++++------ .../stick-at-top-when-scrolling.scss | 25 +++- 2 files changed, 104 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/stick-to-window-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js index 67c519820..b3ad3774d 100644 --- a/app/assets/javascripts/stick-to-window-when-scrolling.js +++ b/app/assets/javascripts/stick-to-window-when-scrolling.js @@ -4,6 +4,39 @@ var $ = global.jQuery; var GOVUK = global.GOVUK || {}; + var StickyElement = function ($el, sticky) { + this._sticky = sticky; + this.$fixedEl = $el; + this._initialFixedClass = 'content-fixed-onload'; + this._fixedClass = 'content-fixed'; + this._appliedClass = null; + this._stopped = false; + this.scrolledFrom = this._sticky.getScrolledFrom($el); + }; + StickyElement.prototype.stickyClass = function () { + return (this._sticky._initialPositionsSet) ? this._fixedClass : this._initialFixedClass; + }; + StickyElement.prototype.appliedClass = function () { + return this._appliedClass; + }; + StickyElement.prototype.isStuck = function () { + return this._appliedClass !== null; + }; + StickyElement.prototype.stick = function () { + this._appliedClass = this.stickyClass(); + this._hasBeenCalled = true; + }; + StickyElement.prototype.release = function () { + this._appliedClass = null; + this._hasBeenCalled = true; + }; + StickyElement.prototype.stop = function () { + this._stopped = true; + }; + StickyElement.prototype.unstop = function () { + this._stopped = false; + }; + // Stick elements to top of screen when you scroll past, documentation is in the README.md var Sticky = function (selector) { this._hasScrolled = false; @@ -11,6 +44,7 @@ this._hasResized = false; this._resizeTimeout = false; this._elsLoaded = false; + this._initialPositionsSet = false; this._els = []; this.CSS_SELECTOR = selector; @@ -26,6 +60,30 @@ scrollTop: $(global).scrollTop() }; }; + Sticky.prototype.setElementPositions = function () { + var self = this; + + $.each(self._els, function (i, el) { + var $el = el.$fixedEl; + + var windowDimensions = self.getWindowDimensions(); + + if (self.scrolledFromInsideWindow(el.scrolledFrom)) { + self.release(el); + } else { + if (self.scrolledToOutsideWindow(el, windowDimensions.height)) { + self.stop(el); + } else if (self.viewportIsWideEnough(windowDimensions.width)) { + if (el.stopped) { + self.unstop(el); + } + self.stick(el); + } + } + }); + + if (self._initialPositionsSet === false) { self._initialPositionsSet = true; } + }; Sticky.prototype.setFixedTop = function (el) { var $siblingEl = $('
'); $siblingEl.insertBefore(el.$fixedEl); @@ -66,17 +124,16 @@ if ($els.length > 0) { $els.each(function (i, el) { var $el = $(el); - var elObj = { - $fixedEl: $el, - scrolledFrom: self.getScrolledFrom($el), - stopped: false - }; + var elObj = new StickyElement($el, self); self.setFixedTop(elObj); self.setElHeight(elObj); self._els.push(elObj); }); + // set element positions based on page scroll position on load + self.setElementPositions(); + if (self._scrollTimeout === false) { $(global).scroll(function (e) { self.onScroll(); }); self._scrollTimeout = global.setInterval(function (e) { self.checkScroll(); }, 50); @@ -86,10 +143,6 @@ $(global).resize(function (e) { self.onResize(); }); self._resizeTimeout = global.setInterval(function (e) { self.checkResize(); }, 50); } - - // fake scrolling to allow us to check the position of the elements - self._hasScrolled = true; - self.checkScroll(); } }; Sticky.prototype.onScroll = function () { @@ -106,25 +159,7 @@ if (self._hasScrolled === true) { self._hasScrolled = false; - - $.each(self._els, function (i, el) { - var $el = el.$fixedEl; - - var windowDimensions = self.getWindowDimensions(); - - if (self.scrolledFromInsideWindow(el.scrolledFrom)) { - self.release($el); - } else { - if (self.scrolledToOutsideWindow(el, windowDimensions.height)) { - self.stop(el); - } else if (self.viewportIsWideEnough(windowDimensions.width)) { - if (el.stopped) { - self.unstop(el); - } - self.stick($el); - } - } - }); + self.setElementPositions(true); } }; Sticky.prototype.checkResize = function () { @@ -154,19 +189,24 @@ }); } }; - Sticky.prototype.stick = function ($el) { - if (!$el.hasClass('content-fixed')) { + Sticky.prototype.stick = function (el) { + if (!el.isStuck()) { + var $el = el.$fixedEl; var height = Math.max($el.height(), 1); var width = $el.width(); this.addShimForEl($el, width, height); - $el.css('width', width + 'px').addClass('content-fixed'); + $el.css('width', width + 'px').addClass(el.stickyClass()); + el.stick(); } }; - Sticky.prototype.release = function ($el) { - if ($el.hasClass('content-fixed')) { - $el.removeClass('content-fixed').css('width', ''); + Sticky.prototype.release = function (el) { + if (el.isStuck()) { + var $el = el.$fixedEl; + + $el.removeClass(el.appliedClass()).css('width', ''); $el.siblings('.shim').remove(); + el.release(); } }; @@ -195,15 +235,15 @@ $el.before('
 
'); }; stickAtTop.stop = function (el) { - if (!el.stopped) { + if (!el.stopped()) { el.$fixedEl.css({ 'position': 'absolute', 'top': el.scrolledTo }); - el.stopped = true; + el.stop(); } }; stickAtTop.unstop = function (el) { - if (el.stopped) { + if (el.stopped()) { el.$fixedEl.css({ 'position': '', 'top': '' }); - el.stopped = false; + el.unstop(); } }; @@ -232,23 +272,23 @@ $el.after('
 
'); }; stickAtBottom.stop = function (el) { - if (!el.stopped) { + if (!el.stopped()) { el.$fixedEl.css({ 'position': 'absolute', 'top': (el.scrolledTo - el.height), 'bottom': 'auto' }); - el.stopped = true; + el.stop(); } }; stickAtBottom.unstop = function (el) { - if (el.stopped) { + if (el.stopped()) { el.$fixedEl.css({ 'position': '', 'top': '', 'bottom': '' }); - el.stopped = false; + el.unstop(); } }; diff --git a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss index 492455fcc..71662c80c 100644 --- a/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss +++ b/app/assets/stylesheets/components/stick-at-top-when-scrolling.scss @@ -44,7 +44,8 @@ } -.content-fixed { +.content-fixed, +.content-fixed-onload { position: fixed; background: $white; @@ -58,26 +59,44 @@ } -.js-stick-at-top-when-scrolling.content-fixed { +.js-stick-at-top-when-scrolling.content-fixed, +.js-stick-at-top-when-scrolling.content-fixed-onload { top: 0; margin-top: 0; border-bottom: 1px solid $border-colour; box-shadow: 0 2px 0 0 rgba($border-colour, 0.2); + +} + +.js-stick-at-top-when-scrolling.content-fixed { + transition: background 0.6s ease-in-out, margin-top 0.4s ease-out; } -.js-stick-at-bottom-when-scrolling.content-fixed { +.js-stick-at-bottom-when-scrolling.content-fixed, +.js-stick-at-bottom-when-scrolling.content-fixed-onload { top: auto; // cancel `top: 0;` inherited from govuk-template bottom: 0; border-top: 1px solid $border-colour; box-shadow: 0 -2px 0 0 rgba($border-colour, 0.2); + +} + +.js-stick-at-bottom-when-scrolling.content-fixed { + transition: background 0.6s ease-in-out; } +.js-stick-at-bottom-when-scrolling-loaded.content-fixed-onload { + + transition: none; + +} + .shim { display: block; margin-bottom: 5px; From eeb096aa6253e04c2e4ba190cf153dbcade72d69 Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Wed, 14 Nov 2018 16:42:52 +0000 Subject: [PATCH 11/11] Add missed .stopped method to Sticky Element --- app/assets/javascripts/stick-to-window-when-scrolling.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/stick-to-window-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js index b3ad3774d..4f5df6025 100644 --- a/app/assets/javascripts/stick-to-window-when-scrolling.js +++ b/app/assets/javascripts/stick-to-window-when-scrolling.js @@ -36,6 +36,9 @@ StickyElement.prototype.unstop = function () { this._stopped = false; }; + StickyElement.prototype.stopped = function () { + return this._stopped; + }; // Stick elements to top of screen when you scroll past, documentation is in the README.md var Sticky = function (selector) {