Giter Site home page Giter Site logo

ryanve / verge Goto Github PK

View Code? Open in Web Editor NEW
694.0 22.0 53.0 163 KB

get viewport dimensions...detect elements in the viewport...trust in <!DOCTYPE html>

Home Page: https://ryanve.dev/verge

License: MIT License

JavaScript 61.98% HTML 38.02%
javascript viewport viewport-dimensions responsive-design

verge's Introduction

verge

verge is a compact set of cross-browser viewport utilities written in native JavaScript. It includes the ability to detect if an element is in the current viewport. It works as a standalone module, an ender module, or as a jQuery plugin. (npm: verge)

API

Accuracy

  • Requires <!DOCTYPE html>
  • verge's viewport methods represent the CSS viewport: the @media (width) and @media (height) breakpoints.
  • At certain zooms the viewport dimensions given by verge may be 1px off the expected @media value due to native rounding. For greater precision (at a slight speed tradeoff) consider actual.

.viewportW()

verge.viewportW() // -> viewport width in pixels

.viewportH()

verge.viewportH() // -> viewport height in pixels

.viewport()

Get both CSS viewport dimensions as an object with width and height properties.

verge.viewportW() === verge.viewport().width  // always true
verge.viewportH() === verge.viewport().height // always true

The .viewportW() syntax is slightly faster.

.inViewport()

Test if any part of an element (or the first element in a matched set) is in the current viewport. Returns boolean.

verge.inViewport(elem) // true if elem is in the current viewport
verge.inViewport(elem, 100) // true if elem is in the current viewport or within 100px of it
verge.inViewport(elem, -100) // true if elem is in the current viewport and not within 99px of the edge

Performance tip for sites that only scroll along 1 axis

verge.inViewport(elem) === verge.inX(elem) && verge.inY(elem) // always true
Substitute inViewport with: inY on vertical sites, inX on horizontal ones.
  • On pages without horizontal scroll, inX is always true.
  • On pages without vertical scroll, inY is always true.
  • If the viewport width is >= the document width, then inX is always true.

.inX()

Test if any part of an element (or the first element in a matched set) is in the same x-axis section as the viewport. Returns boolean.

verge.inX(elem) // true if elem is in same x-axis as the viewport (exact)
verge.inX(elem, 100) // true if elem is in same x-axis as the viewport or within 100px of it
verge.inX(elem, -100) // true if elem in is the viewport and not within 99px of the edge

.inY()

Test if any part of an element (or the first element in a matched set) is in the same y-axis section as the viewport. Returns boolean.

verge.inY(elem) // true if elem is in same y-axis as the viewport (exact)
verge.inY(elem, 100) // true if elem is in same y-axis as the viewport or within 100px of it
verge.inY(elem, -100) // true if elem in is the viewport and not within 99px of the edge

.scrollX()

Get the horizontal scroll position in pixels. (Like window.scrollX, but cross-browser.)

verge.scrollX() // -> horizontal pixels scrolled

.scrollY()

Get the vertical scroll position in pixels. (Like window.scrollY, but cross-browser.)

verge.scrollY() // -> vertical pixels scrolled

.mq()

.mq(mediaQueryString)

Test if a media query is active.

verge.mq('(min-color:2)') // -> boolean
verge.mq('tv') // -> boolean

.rectangle()

.rectangle(element, cushion?)

Get an a object containing the properties top, bottom, left, right, width, and height with respect to the top-left corner of the current viewport, and with an optional cushion amount. Its return is like that of the native getBoundingClientRect.

The optional cushion parameter is an amount of pixels to act as a cushion around the element. If none is provided then it defaults to 0 and the rectangle will match the native rectangle. If a cushion is specified, the properties are adjusted according to the cushion amount. If the cushion is positive the rectangle will represent an area that is larger that the actual element. If the cushion is negative then the rectangle will represent an area that is smaller that the actual element.

verge.rectangle(element) // rectangle object
verge.rectangle(element, 100) // rectangle object adjusted by 100 pixels

.aspect()

.aspect(object?)

Get the aspect ratio of the viewport or of an object with width/height properties.

