Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

$anchorScroll Offset #2070

Closed
leeola opened this issue Feb 25, 2013 · 53 comments
Closed

$anchorScroll Offset #2070

leeola opened this issue Feb 25, 2013 · 53 comments

Comments

@leeola
Copy link

leeola commented Feb 25, 2013

Just a quick feature request.

If your app has a fixed position header, $anchorScroll will "incorrectly" position the scroll for the users view. Nothing is broke here, but allowing for an $anchorScrollProvider offset number would be nice.

Basically, right after elm.scrollIntoView() it would execute roughly.. if (offset > 0) $window.scroll($window.scrollX, $window.scrollY - offset);. This would allow $anchorScrollProvider & $anchorScroll to play nicely with fixed position headers.

@leeola
Copy link
Author

leeola commented Feb 28, 2013

Funny enough, i noticed that even the official docs suffer from this same problem.

http://docs.angularjs.org/api/AUTO.$provide#factory

Notice how when you visit that url, you cannot see the title for that documentation? It's because it is hidden behind the page header, haha.

@davidchang
Copy link
Contributor

Volunteer

@davidchang
Copy link
Contributor

Actually, the underlying scroll functionality comes from https://developer.mozilla.org/en-US/docs/DOM/element.scrollIntoView which doesn't allow for an offset. Doing the $window.scroll after calling elm.scrollIntoView() may be obviously hacky.

@andymcfee
Copy link

+1 for a solution to this problem

@kapilkale
Copy link

+1 here as well. Probably not uncommon to want a 10-20 pixel offset from the element being scrolled to.

@leeola
Copy link
Author

leeola commented Jul 4, 2013

Actually, the underlying scroll functionality comes from https://developer.mozilla.org/en-US/docs/DOM/element.scrollIntoView which doesn't allow for an offset. Doing the $window.scroll after calling elm.scrollIntoView() may be obviously hacky.

Yea, that's why i haven't asked for my code to be pulled in. It's hacky, but i'm not aware of any other way. Anchors on my site would be broken without it heh.

@rickhuizinga
Copy link

+1 here too.

@yellowrangler
Copy link

I wrote the following in my controller. Really awful hack put could not figure any other way. Am new to Angular; but thought i would share.

