How do I get the offset().top value of an element without using jQuery?

offset top not working
jquery get element position relative to window
offset bottom jquery
jquery offset vs position
javascript get element position from top of page
javascript get element position relative to parent
get offset top angular 2
javascript get top of an element

I'm programming a single-page application using the Angular framework. I'm new to it. I've read this guide to help me understand the fundamental differences between jQuery and Angular and I'd like to follow this guidance as much as possible and NOT use jQuery.

Except that jQuery helps get around some of the browser incompatibilities and provides a useful library of functions, like being able to know the top position of an element from the top of the window, as in $('element').offset().top. No plain Javascript seems to be able to come close without rewriting this function, at which point wouldn't it be a better idea to use a jQuery or jQuery like library?

Specifically, what I'm trying to do is set up a directive that fixes an element in place once the top of it is scrolled to a certain position in the window. Here's what it looks like:

directives.scrollfix = function () {
    return {
        restrict: 'C',
        link: function (scope, element, $window) {

            var $page = angular.element(window)
            var $el   = element[0]
            var elScrollTopOriginal = $($el).offset().top - 40

            $page.bind('scroll', function () {

                var windowScrollTop = $page[0].pageYOffset
                var elScrollTop     = $($el).offset().top

                if ( windowScrollTop > elScrollTop - 40) {
                    elScrollTopOriginal = elScrollTop - 40
                    element.css('position', 'fixed').css('top', '40px').css('margin-left', '3px');
                }
                else if ( windowScrollTop < elScrollTopOriginal) {
                    element.css('position', 'relative').css('top', '0').css('margin-left', '0');
                }
            })

        }
    }
}

If there's a much better way to achieve this in Angular that I'm still just not getting, I'd appreciate the advice.

use getBoundingClientRect if $el is the actual DOM object:

var top = $el.getBoundingClientRect().top;

JSFiddle

Fiddle will show that this will get the same value that jquery's offset top will give you

Edit: as mentioned in comments this does not account for scrolled content, below is the code that jQuery uses

https://github.com/jquery/jquery/blob/master/src/offset.js (5/13/2015)

offset: function( options ) {
    //...

    var docElem, win, rect, doc,
        elem = this[ 0 ];

    if ( !elem ) {
        return;
    }

    rect = elem.getBoundingClientRect();

    // Make sure element is not hidden (display: none) or disconnected
    if ( rect.width || rect.height || elem.getClientRects().length ) {
        doc = elem.ownerDocument;
        win = getWindow( doc );
        docElem = doc.documentElement;

        return {
            top: rect.top + win.pageYOffset - docElem.clientTop,
            left: rect.left + win.pageXOffset - docElem.clientLeft
        };
    }
}

.offset(), offset() returns an object containing the properties top and left . Note: jQuery does not support getting the offset coordinates of hidden elements or accounting for  The offset() method set or returns the offset coordinates for the selected elements, relative to the document. When used to return the offset: This method returns the offset coordinates of the FIRST matched element. It returns an object with 2 properties; the top and left positions in pixels.

Here is a function that will do it without jQuery:

function getElementOffset(element)
{
    var de = document.documentElement;
    var box = element.getBoundingClientRect();
    var top = box.top + window.pageYOffset - de.clientTop;
    var left = box.left + window.pageXOffset - de.clientLeft;
    return { top: top, left: left };
}

.position(), Contrast this with .offset() , which retrieves the current position relative to the document. Returns an object containing the properties top and left . Note: jQuery does not support getting the position coordinates of hidden elements or  The .offset() method allows us to retrieve the current position of an element (specifically its border box, which excludes margins) relative to the document. Contrast this with .position() , which retrieves the current position relative to the offset parent .

Seems you can just use the prop method on the angular element:

var top = $el.prop('offsetTop');

Works for me. Does anyone know any downside to this?

You Might Not Need jQuery, Examples of how to do common event, element, ajax and utility operations with plain javascript. At the very least, make sure you know what jQuery is doing for you, and what it's not. Some developers believe that jQuery. var offset = el.​offset(); { top: offset.top - document.body. IE9+. array.map(function(value, index​){ });  You can also modify the code to get the element distance from the left side of the window by changing offset().top to offset().left. Another useful technique is to determine the current distance from top for the element while the visitor is scrolling up/down the page. To do this you would have to catch the current page offset from top first.