verge.aspect() // -> viewport aspect ratio
verge.aspect(element) // -> element aspect ratio
verge.aspect(screen) // -> device aspect ratio
1 < verge.aspect() // => landscape orientation

Integrate

jQuery.extend(verge)
ender build verge

Contribute

Contribute by making edits in ./src or reporting issues.

npm install
npm test

verge's People

Contributors

ryanve avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

verge's Issues

v2 considerations

How we can make v2 even better than v1? Feedback wanted on this and other ideas you have =)

  • .min file: Is there still value in providing a minified file in the repo or are most people using build tools?
  • .mq: Are you using this method? It feels a bit out of the scope of this module. We could remove it and recommend actual.is as an equivalent alternative
  • element: Do we want to continue to support collection elements or only native elements?
  • cushion: Do we want to continuing supporting cushion as a 2nd argument or is there a more expressive way we can do this?
  • structure: I'd like to replace grunt with npm scripts and use a flat directory structure like I've done in some of my other projects: eol, fm, cxn
  • linting: I'd like to replace jshint with eslint
  • pages: Coinciding with the structure change I plan to change the default branch to gh-pages so that a playground and test area can be made available on ryanve.github.io/verge

Initial state affects viewport method detection

I have some functionality in a page where I want to set the width of a list of menu items manually, however, I also want to detect when a 767px break point has been reached, and remove the manually set list.

Currently, I have this

function update() {
        if (window.innerWidth > 767) {
            $("nav.main ul li").width($("nav.main ul").width() / 5 - 11);
        } else {
            $("nav.main ul li").css('width', '');
        }
    };
    update();
    $(window).on("resize", update);

I did try replacing window.innerWidth with $.viewportW(), but noticed that the reported value of $.viewportW() was not matching up with the width displayed in the top corner of Chrome (30.0.1599.101 m). That is, $.viewportW() would report 767 when Chrome is reporting 784.

With regards to the 767px breakpoint, I have a media query that uses max-width, as this is what the Unsemantic CSS Framework is using. i.e. @media screen and (max-width: 767px).

Using the Chrome debug tools, when Chrome reports 767px, and the media query kicks in for max-width: 767px, I can see the following:
$.viewportW() : 750
window.innerWidth : 767
window.outerWidth : 783
$(window).outerWidth() : 750, as well as outWidth(true) and innerWidth()

I can't quite tell if the 17px difference between viewportW() and window.innerWidth has anything to do with scrollbars, or if there is simply an issue because I'm using max-width in my media query.

Add bp() or breakpoint() method

I wrote a breakpoint() function that gets actual @media breakpoints. It's useful for testing development code and maybe elsewhere. It can get dimensions in any supported unit and works for any range feature.

breakpoint('width', 'px')
breakpoint('width', 'em')

Would this be useful to have in verge?

verge.bp() or verge.breakpoint()

Compile as ES6 module

