์นดํ…Œ๊ณ ๋ฆฌ ๋ณด๊ด€๋ฌผ: Javascript

Javascript

ํ˜„์žฌ ๋ทฐํฌํŠธ์—์„œ DOM ์š”์†Œ๊ฐ€ ๋ณด์ด๋Š”์ง€ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์— ํ‘œ์‹œ)

HTML ๋ฌธ์„œ์—์„œ DOM ์š”์†Œ๊ฐ€ ํ˜„์žฌ ํ‘œ์‹œ๋˜๋Š”์ง€ ( ๋ทฐํฌํŠธ ์— ํ‘œ์‹œ) ์•Œ ์ˆ˜์žˆ๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

(์งˆ๋ฌธ์€ Firefox์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)



๋‹ต๋ณ€

์—…๋ฐ์ดํŠธ : ์‹œ๊ฐ„์ด ํ๋ฅด๊ณ  ๋ธŒ๋ผ์šฐ์ €๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ์ˆ ์€ ๋” ์ด์ƒ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ๊ทธ๋ฆฌ๊ณ  ๋‹น์‹ ์€ ์‚ฌ์šฉํ•ด์•ผ ๋‹จ์˜ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด 7 ์ „์— ์ธํ„ฐ๋„ท ์ต์Šคํ”Œ๋กœ๋Ÿฌ์˜ ์ง€์› ๋ฒ„์ „์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ.

๋…์ฐฝ์  ์ธ ์†”๋ฃจ์…˜ (ํ˜„์žฌ ๊ตฌ์‹) :

ํ˜„์žฌ ๋ทฐํฌํŠธ์—์„œ ์š”์†Œ๊ฐ€ ์™„์ „ํžˆ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

function elementInViewport(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top >= window.pageYOffset &&
    left >= window.pageXOffset &&
    (top + height) <= (window.pageYOffset + window.innerHeight) &&
    (left + width) <= (window.pageXOffset + window.innerWidth)
  );
}

๋ทฐํฌํŠธ์— ์š”์†Œ์˜ ์ผ๋ถ€๊ฐ€ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํžˆ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function elementInViewport2(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top < (window.pageYOffset + window.innerHeight) &&
    left < (window.pageXOffset + window.innerWidth) &&
    (top + height) > window.pageYOffset &&
    (left + width) > window.pageXOffset
  );
}

๋‹ต๋ณ€

์ด์ œ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ € ๋Š” getBoundingClientRect ๋ฉ”์†Œ๋“œ๋ฅผ ์ง€์› ํ•˜๋ฉฐ, ์ด๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ž˜๋œ ๋Œ€๋‹ต์„ ์‚ฌ์šฉํ•˜์—ฌ์ž…๋‹ˆ๋‹ค ๋งค์šฐ ๋А๋ฆฌ๊ฒŒ , ์ •ํ™•ํ•˜์ง€ ๋ฐ ์—ฌ๋Ÿฌ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค .

์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์œผ๋กœ ์„ ํƒํ•œ ์†”๋ฃจ์…˜์€ ๊ฑฐ์˜ ์ •ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค .


์ด ์†”๋ฃจ์…˜์€ Internet Explorer 7 ์ด์ƒ, iOS 5 ์ด์ƒ, Safari, Android 2.0 (Eclair) ์ด์ƒ, BlackBerry, Opera Mobile ๋ฐ Internet Explorer Mobile 9 ์—์„œ ํ…Œ์ŠคํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค .


function isElementInViewport (el) {

    // Special bonus for those using jQuery
    if (typeof jQuery === "function" && el instanceof jQuery) {
        el = el[0];
    }

    var rect = el.getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
    );
}

์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•:

์œ„์—์„œ ์ฃผ์–ด์ง„ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋  ๋•Œ ์ •๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋ฒคํŠธ๋กœ์„œ ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ์„ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

<body>ํƒœ๊ทธ ํ•˜๋‹จ์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ํ•˜์‹ญ์‹œ์˜ค .

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (typeof callback == 'function') {
                callback();
            }
        }
    }
}

var handler = onVisibilityChange(el, function() {
    /* Your code go here */
});


// jQuery
$(window).on('DOMContentLoaded load resize scroll', handler);

