Firefox> = 17のwheel
イベントには、deltaMode
プロパティがあります。私が使用しているOS /マウスでは、1
(またはDOM_DELTA_LINE
)に設定されています。この設定は、deltaX
およびdeltaY
イベント値がピクセルではなく線で測定されることを意味します。確かに、デルタがピクセルであると偽った場合、スクロール速度はFirefoxの通常よりもはるかに遅くなります。
対照的に、Chrome31は0
(またはDOM_DELTA_PIXEL
)のdeltaMode
を使用します。これにより、通常の速度でスクロールをシミュレートできます。
ライン値をピクセル値に変換できれば、すべて設定されます。しかし、「線」とは何かについてのドキュメントのスクラップを見つけることができません。 Firefoxでfont-size
とline-height
を変更してみましたが、スクロール動作は変わりませんでした。
「線」がどのように定義されているか知っている人はいますか? W3Cは、「これは多くのフォームコントロールに当てはまります」と言っています。
編集:ここに フィドル 奇妙さを示します。 FirefoxがDOM_DELTA_LINE
モードの場合、ピクセルとラインの間に一貫した比率はありません-それはいたるところにあります。また、マウスの代わりにトラックパッドを使用するように切り替えて、FirefoxをDOM_DELTA_PIXEL
モードに切り替えると、一貫した比率もありません。一方、Chrome 31では、比率はDOM_DELTA_PIXEL
モードではほとんどの場合1:1に非常に近くなります。
更新:Firefoxでマウスホイールを1ティッククリックすると、deltaMode
はDOM_DELTA_LINE
になり、ピクセルデルタはCSS font-size
ですが、line-height
にはありません。デモについては このフィドル を参照してください。この動作は、ホイールを非常にゆっくりと刻むときにのみ当てはまります。速度または勢いがある場合、ラインとピクセルの比率は、特定のインスタンスで、または全体として予測できません。私の知る限り、DOM_DELTA_LINE
モードで提供されるデルタ測定を使用してFirefoxのスクロール動作をエミュレートする方法はありません。
DOM_DELTA_PIXEL
モードでは、動作はほぼピクセルパーフェクトです。つまり、スクロールされた実際のピクセルと報告されたピクセルデルタ値の比率はほぼ正確に1であり、これは 同じフィドル で示されています。
I Mozillaにバグを提出 、DOM_DELTA_LINE
モードでのwheel
イベントの動作は、予測できないため(つまり、方程式であるため)役に立たないと主張します。ここで、単位と大きさの両方が変数です)。 Firefox自体がこれらのデルタを尊重しないという事実にもかかわらず、予想される動作はwheel
イベントがOSによって提供されるネイティブデルタを通過することであるため、この問題は無効とマークされています。
DOM_DELTA_LINE
がどこかの仕様で定義されることを期待して、この質問は開いたままにしておきます。私の知る限り、font-size
への依存(line-height
ではない)はまだどこにも記述されていません。
Chromium Issue Trackerからの次のコメントと私自身の観察に基づくと、DOM_DELTA_LINE
の結果のスクロール値は仕様によって具体的に定義されていない可能性がありますが、Firefoxは現在deltaMode
以外のホイールイベントを報告する唯一のブラウザーのようです。 DOM_DELTA_PIXEL
(0
)として。
コメント Chromiumの問題から DOM3ホイールイベントを実装 :
最終的にIEが行うことを実行し、要素をスクロールする正確なピクセル数を報告しました。
次のアサートは常に真です(要素をスクロールできる場合)。
element.scrollTop = 0; element.addEventListener('wheel', function(e) { assert(e.deltaMode === MouseEvent. DOM_DELTA_PIXEL); assert(element.scrollTop === e.deltaY); }); // scroll
このようにして、常にスクロールする量を正確に知ることができます。
deltaMode
をDOM_DELTA_PIXEL
以外に設定することはありません。
そのコメントによると、ChromiumはIEの唯一のピクセルデルタと一致します。カバーされていませんが、これはほぼ確実に最新のOperaおよびSafariに拡張されます。複数の入力デバイスを使用したWindow、Mac、およびLinuxでのテストからの私自身の観察は、これを否定しませんでした。
したがって、FirefoxはDOM_DELTA_LINE
(1
)またはDOM_DELTA_PAGE
(2
)のdeltaMode
を報告する唯一のブラウザであるため、とりあえず、Firefoxがこれらの値をどのように計算するかを知る必要があるだけです。さて、ここで少し注意が必要ですが、Firefoxのソースを検索し、試行錯誤を繰り返した結果、デフォルトのフォントとデフォルトのフォントサイズに直接対応していることがわかりました。具体的には、ページ上のCSSを無視して、次の設定で構成されたもの。
つまり、スクロールで使用される行の高さを正しく検出するには、計算されたレンダリングの高さを検出するための完全にスタイル設定されていないインライン要素が必要です。ページ上のCSSはほぼ確実に干渉するため、検出を行うには、iframeに新しくクリーンなウィンドウを作成する必要があります。
DOM_DELTA_LINE
によってトリガーされたスクロールイベントによって使用される行の高さの検出:この目的のために、純粋で変更されていない行の高さを同期的に検出する次の小さな関数を作成しました。
function getScrollLineHeight() {
var r;
var iframe = document.createElement('iframe');
iframe.src = '#';
document.body.appendChild(iframe);
var iwin = iframe.contentWindow;
var idoc = iwin.document;
idoc.open();
idoc.write('<!DOCTYPE html><html><head></head><body><span>a</span></body></html>');
idoc.close();
var span = idoc.body.firstElementChild;
r = span.offsetHeight;
document.body.removeChild(iframe);
return r;
}
// Get the native croll line height.
console.log(getScrollLineHeight());
これで、行の高さのデルタがピクセル単位でどれだけ変換されるかがわかりました。ただし、Windowでは、考慮しなければならないことがもう1つあります。 Windowsでは、デフォルトのスクロール速度がオーバーライドされ、デフォルトで2倍速くなりますが、ルート要素に対してのみです。
Windowsのデフォルトのシステムスクロール速度はWebKitのスクロール速度よりも遅いため、システムスクロール速度のオーバーライドメカニズムを提供しています。これは、加速システムの代替方法として提案されました(次のセクションを参照)。
これは、Windowsのデフォルト設定のみで有効になっています。 mousewheel.system_scroll_override_on_root_content.enabledはそれを切り替えることができます。
Windowsでは、システムのスクロール速度設定がユーザーまたはマウスドライバーによってカスタマイズされていない場合にのみ、これがスクロール速度を上書きします。 その他では、これは常に速度を上書きします。
比率は、非表示の設定で指定できます。 mousewheel.system_scroll_override_on_root_content.vertical.factorは垂直スクロールイベント用です。 mousewheel.system_scroll_override_on_root_content.horizontal.factorは水平スクロールイベント用です。値は1/100として使用されます(つまり、デフォルト値200は2.0を意味します)。
nsEventStateManagerは、ドキュメントのrootスクロール可能ビューをスクロールするために実行するときに、スクロール速度に比率を掛けます。したがって、DOMMouseScrollイベントのデルタ値がこれによって上書きされることはありません。
bug 513817 も参照してください。
これはデフォルトでドキュメントのルートにのみ適用され、textarea
のようなドキュメント内のスクロール要素は影響を受けません(おそらくiframeを除く?)。デフォルトの2xが再構成されている場合、指定された値を取得する方法もありません。したがって、この値が重要であると考える場合は、おそらく技術的に非標準でありながら人気のあるnavigator.platform
を使用して、ユーザーエージェントOSスニッフィングに頼る必要があります。
DOM_DELTA_PAGE
はどうですか?:Windowsには、行数でスクロールする代わりに、ほぼフルページでスクロールする垂直スクロールの代替設定もあります。明確にするために、これはWindows7でこれを制御する「一度に1つの画面」設定のダイアログです。
これがアクティブになっている場合、シングルクリックでほぼページ全体がスクロールされます。ここでは、スクロールパネルの高さから、スクロールバーを差し引いたものを意味します。 Firefoxはスクロールの量を減らすために他のいくつかのことを考慮に入れているので、私はほとんど言います。つまり、いくつかの行、パーセンテージを減らし、固定位置のヘッダーとフッターを何らかの方法で減算します。一部のロジックについては、次のコードブロックを参照してください。
layout/generic/nsGfxScrollFrame.cpp
:からの抜粋
nsSize ScrollFrameHelper::GetPageScrollAmount() const { nsSize lineScrollAmount = GetLineScrollAmount(); nsSize effectiveScrollPortSize; if (mIsRoot) { // Reduce effective scrollport height by the height of any fixed-pos // headers or footers nsIFrame* root = mOuter->PresContext()->PresShell()->GetRootFrame(); effectiveScrollPortSize = GetScrollPortSizeExcludingHeadersAndFooters(root, mScrollPort); } else { effectiveScrollPortSize = mScrollPort.Size(); } // The page increment is the size of the page, minus the smaller of // 10% of the size or 2 lines. return nsSize( effectiveScrollPortSize.width - std::min(effectiveScrollPortSize.width/10, 2*lineScrollAmount.width), effectiveScrollPortSize.height - std::min(effectiveScrollPortSize.height/10, 2*lineScrollAmount.height)); }
固定位置のヘッダー要素とフッター要素として正確に検出されるものと検出されないものは100%わかりませんが、この質問で尋ねられるDOM_DELTA_PAGE
に加えて、DOM_DELTA_LINE
モードもどのように機能するかについての概要がわかります。約。
私はFirefox25(Linux上)であなたのフィドルを試しました-そしてホイールイベントでのみscrollTopを追跡するためにそれを拡張しました。フィドルでは、スクロールデルタは、ホイールイベントよりもはるかに頻繁にトリガーされるスクロールイベントで計算されます。また、ソフトスクロールモードでのスクロールイベントは、ホイールイベントに比べて遅れているようです。 (つまり、ソフトスクロールがまだ終了していないときに測定すると、scrollTop()の「中間」値が得られます。)これらが、スクロールデルタとホイールイベントの間に良好な相関関係が得られない理由だと思います。 (注:wheelイベントは、関連するスクロールイベントの前に処理されるようです。)
ソフトスクロールがオフになっている場合、スクロールイベントごとに少なくとも1つのホイールイベントがあります。あなたのフィドルは、私にとって「ホイール」の間、完全に一定の「px/DOM_DELTA_LINE:18」を与えます。 2つのスパンを持つdivを追加した場合<span id="lineN">N</span>
と<br/>
間と測定($("#line2").position().top - $("#line1").position().top)
それから私はちょうど18を得る。
概要:wheelイベントを使用すると、少なくとも私の環境では、スクロール距離をピクセル単位で計算できます。これがあなたにも当てはまることを願っています。
これが私の拡張機能を備えたあなたのフィドルのための私の拡張フィドルのJavaScriptコードです:
var DeltaModes = {
0: "DOM_DELTA_PIXEL",
1: "DOM_DELTA_LINE",
2: "DOM_DELTA_PAGE"
};
var statsPane = $(".stats-pane");
var scrollTop = $(window).scrollTop();
var scrollDelta = 0;
var wheelEvents = 0;
var scrollEvents = 0;
var scrollTopOnWheel = 0;
$(window).scroll(function(){
scrollEvents++;
var newScrollTop = $(window).scrollTop();
scrollDelta = scrollTop - newScrollTop;
scrollTop = newScrollTop;
});
$(window).on("wheel", function(e){
wheelEvents++;
var wheelScrollTop = $(window).scrollTop();
var wheelScrollDelta = wheelScrollTop - scrollTopOnWheel;
e = e.originalEvent;
var pxPerDeltaUnit = Math.abs(scrollDelta) / Math.abs(e.deltaY);
var deltaMode = DeltaModes[e.deltaMode];
var stats = [deltaMode + ": " + e.deltaY];
stats.Push("px delta: " + scrollDelta);
stats.Push("px/" + deltaMode + ": " + pxPerDeltaUnit);
stats.Push("wheel scroll top (prev): " + scrollTopOnWheel);
stats.Push("wheel scroll top: " + wheelScrollTop);
stats.Push("wheel scroll delta: " + wheelScrollDelta);
stats.Push("line height: " + ($("#line2").position().top - $("#line1").position().top));
stats.Push("wheel event#: " + wheelEvents);
stats.Push("scroll event#: " + scrollEvents);
statsPane.html('<div>' + stats.join('</div><div>') + '</div>');
scrollTopOnWheel = wheelScrollTop;
//scrollTop = newScrollTop;
});
そしてHTML:
<div class="stats-pane"></div>
<div>Hey.</div>
<div>Hi.</div>
<div>Hello.</div>
<div>
<span id="line1">1</span><br/>
<span id="line2">2</span><br/>
</div>
font-size: initial
を使用して、iframeを使用せずにスクロールラインの高さ(ブラウザのデフォルトのフォントサイズ)を取得する簡単な方法があります。
function getScrollLineHeight() {
const el = document.createElement('div');
el.style.fontSize = 'initial';
el.style.display = 'none';
document.body.appendChild(el);
const fontSize = window.getComputedStyle(el).fontSize;
document.body.removeChild(el);
return fontSize ? window.parseInt(fontSize) : undefined;
}
// Get the native scroll line height
console.log(getScrollLineHeight());
html
要素とbody
要素のフォントサイズを上書きするページで、Chrome、Firefox、Safari(9と12をテスト)、Edge、IE11の最新バージョンでこれをテストしました。これは、IE11を除く他のすべてのテスト済みブラウザーで確実に機能するようです。 IE11ではCSSキーワード body
をサポートしていないため、IE11ではinitial
から継承されたフォントサイズが返されます。
したがって、IE11をサポートする必要がなくなった場合、これは機能するはずです。