the accepted solution by Patrick Evans doesn't take scrolling into account. i've slightly changed his jsfiddle to demonstrate this:

css: add some random height to make sure we got some space to scroll

body{height:3000px;} 

js: set some scroll position

jQuery(window).scrollTop(100);

as a result the two reported values differ now: http://jsfiddle.net/sNLMe/66/

UPDATE Feb. 14 2015

there is a pull request for jqLite waiting, including its own offset method (taking care of current scroll position). have a look at the source in case you want to implement it yourself: https://github.com/angular/angular.js/pull/3799/files

jQuery offset() Method, jQuery offset() Method Return the offset coordinates of a <p> element: Name/​Value pairs, like {top:100,left:100}; An object with top and left properties  Is it possible to get the top position of an element using javascript/jquery ? The element is a table, if that matters.

You can try element[0].scrollTop, in my opinion this solution is faster.

Here you have bigger example - http://cvmlrobotics.blogspot.de/2013/03/angularjs-get-element-offset-position.html

Element offsetTop Property, Definition and Usage. The offsetTop property returns the top position (in pixels) relative to the top of the offsetParent element. The returned value includes:. The offsetTop property returns the top position (in pixels) relative to the top of the offsetParent element. The returned value includes: the top position, and margin of the element; the top padding, scrollbar and border of the offsetParent element; Note: The offsetParent element is the nearest ancestor that has a position other than static. Tip: To return the left position of an element, use the offsetLeft property.

Get element offset in JavaScript · Muffin Man, When we left jQuery behind and embraced modern JavaScript frameworks, we thought we would never touch DOM directly But one of the other common tasks is getting element's offset, top and left. One important thing to note - it is not taking CSS transforms into calculations. Sometimes it is returning wrong values​. Just for reference, if you are using: $(el).offset().top To get the position, it can be affected by the position of the parent element. Thus you may want to be consistent and use the following to set it: $(el).offset({top: pos}); As opposed to the CSS methods above.

HTMLElement.offsetTop, offsetTop read-only property returns the distance of the current of pixels from the top of the closest relatively positioned parent element. (Having display:​none does not affect this browser.) click() · forceSpellCheck(). That probably makes no sense. What I am trying to say is that these properties measure the distance from the current element's top-left corner to its nearest offset parent. For example, here is the offsetTop and offsetLeft value for our image element: The value is 24 because the parent (aka the container) pushes the image away by 24 pixels.

What is the difference between jQuery.position() and jQuery.offset , The position() method gets the top and left position of an element relative to make sure to use pixel values for margins, borders and padding. The index parameter is used to return the position of set element and offset return the coordinate of selected element. Return Value: This method returns the co-ordinate of matched elements. Below examples illustrate the offset() method in jQuery:

Comments
  • the accepted solution doesn't take the current scroll position into account, see my answer below
  • Looks like the cross browser compatibility on this is great too. Thanks.
  • note that this solution doesn't account for the current scrolling position, see my answer below
  • No, it's not the same. This is the same: $el.getBoundingClientRect().top + document.body.scrollTop
  • Well jQuery uses more than that... You should include getWindow, isWindow etc...
  • @TJ, why? Users should be able to infer what getWindow does, can look up the code of the utility function themselves since I have linked the github repo, and I believe adding in the code just to explain a utility function would just clutter the answer.
  • Reinventing the wheel (not universal one, by the way) is definitely better then using "cancer", yes, sure...
  • @Regent Not everyone wants to include a giant library to do something that can otherwise be done in 5 lines of code.
  • For example, jquery-2.1.3.min.js (83KB) is not giant file. What about projects (not AngularJS ones) where jQuery is used in many places? Do you suggest to write your one functions to make code (which works with DOM) shorter? Not well tested, with bugs, without good cross-browsing? I do understand that jQuery shouldn't be used in all projects, but by insulting jQuery you state that it should't be used anywhere (and this is wrong statement, by the way), don't you?
  • I'm not sure where I said that it "shouldn't be used anywhere". If jQuery is already a requirement, then sure, make use of it. But as time goes on and browser incompatibilities are resolved, it's value begins to diminish. And while 83kb might not be a lot on your first-world fiberoptic connection, much of the developing world isn't so fortunate. It's also frustrating as a JS library designer that so many SO posts continually punt to jQuery at times when you really need to understand how things work. See youmightnotneedjquery.com