/* // Non-jQuery
if (window.addEventListener) {
    addEventListener('DOMContentLoaded', handler, false);
    addEventListener('load', handler, false);
    addEventListener('scroll', handler, false);
    addEventListener('resize', handler, false);
} else if (window.attachEvent)  {
    attachEvent('onDOMContentLoaded', handler); // Internet Explorer 9+ :(
    attachEvent('onload', handler);
    attachEvent('onscroll', handler);
    attachEvent('onresize', handler);
}
*/

DOM ์ˆ˜์ •์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€์นจ ๋ฐ ์ผ๋ฐ˜์ ์ธ ํ•จ์ • :

์•„๋งˆ ๋‹น์‹ ์€ ํŽ˜์ด์ง€ ํ™•๋Œ€ / ๋ชจ๋ฐ”์ผ ์žฅ์น˜ ํ•€์น˜๋ฅผ ์ถ”์ ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? jQuery๋Š” ์คŒ / ํ•€์น˜ ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ฒซ ๋ฒˆ์งธ ๋˜๋Š” ๋‘ ๋ฒˆ์งธ ๋งํฌ๊ฐ€ ๋„์›€์ด๋ฉ๋‹ˆ๋‹ค.

DOM ์„ ์ˆ˜์ • ํ•˜๋ฉด ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ œ์–ดํ•˜๊ณ  handler()์ˆ˜๋™์œผ๋กœ ํ˜ธ์ถœ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„, ์šฐ๋ฆฌ๋Š” ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ € onrepaint์ด๋ฒคํŠธ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค . ๋ฐ˜๋ฉด์— ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜์žˆ๋Š” DOM ์ˆ˜์ •์— ๋Œ€ํ•ด์„œ๋งŒ ์ตœ์ ํ™”ํ•˜๊ณ  ์žฌํ™•์ธ์„ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ CSS๊ฐ€ ์ ์šฉ๋˜์—ˆ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†์œผ๋ฏ€๋กœ jQuery $ (document) .ready () ์—์„œ๋งŒ ์‚ฌ์šฉ ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค . ์ฝ”๋“œ๋Š” ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ์—์„œ CSS์™€ ๋กœ์ปฌ๋กœ ์ž‘๋™ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋‹จ ์›๊ฒฉ ์„œ๋ฒ„์— ๋„ฃ์œผ๋ฉด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

ํ›„์— DOMContentLoaded๋Š” ์Šคํƒ€์ผ์ด ์ ์šฉ ๋˜์ง€๋งŒ ์ด๋ฏธ์ง€๋Š” ์•„์ง๋กœ๋“œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ๋”ฐ๋ผ์„œ window.onload์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค .

์•„์ง ์คŒ / ํ•€์น˜ ์ด๋ฒคํŠธ๋ฅผ ์žก์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ์ˆ˜๋‹จ์€ ๋‹ค์Œ ์ฝ”๋“œ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

/* TODO: this looks like a very bad code */
setInterval(handler, 600);

์›น ํŽ˜์ด์ง€๊ฐ€์žˆ๋Š” ํƒญ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๊ณ  ๊ฐ€์‹œ์ ์ธ์ง€ ์‹ ๊ฒฝ ์“ฐ๋ฉด HTML5 API ์˜ ๋ฉ‹์ง„ ๊ธฐ๋Šฅ pageVisibiliy ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TODO :์ด ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

์ตœ์‹  ์ •๋ณด

์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ์ œ๊ณตํ•˜๋Š” Intersection Observer API ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค .

  • ์Šคํฌ๋กค ์ด๋ฒคํŠธ๋ฅผ ๋“ฃ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚˜์€ ์„ฑ๋Šฅ
  • ๊ต์ฐจ ๋„๋ฉ”์ธ iframe์—์„œ ์ž‘๋™
  • ์š”์†Œ๊ฐ€ ๋‹ค๋ฅธ ์š”์†Œ๋ฅผ ๋ฐฉํ•ดํ•˜๊ฑฐ๋‚˜ ๊ต์ฐจํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Intersection Observer๋Š” ๋ณธ๊ฒฉ์ ์ธ ํ‘œ์ค€์œผ๋กœ ๋‚˜์•„๊ฐ€๊ณ  ์žˆ์œผ๋ฉฐ Chrome 51 ์ด์ƒ, Edge 15 ์ด์ƒ ๋ฐ Firefox 55 ์ด์ƒ์—์„œ ์ด๋ฏธ ์ง€์›๋˜๋ฉฐ Safari ์šฉ์œผ๋กœ ๊ฐœ๋ฐœ ์ค‘์ž…๋‹ˆ๋‹ค. ๋„์žˆ๋‹ค polyfill ์ด ์—†์Šต๋‹ˆ๋‹ค.


