ある要素が見える位置までスクロール

into_viewport という関数を作ってみた。

Chrome 以外ではチェックしてない。(でも IE 含め、他のブラウザで使えない関数などは使ってないはず)

IE に getComputedStyle が無いのを忘れてた。var s = getComputedStyle(elem, null); のところを var s = window.getComputedStyle ? getComputedStyle(elem, null) : elem.currentStyle; にしたらいいのかな? (IE 持ってないのでわからない)

微修正。body や html 要素に overflow:auto などが着いてると変なことになる件。あと、FirefoxOpera では互換モードのとき document.body.scrollTop が使えて、標準モードのときは document.documentElement.scrollTop を使わないといけない。ChromeSafari は標準、互換とも document.body.scrollTop で OK。UserAgent で判定するのは不本意だけど、このへんは好きな判定方法を使ったらいい。

function into_viewport(elem) {
  var target = elem;

  while (elem = elem.parentNode) {
    if (elem === document.body || elem === document.documentElement) break;
    var s = window.getComputedStyle ? getComputedStyle(elem, null) : elem.currentStyle;
    if (s && /auto|scroll/.test(s.overflowX + s.overflowY)) {alert([target,elem]);
      scroll_to_element(target, elem);
      into_viewport(elem);
      return;
    }
  }

  var origin = (document.compatMode !== 'BackCompat' && (window.opera || navigator.userAgent.indexOf('Gecko/'))) ? document.documentElement : document.body;
  scroll_to_element(target, origin);
}

function scroll_to_element(elem, origin) {
  if (origin === document.body || origin === document.documentElement) {
    var outer = {left: 0, right: window.innerWidth, top: 0, bottom: window.innerHeight};
  } else {
    var outer = origin.getBoundingClientRect();
  }
  var inner = elem.getBoundingClientRect();
  var x = origin.scrollLeft;
  var y = origin.scrollTop;

  var flag = 0;
  if ((outer.left > inner.left || outer.right < inner.right) && ++flag)
    x += (inner.left + inner.right) / 2 - (outer.left + outer.right) / 2;
  if ((outer.top > inner.top || outer.bottom < inner.bottom) && ++flag)
    y += (inner.top + inner.bottom) / 2 - (outer.top + outer.bottom) / 2;

  //if (flag) {origin.scrollLeft = x; origin.scrollTop = y;}  // スムーズスクロールしない場合

  if (flag) new Tween(origin, { // スムーズスクロールする場合
    time: 0.1,
    scrollLeft: {
      to: x
    },
    scrollTop: {
      to: y
    }
  });
}

Prototype.js の Element.scrollTo だと overflow: scroll/auto な親要素をわざわざスクロールしてくれないと思う。(ちらっとコード見ただけなので違ってるかも)

Tween は id:os0x さんの AutoPatchwork から持ってきたのを微修正して使っている。

ところで、

上のコードは、実は Chrome 用の Migemo ページ内検索を作ってるときに書いたのだけど、もし試したい人がいれば試してください。

正式に公開しました→Migemoでページ内検索するためのGoogle Chrome Extension - by edvakf in hatena




ソースを一つのフォルダに入れ、load unpacked extension でそのフォルダを指定。ChromeMigemo Extension が必須。

今のところキーバインドは、/ キーで検索開始、↓↑で次と前を選択、; でフォーカス。

ほとんど完成しているんだけど、一つだけ気になるのが、普通だったら↓のように "1 or 5" というのがこの位置に出るところが、

何故かこのページだけ右に大きくずれて出てしまう (↓うっすら見える?)。理由が分からなくてお手上げです。この件は修正した。

その他バグを発見したら教えてください。


MigemoFindInPage は最終的に ChromeKeyConfig と連携させるかマージする方向でいこうと思っている。キーハンドリングは出来ればやりたくない。