Можно ли с помощью JavaScript определить, когда пользователь изменяет масштаб страницы? Я просто хочу поймать событие «zoom» и ответить на него (аналогично событию window.onresize).
Спасибо.
Можно ли с помощью JavaScript определить, когда пользователь изменяет масштаб страницы? Я просто хочу поймать событие «zoom» и ответить на него (аналогично событию window.onresize).
Спасибо.
Ответы:
Там нет никакого способа, чтобы активно обнаружить, если есть зум. Я нашел хорошую запись здесь о том, как вы можете попытаться реализовать это.
Я нашел два способа определения уровня масштабирования. Один из способов обнаружения изменений уровня масштабирования основан на том факте, что процентные значения не увеличиваются. Процентное значение относится к ширине области просмотра и, следовательно, не зависит от масштаба страницы. Если вы вставите два элемента, один с позицией в процентах, а другой с одинаковой позицией в пикселях, они будут раздвигаться при увеличении страницы. Найдите соотношение между позициями обоих элементов, и вы получите уровень масштабирования. Смотрите тестовый пример. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3
Вы также можете сделать это с помощью инструментов, описанных выше. Проблема в том, что вы более или менее делаете обоснованные предположения о том, увеличена ли страница. Это будет работать лучше в некоторых браузерах, чем в других.
Невозможно определить, увеличена ли страница, если они загружают вашу страницу во время увеличения.
document.body.offsetWidth
Я использую этот кусок 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);
})();
Хорошие новости всенекоторые люди! Новые браузеры будут вызывать событие изменения размера окна при изменении масштаба.
Давайте определим px_ratio как показано ниже:
отношение px = отношение физического пикселя к CSS;
если какой-либо один масштабирует страницу, область просмотра пикселей (px отличается от пикселя) уменьшается и должна соответствовать экрану, поэтому соотношение (физический пиксель / CSS_px) должно увеличиваться.
но в окне Изменение размера размер экрана уменьшается так же, как и пиксели. поэтому соотношение сохранится.
но
изменение размера: вызвать событие 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;
}
}
Ключевым моментом является разница между CSS PX и Physical Pixel.
https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e
Это работает для меня:
var deviceXDPI = screen.deviceXDPI;
setInterval(function(){
if(screen.deviceXDPI != deviceXDPI){
deviceXDPI = screen.deviceXDPI;
... there was a resize ...
}
}, 500);
Это нужно только на IE8. Все остальные браузеры, естественно, генерируют событие изменения размера.
Есть встроенный плагин, yonran
который может сделать обнаружение. Вот его ранее отвеченный вопрос о StackOverflow. Это работает для большинства браузеров. Приложение так просто, как это:
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
: "");
}
Always enable zoom
кнопку в опции Доступность. Демо не будет реагировать на изменения.
Я хотел бы предложить улучшение предыдущего решения с отслеживанием изменений ширины окна. Вместо того чтобы хранить собственный массив прослушивателей событий, вы можете использовать существующую систему событий javascript, запускать собственное событие при изменении ширины и привязывать к нему обработчики событий.
$(window).bind('myZoomEvent', function() { ... });
function pollZoomFireEvent()
{
if ( ... width changed ... ) {
$(window).trigger('myZoomEvent');
}
}
Throttle / debounce может помочь в снижении скорости вызовов вашего обработчика.
Вы также можете получить события изменения размера текста и коэффициент масштабирования, введя элемент div, содержащий как минимум неразрывный пробел (возможно, скрытый), и регулярно проверяя его высоту. Если высота изменяется, размер текста изменился (и вы знаете, сколько - это также срабатывает, кстати, если окно масштабируется в режиме полной страницы, и вы все равно получите правильный коэффициент масштабирования с той же высотой / соотношение высоты).
<script>
var zoomv = function() {
if(topRightqs.style.width=='200px){
alert ("zoom");
}
};
zoomv();
</script>
В 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;
});
Хотя это 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, но оно мне помогло.
0.05
по крайней мере, без хорошего объяснения. ;-) Например, я знаю, что в Chrome, в частности, 10% - это наименьшее значение, которое браузер будет увеличивать в любом случае, но не ясно, что это верно для других браузеров. К вашему сведению, всегда проверяйте ваш код и будьте готовы защитить или улучшить его.
Вот чистое решение:
// 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);
});
Событие resize работает в современных браузерах, прикрепляя событие 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 всякий раз, когда вам нужно перерисовать.
Согласно MDN, «matchMedia» является правильным способом сделать это https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes
это немного привередливо, потому что каждый экземпляр может смотреть только один 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>
Я отвечаю на 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».
max-width
и коэффициентом масштабирования?