์ด์ „ ๋‹ต๋ณ€

Dan ์ด ์ œ๊ณต ํ•œ ๋‹ต๋ณ€ ์—๋Š” ์ผ๋ถ€ ์ƒํ™ฉ์— ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ ๊ฐ€์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ์ค‘ ์ผ๋ถ€๋Š” ํ•˜๋‹จ ๊ทผ์ฒ˜์˜ ๋‹ต๋ณ€์—์„œ ์ง€์ ๋˜์—ˆ์œผ๋ฏ€๋กœ ๊ทธ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์š”์†Œ์— ๋Œ€ํ•ด ์ž˜๋ชป๋œ ๊ธ์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์ŠคํŠธ์ค‘์ธ ์š”์†Œ ์•ž์— ๋‹ค๋ฅธ ์š”์†Œ๊ฐ€ ์ˆจ๊ฒจ์ ธ ์žˆ์Œ
  • ๋ถ€๋ชจ ๋˜๋Š” ์กฐ์ƒ ์š”์†Œ์˜ ๊ฐ€์‹œ ์˜์—ญ ์™ธ๋ถ€
  • CSS clip์†์„ฑ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆจ๊ฒจ์ง„ ์š”์†Œ ๋˜๋Š” ํ•˜์œ„ ์š”์†Œ

์ด๋Ÿฌํ•œ ์ œํ•œ ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์—์„œ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค .

ํ•ด๊ฒฐ์ฑ…: isElementVisible()

์•„๋ž˜ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์ฝ”๋“œ์˜ ์ผ๋ถ€์— ๋Œ€ํ•œ ์„ค๋ช…๊ณผ ํ•จ๊ป˜ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๋‹ค.

function isElementVisible(el) {
    var rect     = el.getBoundingClientRect(),
        vWidth   = window.innerWidth || document.documentElement.clientWidth,
        vHeight  = window.innerHeight || document.documentElement.clientHeight,
        efp      = function (x, y) { return document.elementFromPoint(x, y) };

    // Return false if it's not in the viewport
    if (rect.right < 0 || rect.bottom < 0
            || rect.left > vWidth || rect.top > vHeight)
        return false;

    // Return true if any of its four corners are visible
    return (
          el.contains(efp(rect.left,  rect.top))
      ||  el.contains(efp(rect.right, rect.top))
      ||  el.contains(efp(rect.right, rect.bottom))
      ||  el.contains(efp(rect.left,  rect.bottom))
    );
}

ํ•ฉ๊ฒฉ ์‹œํ—˜ : http://jsfiddle.net/AndyE/cAY8c/

๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ :

์ถ”๊ฐ€ ์‚ฌํ•ญ