$scope.goToInternalHash = function(id, offset) {
$location.hash(id);
$anchorScroll();
setTimeout(function(){
window.scrollTo(window.pageXOffset, window.pageYOffset - offset);
},300);

@trask
Copy link

trask commented Sep 1, 2013

Adding invisible anchor tags with negative relative offset seems like a nice workaround for this issue, e.g. http://stackoverflow.com/a/13184714/295416

@ghost
Copy link

ghost commented Sep 20, 2013

Might as well be using angular-ui and bootstrap Scrollspy or wrapping some other plugin in a service.

@pavelnikolov
Copy link

I have the same problem.

@rjelte
Copy link

rjelte commented Nov 5, 2013

+1 for a solution to this

There are any number of little hacks that can be implemented, but it would be nice if there was something built in.

@mikeobrien
Copy link

+1

3 similar comments
@mrzepinski
Copy link

+1

@paul-lemon
Copy link

+1

@ada-lovecraft
Copy link

+1

@ghost ghost assigned btford Dec 19, 2013
@maltenuhn
Copy link

+1

@deepak-nulu
Copy link

+1

7 similar comments
@voxmatt
Copy link

voxmatt commented Jan 19, 2014

+1

@akarl
Copy link

akarl commented Jan 23, 2014

+1

@npatten
Copy link

npatten commented Jan 24, 2014

+1

@iarcher367
Copy link

+1

@tschiela
Copy link

+1

@carlosrymer
Copy link

+1

@awdng
Copy link

awdng commented Feb 14, 2014

+1

@hueitan
Copy link

hueitan commented Feb 17, 2014

+1 ( $anchorScroll is cool )

@lynndylanhurley
Copy link

+1

@linfongi
Copy link

+1

1 similar comment
@fabianmarz
Copy link

👍

@IgorMinar
Copy link
Contributor

I like @a8m's solution that uses css only:

<span class="anchor" id="head1">head1</span>
.anchor {
   padding-top: 40px;
}

demo: http://jsbin.com/foyelo/9/edit

this solution is clean (keeps the layout information in CSS, doesn't require duplicate scrolling, timeout, etc) and flexible. Adding the extra offset info to $anchorScroll will result only in hacks and duplication of layout info between css and js.

unless there is a good reason why the css solution doesn't work, we should close this issue

@gkalpak
Copy link
Member

gkalpak commented Oct 1, 2014

The drawback of this approach is that it is kind of cubersome:

  • You have to specify a different padding for each screen size (based on the media queries used).
  • You have to account for the widths of the various elements inside the header (e.g. as specified by their col-x-y classes), in order to know when an element will wrap to the next line.
  • You have to manually keep track of any CSS styles affecting the height of an element (e.g. an explicit [min-/max-]height, a line-height etc).
  • If anything changes (e.g. a new element is added, a col-x-y is modified etc), you have to (remember to) recalculate all values again.

It is not that it's unworkable, but it sounds like a tedious (and error-prone) task, and a repetitive one in nature as well (supposing your header content and/or CSS won't stay unchanged forever).

(Of course, this is not specific to the docs app - it's quite often in several projects.)


The fixed offset in $anchorScroll won't address all of the issues either, so how about this:

$anchorScroll will accept either a fixed offset or...[drums please]...an offset-getter function.
It will execute the function each time to get the offset. This will save us a lot of time I think. We'll never have to worry about updating our CSS and account for any tiny change in the header or in CSS styles that might break our anchor scrolling.

(In case it's not clear yet, in the example at hand, we would pass a function that returns the current heght of the fixed header as offset.)

What do you think (@IgorMinar, @petebacondarwin) ?

@petebacondarwin
Copy link
Contributor

How about this?

Create a directive that you attach to any headings that you don't want to be obscured.

This directive will insert a new anchor element in front of the heading (as proposed by @IgorMinar), which has a dynamic padding style based either on an expression passed into the directive or based on a config value defined in a service:

Explicit Example

<h1 ng-offset="{{ headerHeight }}">Heading 1</h1>

In this case the offset is computed based on the value of $scope.headerHeight, which can be changed at run time.

Implicit Example

<h1 ng-offset>Heading 1</h1>

In this case the directive could look for a service, say, headingOffset, which can be defined by the application and modified as needed:

.value('headingOffset', { value: 40 });

@petebacondarwin
Copy link
Contributor

I will prototype this but my only concern is whether it would work on initial page render before the first digest has run...

@gkalpak
Copy link
Member

gkalpak commented Oct 1, 2014

@petebacondarwin: I have implemented a similar solution and use in my projects (where I usually have collapsible header menus and the issue is harder to address).
But, a simple solution for simpler cases would be nice.

For what you propose to work ngOffset should evaluate an expression (since the header height might change "at runtime"). The drawback with this approach is that the expression would have to be evaluated at every $digest, in contrast to the $anchorScroll solution, which would only get evaluated when $anchorScrolling (a much rarer task usually).

petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Oct 1, 2014
gkalpak added a commit to gkalpak/angular.js that referenced this issue Oct 1, 2014
Add support for a configurable scroll offset to $anchorScrollProvider.
The offset is expressed in pixels and can be specified either as a fixed
value or as a function that return the offset it pixels dynamically.
(This is a POC and a WIP: no docs, no tests)

Related to angular#9368

Closes angular#2070, angular#9360
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Oct 1, 2014
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 2, 2014
Add support for a configurable scroll offset to $anchorScrollProvider.
The offset is expressed in pixels and can be specified either as a fixed
value or as a function that return the offset it pixels dynamically.
(This is a POC and a WIP: no docs, no tests)

Related to angular#9368

Closes angular#2070, angular#9360
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Oct 7, 2014
Add support for a configurable scroll offset to $anchorScrollProvider.

Related to angular#9368
Closes angular#2070
Closes angular#9371
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
gkalpak added a commit to gkalpak/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable scroll offset to $anchorScrollProvider.
The offset is expressed in pixels and can be specified either as a fixed
value or as a function that return the offset it pixels dynamically.
(This is a POC and a WIP: no docs, no tests)

Related to angular#9368

Closes angular#2070, angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
gkalpak added a commit to gkalpak/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable scroll offset to $anchorScrollProvider.
The offset is expressed in pixels and can be specified either as a fixed
value or as a function that return the offset it pixels dynamically.
(This is a POC and a WIP: no docs, no tests)

Related to angular#9368

Closes angular#2070, angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 9, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
gkalpak added a commit to gkalpak/angular.js that referenced this issue Oct 10, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 10, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 10, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
gkalpak added a commit to gkalpak/angular.js that referenced this issue Oct 10, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Oct 10, 2014
Add support for a configurable vertical scroll offset to `$anchorScroll`.

The offset can be defined by a specific number of pixels, a callback function
that returns the number of pixels on demand or a jqLite/JQuery wrapped DOM
element whose height and position are used if it has fixed position.

The offset algorithm takes into account items that are near the bottom of
the page preventing over-zealous offset correction.

Closes angular#9368
Closes angular#2070
Closes angular#9360
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.