I want to allow the user to zoom when he clicked on an image and I don't want to allow him to zoom if there is no image.
// image function
viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes');
// no image function
viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
The problem:
If the user can zoom he can't go back to NORMAL disabled zoom because the no image function disables the zoom BUT the zoomfactor is not going back to the normal viewport.
So after the no image function it is possible to zoom but there is a zoom-factor already :/
Do you have any idea how to zoom back to the normal viewport in the no image function?
Thanks!
Don't change the viewport. There is a better way to achieve the same thing -> http://lab.hakim.se/zoom-js/
I'm sure that if you play with the viewport like that you will have problems in most of the mobile devices.
Related
I've built my app using reactand styled-components. It's all client-side rendered and routed.
All my responsive layout is based on the window.innerWidth value and I do lots of:
const MyComponent_DIV = styled.div`
width: ${props => props.isMobile ? "200px" : "400px"};
`;
const [windowWidth,setWindowWidth] = useState(window.innerWidth);
... some code
return (
<MyComponent_DIV
isMobile={windowWidth <= 768}
/>
);
NOTE: I also attach a resize event listener, so my app is responsive to resize events. So far so good.
function handleResize() {
console.log("FROM RESIZE: " + window.innerWidth); // I CAN SEE THIS VALUE CHANGING WHEN ZOOMING IN AND OUT
setWindowWidth(window.innerWidth);
}
But the weird thing, at least to me, is when I found out that changing the browser ZOOM level (on desktop and mobile) affects the window.innerWidth value. And it also fires the resize event.
What I'm trying to accomplish:
Be responsive to resize events, but not to "ZOOM events"
When user changes the zoom level, I want my layout to remain the same and show scroll bar when zoomed in.
Basically I want the zoom to work normally like a zoom and not trigger a re-render on my app.
EXTRA:
This is my meta viewport tag:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, shrink-to-fit=no">
QUESTION
Does it make sense for the zoom event to change the window.innerWidth property? I mean, isn't that completely counter intuitive?
How can I avoid it, or at least, do some workaround for my app to behave the way I need?
I'm no expert in javascript/jquery and have searched and searched to find an answer to my situation. Some answers have been close but I'm not sure how to translate it to my own situation.
I have a form on my website which conveniently zooms in on mobile devices for the user to input their data. After they hit 'submit' the screen zoom remains the same and the post-submit message is not seen since it's out of the viewport.
Is there a way to reset the screen zoom after form submission?
I've found the metatag 'viewport' and can change that so that the zoom function doesn't trigger at all
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
but I'd still like the zoom function to be there...
You can update viewport on form submit, like:-
element.on('submit', function(event) {
var viewportmeta = document.querySelector('meta[name="viewport"]');
if (viewportmeta) {
viewportmeta.setAttribute('content', 'width=device-width, maximum-scale=1.0, initial-scale=1.0');
}
}
Try this.
Is there a way to center a element on the viewport of a mobile browser?
This means that when users pinch to zoom, they should still see the element ( let's say a div styled as a window ) on the center of their viewport.
I can't find a straight way with HTML\CSS.
You can use JavaScript to detect page zooming and then calculate absolute sizes relative to original sizes and zoom factor.
Take a look at this:
How to detect page zoom level in all modern browsers?
There is a very good and universal way.
You can try to position the div fixed, and centering it with a combination of margin and top / left:
.center {
position:fixed;
z-index:999;
width:200px;
height:200px;
background:#4679BD;
top:50%;
margin-left:-100px;
margin-top:-100px;
left:50%;
}
JSFiddle: http://jsfiddle.net/HGtQA/
It turns out that pinching to zoom triggers a window scroll event in ios browsers on my ipad mini, and on my android 4.something device.
$(window).on("resize scroll", function () {
clearTimeout(pinchToZoomCheckTimer);
pinchToZoomCheckTimer = setTimeout( function () {
var width = window.innerWidth || document.documentElement.clientWidth;
var height = window.innerHeight || document.documentElement.clientHeight;
dlgInner.width(width);
dlgInner.height(height);
dlgInner.css("top",window.pageYOffset+"px");
dlgInner.css("left",window.pageXOffset+"px");
}, 50);
});
This centers a div on the exact location used by the viewport. Since it is transparent, it "kinda" takes up the whole viewport. I've read that some browser report a few more pixels for the window.innerWidth, but I can live with a ~20px displacement.
http://jsfiddle.net/agilius/yFajk/show works while pinching to zoom, and scrolling after being zoomed in on my ipad mini and android nexus.
What do you mean by "they should still see the element" ? If a user zoom he will see only a part of an image. But if you want you can disable zoom with this meta :
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
I've encountered similar problems before and could never really understand the workarounds, and so I ended up relying on plugins like iScroll. This is such simple task that I refuse to include a plugin for it - what I want is to prevent horizontal scroll in iOS. This includes the rubber band effect for any content that might be on the page but that isn't visible.
From what I understand I need to disable the rubber band altogether first and then apply the touch scroll to a container element (which I've given the id "touch"). Not sure if this is the right approach?
$(document).bind('touchmove', function(e) {
if (!e.target == '#touch') {
e.preventDefault();
}
});
Style for #touch
-webkit-overflow-scrolling: touch;
overflow: hidden;
height: 100%;
#media only screen and (max-width: 768px) {
width: 768px;
}
This doesn't prevent the horizontal width from staying at 728px however, the user is still able to scroll and see the hidden content. Ideas?
Well, the above metas are useful as such:
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
They prevent that bug in Safari that happens when the user rotates the screen. However, the most proper way to accomplish the desired functionality is:
Use a parent div with overflow hidden and make sure the height of this div is limited according to the viewport and a child div with overflow:auto or the css 3 overflow-y:scroll. So basically if the size of the content inside the child div exceeds the default size of the child, you can vertically/horizontally scroll through it. Because the parent has overflow:hidden, the content outside of the child will not be displayed, so you get a proper scroll effect. ** Also, if you use overflow: hidden and prevent default for all touchEvents, there will be no scrolling or weird browser behavior**
With the help of JavaScript, make sure that every element in the DOM is scaled according to the viewport, so avoid using static sizes for as many elements as possible.
Bind the touchStart, touchMove and touchEnd events. Safari doesn't always fire a touchEnd event unless a touchMove event is listened for as well. Even if it's just a placeholder, put it there to avoid the inconsistent behavior in Safari.
Horizontal sliding is possible in two ways: load new content in the same div after you detect the slide direction or populate that child div with all the elements and you are good to go and actually shifting the margins/position of the child inside it's parent to 'scroll'. Animation can be used for a slicker interface.
Bind your touch event listeners. I don't know what library or event management system you are using, but it doesn't matter. Just call the respective function for the respective task.
Get the slide direction(left/right):
var slideBeginX;
function touchStart(event){event.preventDefault();//always prevent default Safari actions
slideBeginX = event.targetTouches[0].pageX;
};
function touchMove(event) {
event.preventDefault();
// whatever you want to add here
};
function touchEnd(event) {
event.preventDefault();
var slideEndX = event.changedTouches[0].pageX;
// Now add a minimum slide distance so that the links on the page are still clickable
if (Math.abs(slideEndX - slideBeginX) > 200) {
if (slideEndX - slideBeginX > 0) {
// It means the user has scrolled from left to right
} else {
// It means the user has scrolled from right to left.
};
};
};
This work for me on Android, iPhone and iPad.
<!doctype html>
<html>
<head>
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
<title>Main</title>
</head>
<body>
...
</body>
</html>
Following link might be useful to you, here vertical is disabled and horizontal enabled, you just need to tweak the code a little for your purpose.
jquery-tools-touch-horizontal-only-disable-vertical-touch
In case you aren't concerned about vertical sliding, you can try the following code also -
document.ontouchmove = function(e){
e.preventDefault();
}
Hope it helps.
If you dont use the meta you will always get a rubber band effect.
<meta name="viewport" content="width=device-width" />
Even if the page fitted exactly the user would still be able to stretch the page wider than it should be able to go, you must use the view port to prevent this, there is no other way...
I am trying to implement a mobile website with the following appearance:
a fixed header
scrollable, zoomable content
content zoomed out when page is first loaded
I have been experimenting with IScroll 4 and the results seem good but there is one problem that I can't find a way around. The contents of my pages are user-generated html tables which are often wider than the screen. I would like the full width of the table to be visible when the user lands on the page. They can then zoom in if they want to.
If you look at the IScroll zoom demo in a mobile browser it demonstrates the problem. The page content is wider than the screen and it's not possible to zoom out, only zoom in.
Changing the initial-scale in the viewport meta tag doesn't help as the whole page, including the header, gets zoomed out:
<meta name="viewport" content="width=device-width, initial-scale=0.5, user-scalable=yes, minimum-scale=0.5, maximum-scale=1.0">
(the header will eventually be a JQueryMobile element which I don't want to mess with).
And modifying the zoomMin setting in iscroll.js (v4.2.2, line 119) from 1 to something smaller (e.g. 0.5) breaks things:
// Zoom
zoom: false,
zoomMin: 1,
zoomMax: 4,
You can zoom out further but the content then gets stuck and you can't resize it without reloading the page.
Does anyone know a way around this? I'm happy to try other frameworks if necessary.
To allow zooming out, you can use the zoomMin and zoomMax that you identified, but do it when you instantiate iscroll, rather than modifying iscroll.js:
<script type="text/javascript">
var myScroll;
function loaded() {
myScroll = new iScroll('wrapper',
{ zoom:true, onBeforeScrollStart: null,
zoomMin:0.5, zoomMax: 6 });
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', loaded, false);
</script>
I also found I needed to explicitly set the width of the 'scroller' div, like so:
$('#scroller').width(your_width);