๊ทธ๋Ÿฌ๋‚˜์ด ๋ฐฉ๋ฒ•์—๋Š” ๊ณ ์œ  ํ•œ ์ œํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋™์ผํ•œ ์œ„์น˜์—์žˆ๋Š” ๋‹ค๋ฅธ ์š”์†Œ๋ณด๋‹ค ๋‚ฎ์€ z- ์ƒ‰์ธ์œผ๋กœ ํ…Œ์ŠคํŠธ์ค‘์ธ ์š”์†Œ๋Š” ์•ž์—์žˆ๋Š” ์š”์†Œ๊ฐ€ ์‹ค์ œ๋กœ ์ผ๋ถ€๋ฅผ ์ˆจ๊ธฐ์ง€ ์•Š๋”๋ผ๋„ ์ˆจ๊ฒจ์ง„ ๊ฒƒ์œผ๋กœ ์‹๋ณ„๋ฉ๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ์ด ๋ฐฉ๋ฒ•์€ Dan์˜ ์†”๋ฃจ์…˜์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋‘ element.getBoundingClientRect()์™€ document.elementFromPoint()CSSOM ์ž‘์—… ์ดˆ์•ˆ ์‚ฌ์–‘์˜ ์ผ๋ถ€์ด๋ฉฐ ์ดํ›„ ์ ์–ด๋„ IE 6์—์„œ ์ง€์›ํ•˜๊ณ , ๊ฐ€์žฅ ์˜ค๋žซ๋™์•ˆ ๋ฐ์Šคํฌํƒ‘ ๋ธŒ๋ผ์šฐ์ € (ํ•˜์ง€ ์™„๋ฒฝํ•˜๊ฒŒ์ด๊ธฐ๋Š”ํ•˜์ง€๋งŒ). ์ž์„ธํ•œ ๋‚ด์šฉ ์€์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ Quirksmode ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

contains()์—์„œ ๋ฐ˜ํ™˜ ํ•œ document.elementFromPoint()์š”์†Œ๊ฐ€ ๊ฐ€์‹œ์„ฑ ํ…Œ์ŠคํŠธ์ค‘์ธ ์š”์†Œ์˜ ํ•˜์œ„ ๋…ธ๋“œ ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค . ๋ฆฌํ„ด ๋œ ์š”์†Œ๊ฐ€ ๋™์ผํ•œ ์š”์†Œ ์ธ ๊ฒฝ์šฐ์—๋„ true๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‹จ์ง€ ์ˆ˜ํ‘œ๋ฅผ ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›๋˜๋ฉฐ Firefox 9.0์ด ๋งˆ์ง€๋ง‰์œผ๋กœ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ด์ „ Firefox ์ง€์›์— ๋Œ€ํ•ด์„œ๋Š”์ด ๋‹ต๋ณ€์˜ ๊ธฐ๋ก์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๊ฐ€์‹œ์„ฑ์„ ์œ„ํ•ด ์š”์†Œ ์ฃผ์œ„์— ๋” ๋งŽ์€ ์ ์„ ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ๊ฒฝ์šฐ (์˜ˆ : ์š”์†Œ๊ฐ€ 50 % ์ด์ƒ์œผ๋กœ ๋ฎ์—ฌ ์žˆ์ง€ ์•Š์€์ง€ ํ™•์ธํ•˜๋ ค๋ฉด) ์‘๋‹ต์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์„ ์กฐ์ •ํ•˜๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ํ”ฝ์…€์„ 100 % ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ์†๋„๊ฐ€ ๋งค์šฐ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

๋‚˜๋Š” Dan์˜ ๋Œ€๋‹ต์„ ์‹œ๋„ํ–ˆ๋‹ค . ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฝ๊ณ„๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋Œ€์ˆ˜๋Š” ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ ํฌ๊ธฐ๋ณด๋‹ค ์ž‘๊ณ  ๋ทฐํฌํŠธ ๋‚ด๋ถ€์— ์™„์ „ํžˆ ์žˆ์–ด์•ผํ•ด์„œ true์‰ฝ๊ฒŒ ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค . ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ์— ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋ ค๋ฉด ryanve์˜ ๋‹ต๋ณ€ ์ด ๊ฐ€๊น์ง€๋งŒ ํ…Œ์ŠคํŠธ์ค‘์ธ ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ์™€ ๊ฒน์น˜๋ฏ€๋กœ ๋‹ค์Œ์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();

    return rect.bottom > 0 &&
        rect.right > 0 &&
        rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}

๋‹ต๋ณ€

๊ณต๊ณต ์„œ๋น„์Šค :
Dan์€ ์˜ฌ๋ฐ”๋ฅธ ๊ณ„์‚ฐ (ํŠนํžˆ ํœด๋Œ€ ์ „ํ™” ํ™”๋ฉด์—์„œ> ์ฐฝ์ผ ์ˆ˜ ์žˆ์Œ), ์˜ฌ๋ฐ”๋ฅธ jQuery ํ…Œ์ŠคํŠธ ๋ฐ isElementPartiallyInViewport ์ถ”๊ฐ€์™€ ํ•จ๊ป˜ ๋Œ€๋‹ตํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ window.innerWidth์™€ document.documentElement.clientWidth ์˜ ์ฐจ์ด์  ์€ clientWidth / clientHeight๋Š” ์Šคํฌ๋กค ๋ง‰๋Œ€๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์ง€๋งŒ window.innerWidth / Height๋Š” ์Šคํฌ๋กค ๋ง‰๋Œ€๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

