Поймать браузер "зум" событие в JavaScript
Можно ли с помощью JavaScript определить, когда пользователь изменяет масштаб страницы? Я просто хочу поймать событие "zoom" и ответить на него (аналогично событию window.onresize).
Благодарю.
12 ответов
Там нет никакого способа, чтобы активно обнаружить, если есть зум. Здесь я нашел хорошую запись о том, как вы можете попытаться реализовать это.
Я нашел два способа определения уровня масштабирования. Один из способов обнаружения изменений уровня масштабирования основан на том факте, что процентные значения не увеличиваются. Процентное значение относится к ширине области просмотра и, следовательно, не зависит от масштаба страницы. Если вы вставите два элемента, один с позицией в процентах, а другой с одинаковой позицией в пикселях, они будут раздвигаться при увеличении страницы. Найдите соотношение между позициями обоих элементов, и вы получите уровень масштабирования. Смотрите тестовый пример. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3
Вы также можете сделать это с помощью инструментов, описанных выше. Проблема в том, что вы более или менее делаете обоснованные предположения о том, увеличена ли страница. Это будет работать лучше в некоторых браузерах, чем в других.
Невозможно определить, увеличена ли страница, если они загружают вашу страницу во время увеличения.
У меня была эта проблема и наконец. У меня есть решение. это просто и работает для меня. ("Mozilla/5.0 (X11; Linux x86_64;Gecko/20100101 Firefox/50.0)".
отношение px = отношение физического пикселя к CSS; при любом увеличении пиксели окна просмотра уменьшаются и должны соответствовать экрану, поэтому соотношение должно увеличиваться. но при изменении размера окна уменьшается размер экрана, а также размеры пикселей. поэтому соотношение сохранится.
масштабирование: вызвать событие windows.resize -> и изменить px_ratio resizing: изменить событие windows.resize -> не изменить px_ratio
//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
$(window).resize(function(){isZooming();});
function isZooming(){
var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
if(newPx_ratio != px_ratio){
px_ratio = newPx_ratio;
console.log("zooming");
return true;
}else{
console.log("just resizing");
return false;
}
}
Хорошие новости каждый некоторые люди! Новые браузеры будут вызывать событие изменения размера окна при изменении масштаба.
Я использую этот кусок JavaScript, чтобы реагировать на "события" Zoom.
Опрашивает ширину окна.
(Как несколько предложено на этой странице (на которую ссылается Ян Эллиотт): http://novemberborn.net/javascript/page-zoom-ff3 [архив])
Протестировано с Chrome, Firefox 3.6 и Opera, а не IE.
С уважением, Магнус
var zoomListeners = [];
(function(){
// Poll the pixel width of the window; invoke zoom listeners
// if the width has been changed.
var lastWidth = 0;
function pollZoomFireEvent() {
var widthNow = jQuery(window).width();
if (lastWidth == widthNow) return;
lastWidth = widthNow;
// Length changed, user must have zoomed, invoke listeners.
for (i = zoomListeners.length - 1; i >= 0; --i) {
zoomListeners[i]();
}
}
setInterval(pollZoomFireEvent, 100);
})();
Это работает для меня:
var deviceXDPI = screen.deviceXDPI;
setInterval(function(){
if(screen.deviceXDPI != deviceXDPI){
deviceXDPI = screen.deviceXDPI;
... there was a resize ...
}
}, 500);
Это нужно только на IE8. Все остальные браузеры, естественно, генерируют событие изменения размера.
Хотя это 9-летний вопрос, проблема сохраняется!
Я обнаружил изменение размера при исключении увеличения в проекте, поэтому я отредактировал свой код, чтобы он работал для определения как изменения размера, так и изменения масштаба друг от друга. Это работает большую часть времени, поэтому, если большинство достаточно хорошо для вашего проекта, то это должно быть полезно! Он обнаруживает увеличение в 100% случаев в том, что я тестировал до сих пор. Единственная проблема заключается в том, что если пользователь сходит с ума (то есть из-за резкого изменения размера окна) или задержки окна, он может срабатывать как увеличение вместо изменения размера окна.
Это работает, обнаруживая изменение в window.outerWidth
или же window.outerHeight
как изменение размера окна при обнаружении изменения в window.innerWidth
или же window.innerHeight
независимо от изменения размера окна в качестве увеличения.
//init object to store window properties
var windowSize = {
w: window.outerWidth,
h: window.outerHeight,
iw: window.innerWidth,
ih: window.innerHeight
};
window.addEventListener("resize", function() {
//if window resizes
if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
windowSize.w = window.outerWidth; // update object with current window properties
windowSize.h = window.outerHeight;
windowSize.iw = window.innerWidth;
windowSize.ih = window.innerHeight;
console.log("you're resizing"); //output
}
//if the window doesn't resize but the content inside does by + or - 5%
else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
console.log("you're zooming")
windowSize.iw = window.innerWidth;
}
}, false);
Примечание: мое решение похоже на решение KajMagnus, но для меня это сработало лучше.
Есть отличный плагин, построенный из yonran
что может сделать обнаружение. Вот его ранее отвеченный вопрос о Stackru. Это работает для большинства браузеров. Приложение так просто, как это:
window.onresize = function onresize() {
var r = DetectZoom.ratios();
zoomLevel.innerHTML =
"Zoom level: " + r.zoom +
(r.zoom !== r.devicePxPerCssPx
? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
: "");
}
Согласно MDN, "matchMedia" - правильный способ сделать это https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
это немного привередливо, потому что каждый экземпляр может просматривать только один MQ за раз, поэтому, если вас интересует какое-либо изменение уровня масштабирования, вам нужно сделать кучу сопоставлений... но поскольку браузер отвечает за создание событий, это, вероятно, все еще более производительный, чем опрос, и вы можете задросселировать или отклонять обратный вызов или прикреплять его к кадру анимации или чему-то еще - вот реализация, которая кажется довольно быстрой, не стесняйтесь менять _throttle или что-то еще, если вы уже зависите от этого.
Запустите фрагмент кода и увеличивайте и уменьшайте масштаб в браузере, обратите внимание на обновленное значение в разметке - я тестировал это только в Firefox! дайте мне знать, если вы заметите какие-либо проблемы.
const el = document.querySelector('#dppx')
if ('matchMedia' in window) {
function observeZoom(cb, opts) {
opts = {
// first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
ceiling: 3,
floor: 0.3,
granularity: 0.05,
...opts
}
const precision = `${opts.granularity}`.split('.')[1].length
let val = opts.floor
const vals = []
while (val <= opts.ceiling) {
vals.push(val)
val = parseFloat((val + opts.granularity).toFixed(precision))
}
// construct a number of mediamatchers and assign CB to all of them
const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))
// poor person's throttle
const throttle = 3
let last = performance.now()
mqls.forEach(mql => mql.addListener(function() {
console.debug(this, arguments)
const now = performance.now()
if (now - last > throttle) {
cb()
last = now
}
}))
}
observeZoom(function() {
el.innerText = window.devicePixelRatio
})
} else {
el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>
Событие изменения размера работает в современных браузерах, прикрепляя событие кwindow
, а затем считывая значенияbody
, или другой элемент, например (.getBoundingClientRect()).
В некоторых более ранних браузерах можно было зарегистрировать обработчики событий изменения размера для любого элемента HTML. По-прежнему можно установить атрибуты onresize или использовать addEventListener() для установки обработчика для любого элемента. Однако события изменения размера запускаются только для объекта окна (то есть возвращаются document.defaultView). Только обработчики, зарегистрированные в объекте окна, будут получать события изменения размера.
window.addEventListener("resize", getSizes, false)
function getSizes(){
let body = document.body
console.log(body.clientWidth +"px x "+ body.clientHeight + "px")
}
Другая альтернатива: API ResizeObserver
В зависимости от вашего макета вы можете следить за изменением размера конкретного элемента.
Это хорошо работает с "адаптивными" макетами, потому что размер контейнера изменяется при масштабировании.
function watchBoxchange(e){
// console.log(e[0].contentBoxSize.inlineSize+" "+e[0].contentBoxSize.blockSize)
info.textContent = e[0].contentBoxSize.inlineSize+" * "+e[0].contentBoxSize.blockSize + "px"
}
new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
width: 200px;
height:100px;
overflow: auto;
resize: both;
border: 3px black solid;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 8vh
}
<div id="fluid">
<info id="info"></info>
</div>
Будьте осторожны, чтобы не перегружать задачи javascript событиями пользовательских жестов. Используйте requestAnimationFrame всякий раз, когда вам нужно перерисовать.
Вот чистое решение:
// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
Object.defineProperty(window,'devicePixelRatio',{
enumerable: true,
configurable: true,
get:function(){
return screen.deviceXDPI/screen.logicalXDPI;
}
});
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
var newValue=window.devicePixelRatio;
if(newValue!==oldValue){
// TODO polyfill CustomEvent for IE
var event=new CustomEvent('devicepixelratiochange');
event.oldValue=oldValue;
event.newValue=newValue;
oldValue=newValue;
window.dispatchEvent(event);
}
});
window.addEventListener('devicepixelratiochange',function(e){
console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});
Я хотел бы предложить улучшение предыдущего решения с отслеживанием изменений ширины окна. Вместо сохранения собственного массива слушателей событий вы можете использовать существующую систему событий javascript и запускать собственное событие при изменении ширины, а также привязывать к нему обработчики событий.
$(window).bind('myZoomEvent', function() { ... });
function pollZoomFireEvent()
{
if ( ... width changed ... ) {
$(window).trigger('myZoomEvent');
}
}
Throttle / debounce может помочь в снижении скорости вызовов вашего обработчика.
На iOS 10 можно добавить прослушиватель событий в touchmove
событие и определить, масштабируется ли страница с текущим событием.
var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);
if(pageHasZoom) {
// page is zoomed
if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
// page is zoomed with this event
}
}
prevZoomFactorX = zoomFactorX;
prevZoomFactorY = zoomFactorY;
});
<script>
var zoomv = function() {
if(topRightqs.style.width=='200px){
alert ("zoom");
}
};
zoomv();
</script>
Вы также можете получить события изменения размера текста и коэффициент масштабирования, введя элемент div, содержащий по крайней мере неразрывный пробел (возможно, скрытый), и регулярно проверяя его высоту. Если высота изменяется, размер текста изменился (и вы знаете, сколько - это также срабатывает, кстати, если окно масштабируется в полностраничном режиме, и вы все равно получите правильный коэффициент масштабирования с той же высотой / соотношение высоты).
Вот собственный способ (основные фреймворки не могут масштабировать Chrome, потому что они не поддерживают пассивное поведение событий)
//For Google Chrome
document.addEventListener("mousewheel", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.deltaY > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.detail > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
Я отвечаю на 3-летнюю ссылку, но я думаю, что это более приемлемый ответ,
Создайте файл.css как,
@media screen and (max-width: 1000px)
{
// things you want to trigger when the screen is zoomed
}
НАПРИМЕР:-
@media screen and (max-width: 1000px)
{
.classname
{
font-size:10px;
}
}
Приведенный выше код делает размер шрифта "10 пикселей", когда экран увеличен примерно до 125%. Вы можете проверить другой уровень масштабирования, изменив значение "1000px".