Would you be able to compile an ES modules version and specify it in the module field of package.json? (Or specify it in the main field along with `"type": "module" and drop the old CJS version). The library cannot be used with Vite otherwise.

Using resizeTests['viewport-w'] value in HTML

I'm a JavaScript newbie but uses PHP with HTML. I've been studying the files in "test" directory.

In the index.html, <code id="viewport-w"></code> displays the most updated viewport width. So for, I know I need to set the id to get the value.

Is there a way to assign that value to a variable so I can set another value to reference different image file name in <img src=...>? Like for viewport width < 320, in HTML I will have the file name as image320.jpg; width < 480, image480.jpg.

If you think this is not something easy to show a newbie, I understand. And I appreciate you taking time with this in any case.

inViewport falsely returns true

I attached verge.inViewport to a scroll event to test this.

When I start scrolling I keep getting true returned even if the element is not in the viewport. Only after I scroll past the desired element, false is returned.

If I scroll back up past that element, it's still true.

Add div with dynamic VergeJS viewport values to HTML

Trying to display a div with the Verge values during development.
Please see https://jsfiddle.net/ccL30a26/1/.

function getVergeValues() {

viewportWidth  = verge.viewportW() // Get the viewport width in pixels.
viewportHeight = verge.viewportH() // Get the viewport height in pixels.

var $width  = $( "<div class='w'></div>" );
var $height = $( "<div class='h'></div>" );

$('.w').text(viewportWidth  + 'px wide');
$('.h').text(viewportHeight + 'px high');

$( "body" ).append( $width, $height);

}

$(window).on('resize', getVergeValues);
$(document).ready(getVergeValues);

However now on domready there is no value shown and on window resize the values get added up filling the viewport.

How can I get the initial value to show on domready and only the current value to show on window resize please?

I assume this is not really an issue but am wondering why Verge does not display the inital value on domready. Do you have a clue?

Additionally it would be great if you could help with letting me know how I can avoid filling the viewport with new divs as I resize. Thank you.

inViewPort but above 100px from the bottom of the ViewPort

Is there a way to check if an element is in the viewport but has to be above the bottom 100px from the bottom edge of the viewPort? sorta like modifying the viewport height to be -100px less and checking inViewPort with the new height.

Separate cushion from rectangle

Internally I'm planning to separate rectangle cushioning from measuring. It could also be useful to have a public method (called .pad() or .cushion() or otherwise) that could adjust rectangles. Should this be exposed?

function pad(coords, cushion) {
    var o = {};
    cushion = typeof cushion == 'number' && cushion || 0;
    o.width = (o.right = coords.right + cushion) - (o.left = coords.left - cushion);
    o.height = (o.bottom = coords.bottom + cushion) - (o.top = coords.top - cushion);
    return o;
}

For use by .rectangle()

function rectangle(el, cushion) {
    el = el && !el.nodeType ? el[0] : el;
    if (!el || 1 !== el.nodeType) return false;
    return pad(el.getBoundingClientRect(), cushion);
}

Let viewportW/viewportH methods compare min

The 1.7- viewport methods are simple getters:

$.viewportW() // get viewport width
$.viewportH() // get viewport height

It could be useful to let these support a min parameter that compares and returns boolean:

$.viewportW(min) // true if viewport is at least `min` wide
_.find(list, $.viewportW) // use case

Are there pitfalls in adding the (min) syntax? It seems rather expressive. Going further to add (min, max) would be problematic for the _.find use case above because of the indices.

Element's offsetTop property?

Was wondering if there's a way for getting an element's offsetTop property or its equivalent?

Enjoying this script, thanks for the hard work thus far. ๐Ÿ‘

Device size/resolution module

Do device size/resolution methods belong in verge or should I make a separate module for them?

Potential device resolution methods

$.dpi()     // get resolution in dpi
$.dpi(min)  // check if device is at least `min`
$.dpcm()    // get resolution in dpcm
$.dpcm(min) // check if device is at least `min`
$.dpr()     // get device-pixel-ratio
$.dpr(min)  // check if device is at least `min`

dpi, dpcm, and device-pixel-ratio are all mathematically related. Determine one and then use unit conversion. (resolution) is a standard media query. device-pixel-ratio is vendor specific but can be approximated (interpolated) otherwise via media queries.

dpi = 96 * dpr;
dpcm = dpi / 2.54;

Potential device size methods

Size detection is easy via screen.width and screen.height. Basically they're sugar.

$.deviceW()    // get device width
$.deviceW(min) // check if device is at least `min` wide
$.deviceH()    // get device height
$.deviceH(min) // check if device is at least `min` high

Watch functionality

Hi @ryanve,

At @esites we use verge.js in our projects quite often. That said, I caught myself writing small wrappers around verge.inViewport to handle scroll and resize events. So, I decided to wrap this functionality up in a 'plugin' of sorts.

It exposes the verge.watch method that accepts an object with the following properties:

  • target: the DOM element that needs to be watched
  • callback: callback that will be invoked when the target is in the viewport. When passing an array with two functions, the first will be executed when the target is in the viewport, the second when it's out.
  • interval; optional interval that determines how many times verge.inViewport will be called

Example calls:

verge.watch({
    target: document.getElementById('target'),
    callback: function (e) {
        // do something
        // `this` points to the target DOM element
        // the first passed argument is a reference to the corresponding event object (either scroll or resize)
    }
});

verge.watch({
    target: document.getElementById('target'),
    callback: [showElement, hideElement]
});

Some characteristics:

  • vanilla JS and no dependencies
  • lightweight; only 2kb (minified) when merged with verge.js
  • performant; embraces John Resig's best practice on working with scroll/resize events. So no complex calculations while scrolling/resizing, verge.inViewport is being called within a setInterval. Hence the possibility to pass along a an interval to overrule the default interval (150ms).
  • tests available and jshint compliant
  • tested in Firefox, Safari, Chrome, Opera and IE8+

For now the code is located in the forked repo. If you would like to see this functionality merged (say, as part of 2.0) I could create a PR :)

Cheers!

Deprecate viewport filters

In verge 1.0.0, there is the ability to filter elems via $(elems).inViewport(). In practice one typically wants to do one action for elements in the viewport, and maybe another for those that aren't. The filter methods are inefficient for this common use case because they create a new $ object each time. The block below demonstrates this waste:

// awkward
var $elems = $(elems);
$elems.inViewport().each(function() {
  // actions for elems in the viewport
});
$elems.inViewport(0, true).each(function () {
  // actions for elems NOT it the viewport
});

My plan is to remove the .fn filters, because the simpler top-level verge.inViewport methods allow for much more efficient code, like so:

// better
$(elems).each(function () {
    if (verge.inViewport(this)) {

    } else {

    }
});

One can still filter like so:

$(elems).filter(function () {
    return verge.inViewport(this);
});

Add typescript support

Hi, thx for your work.
It will be usefull to add a typescript support
Somebody has allready code it ?

Add "guard" parameters

Methods whose signature is (value [, number]) cannot be used directly as array iterators whose 2nd argument is the array index. It'd be useful add guard params that allow the following examples to work with standard array methods:

array.filter(verge.inViewport)
array.some(verge.inViewport)
array.map(verge.rectangle)

We can achieve this similar to how underscore uses guard params. For example:

function rectangle(el, pad, guard) {
  pad = !guard && +pad || 0; // number and not NaN

We had some partial undocumented support for this in some versions. We should add it to all applicable methods with this signature and document the usage.

missing browser support in readme

I am trying to debug some site with verge as a basis for animations, and I don't know it's my code or it's verge. no errors in IE at all, but classes are not added on inViewport event.

So, in short: what browsers are supported by Verge?

Improving testing for verge

I think we could improve on the testing here.

Does anyone have interest in helping redoing the tests in a better way?

Such that we could run then via npm test potentially via headless chrome

Or other ideas?

verge online library not on https

Our website is an https, we cannot include your library because it is served from an http server. Would you mind if we can host your library on https ? Our website is ToolsQA.com

Resource I am talking about is: http:////airve.github.io//js//verge//verge.min.js

Put it on bower

Would it be possible to put verge on bower? Since it's dependent on the DOM, it makes sense to have it on bower, too.

Viewport width/height technique needs realtime detection

<meta name=viewport content="width=device-width, initial-scale=1">

I've done some more testing related to #7 and realized that various zoom and initial-scale combinations cause verge.viewport() in 1.9.0 to use the wrong technique because the detection is cached. To correct this it seems we need to detect the correct technique each time.

Verge thinks an element exactly off of the screen is in the viewport

Hey Ryan,

Thanks for building this awesome plugin! My current viewport plugin fails on iOS so this is fantastic. The main difference I see is that Verge thinks an element that is exactly off of the screen is in the viewport.

Imagine a drawer with the following CSS:

.drawer {
    position: fixed;
    right: -300px;
    width: 300px;
    top: 0;
    bottom: 0;
}

A thought experiment: a 1px wide fixed position element with right: 0 sits exactly on the right edge. Setting the right parameter to -1px puts it exactly off the screen.

Any thoughts?

Thank you!

Drop undocumented `[0]` grabs

verge methods that accept (element [, cushion]) expect element to be native DOM element. Under the hood the 1.x code actually allows element to be an array-like object, in which case the first item is used. This was never a recommended syntax. I had kept it in there for back support just in case. Does anyone use this syntax? If not, I think we could safely remove it in a later minor or major version.

Multiple elements with same class?

Any tips for having Verge work with multiple elements with the same class? From my tests, using something like inViewport() will only detect the first element of that selector on the page.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.