function isElementPartiallyInViewport(el)
{
    // Special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery)
        el = el[0];

    var rect = el.getBoundingClientRect();
    // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
    var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
    var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

    return (vertInView && horInView);
}


// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el)
{
    // Special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery)
        el = el[0];

    var rect = el.getBoundingClientRect();
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    return (
           (rect.left >= 0)
        && (rect.top >= 0)
        && ((rect.left + rect.width) <= windowWidth)
        && ((rect.top + rect.height) <= windowHeight)
    );
}


function fnIsVis(ele)
{
    var inVpFull = isElementInViewport(ele);
    var inVpPartial = isElementPartiallyInViewport(ele);
    console.clear();
    console.log("Fully in viewport: " + inVpFull);
    console.log("Partially in viewport: " + inVpPartial);
}

ํ…Œ์ŠคํŠธ ์‚ฌ๋ก€

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Test</title>
    <!--
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="scrollMonitor.js"></script>
    -->

    <script type="text/javascript">

        function isElementPartiallyInViewport(el)
        {
            // Special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery)
                el = el[0];

            var rect = el.getBoundingClientRect();
            // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
            var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
            var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

            return (vertInView && horInView);
        }


        // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        function isElementInViewport (el)
        {
            // Special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery)
                el = el[0];

            var rect = el.getBoundingClientRect();
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            return (
                   (rect.left >= 0)
                && (rect.top >= 0)
                && ((rect.left + rect.width) <= windowWidth)
                && ((rect.top + rect.height) <= windowHeight)
            );
        }


        function fnIsVis(ele)
        {
            var inVpFull = isElementInViewport(ele);
            var inVpPartial = isElementPartiallyInViewport(ele);
            console.clear();
            console.log("Fully in viewport: " + inVpFull);
            console.log("Partially in viewport: " + inVpPartial);
        }


        // var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
        // var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
    </script>
</head>

<body>
    <div style="display: block; width: 2000px; height: 10000px; background-color: green;">

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
        <div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
        t
        </div>

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />
    </div>

    <!--
    <script type="text/javascript">

        var element = document.getElementById("myele");
        var watcher = scrollMonitor.create(element);

        watcher.lock();

        watcher.stateChange(function() {
            console.log("state changed");
            // $(element).toggleClass('fixed', this.isAboveViewport)
        });
    </script>
    -->
</body>
</html>

๋‹ต๋ณ€

getBoundingClientRect ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” verge ์†Œ์Šค๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค . ๊ทธ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค

function inViewport (el) {

    var r, html;
    if ( !el || 1 !== el.nodeType ) { return false; }
    html = document.documentElement;
    r = el.getBoundingClientRect();

    return ( !!r
      && r.bottom >= 0
      && r.right >= 0
      && r.top <= html.clientHeight
      && r.left <= html.clientWidth
    );

}

๊ทธ๊ฒƒ์€ ๋ฐ˜ํ™˜ํ•˜๋Š” true๊ฒฝ์šฐ ์–ด๋–ค ์š”์†Œ์˜ ์ผ๋ถ€๊ฐ€ ๋ทฐํฌํŠธ์— ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

๋” ์งง๊ณ  ๋น ๋ฅธ ๋ฒ„์ „ :

function isElementOutViewport(el){
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

๊ทธ๋ฆฌ๊ณ  ํ•„์š”์— ๋”ฐ๋ผ jsFiddle : https://jsfiddle.net/on1g619L/1/


์ด ๊ธ€์€ Javascript ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜์—ˆ๊ณ  ๋‹˜์— ์˜ํ•ด ์— ์ž‘์„ฑ๋์Šต๋‹ˆ๋‹ค.