enhance javascript code for screen orientation - javascript

Having tried a load of different options found on SO, including jQuery mobile solutions (caused masses of conflicts with other jQuery) i found the following code would detect screen rotation and i could use it to add a class.
$(window).bind("resize", function(){
screenOrientation = ($(window).height() > $(window).width())? 90 : 0;
$('.centerBoxContentsSubCat').addClass('mobile_landscape');
});
However, I need to .removeClass when rotated the other way.
I tried duplicating the code, switching the positions of height and width, but this didn't work.
I tried changing the code to
$(window).bind("resize", function(){
if(screenOrientation = ($(window).height() > $(window).width())? 90 : 0){
$('.centerBoxContentsSubCat').addClass('mobile_landscape');
}else{
$('.centerBoxContentsSubCat').removeClass('mobile_landscape');
}
});
but that didn't work either.
I am actually using #media queries for css, but i need to force a change in a column count on screen rotate and all other attempts have failed to get even close.
Any suggestions on where I'm going wrong here?

There are two different ways you can handle this.
The first is with the event orientation change.
// Listen for orientation changes
window.addEventListener("orientationchange", function() {
// Announce the new orientation number
alert(window.orientation);
}, false);
The second is with matchMedia.
// Find matches
var mql = window.matchMedia("(orientation: portrait)");
// If there are matches, we're in portrait
if(mql.matches) {
// Portrait orientation
} else {
// Landscape orientation
}
// Add a media query change listener
mql.addListener(function(m) {
if(m.matches) {
// Changed to portrait
}
else {
// Changed to landscape
}
});
Source:
http://davidwalsh.name/orientation-change
If you need to support older browsers I recommend this library:
https://github.com/WickyNilliams/enquire.js/

You need to use the orientationchange event, not resize.

Related

Remove scroll function upon window resize/media query

I have a navigation menu set to display:none, which appears upon scroll and disappears once back at the top.
Is there a way to disable the scroll function once I reach a certain breakpoint (ex. max-width: 786px) and display the menu?
Javascript
$(window).on("scroll", function() {
if($(window).scrollTop()) {
$('nav').addClass('show');
}
else {
$('nav').removeClass('show');
}
})
CSS
.show {
display: block
}
You can solve this using either javascript or CSS, however I would personally go with the javascript one.
First up, for a javascript solution, the function you need is:
window.innerWidth
It will return the entire window width not including scroll bars. Read more about it here.
So, as Temani Afif suggested, you would write a test inside your scroll function to check for the desired window width like so:
$(window).on("scroll", function() {
if (window.innerWidth <= 786) return;
// Your other code here
})
For a purely CSS solution, you could override the effect of the 'show' class with a media query:
.show {
display: block
}
#media screen and (max-width: 786px) {
nav {
display: block !important
}
}
More on media queries here
You can activate/deactivate the scroll listener on browser resize. This way your scroll listener wont be called everytime user scrolls when browser width is more than 786px.
var scrollListenerActive = false;
var handleScrollListener = function() {
if( $(window).width() < 786 && !scrollListenerActive ) {
$(window).on("scroll", function() {
if($(window).scrollTop()) {
$('nav').addClass('show');
}
else {
$('nav').removeClass('show');
}
});
scrollListenerActive = true;
} else {
$(window).off("scroll");
scrollListenerActive = false;
}
}
$(document).ready(handleScrollListener); // attach the listener on page load
$(window).resize(handleScrollListener); // attach/remove listener on window resize
That's a good strategy above, however the event you want to listen for is simply 'resize', on the window object (some older browsers can do it on any dom element, but better to be consistent and current with the standard).
So something like:
window.addEventListener('resize',function(){
if(window.innerWidth >= 768){
document.body.style['overflow-x'] = 'hidden';
}
else{
document.body.style['overflow-x'] = 'auto';
}
});
You can trade 'auto' for 'scroll' if you want the scrollbar to always show when less than 768.
Similarly, you can switch out 'overflow' instead of 'overflow-x' if you want to affect both scrollbars.
Keep in mind that the event tends to fire for every width and height change as the window is resized, in case you have other logic that might have an issue with firing many times (thousands or more) as it is resized.
This also works on maximize/restore, as they trigger the resize event as well.
Here's MDN's doc on the resize event if needed:
https://developer.mozilla.org/en-US/docs/Web/Events/resize
This is vanilla javascript, so it should work whether you're using a lib like jquery or not.

On iOS Safari, window.scrollTo doesn't work after orientation change

In short:
In iOS Safari, window.scrollTo method doesn't do anything if called from orientationchange event handler. It seems like a certain amount of time (500-1000ms) must pass before you can modify scroll position after orientation change.
Is there a workaround to change scroll position immediately and avoid the problem when user can see old scroll position for a moment after orientation change?
Detailed problem description:
I need to implement the following feature for mobile browsers:
When the user switches to landscape mode, he should see fullscreen video. When he switches back to portrait, he should be returned to exact same place where he left off.
The second part is the problem. Both iOS and Android will keep scroll position if you switch orientation back and forth, but only if you dont scroll the screen and dont make any adjustments to DOM. So if you just switch from portrait to landscape and back, everything works as expected. If you switch from portrait to landscape, adjust scroll position even by 1 pixel or make any changes to DOM, you will return to a different scroll position.
So I'm trying to pragmatically restore scroll position once the user returns to portrait orientation. Here's the simplified code I use:
var scrollPosition;
var savedScrollPosition;
window.addEventListener('scroll', function() {
scrollPosition = window.scrollY;
});
window.addEventListener('orientationchange', function(event) {
if (Math.abs(window.orientation) === 90) {
// This line will correctly save last scroll position for portrait orientation
savedScrollPosition = scrollPosition;
} else {
// This line will correctly try to restore previously saved scroll position
window.scrollTo(0, savedScrollPosition);
}
});
This works on android, but on iOS it doesn't. The problem is, window.scrollTo just doesn't seem to do anything until the certain time after orientation change has passed.
So if I change
window.scrollTo(0, savedScrollPosition);
to
setTimeout(function() {
window.scrollTo(0, savedScrollPosition);
}, 1000);
it works on iOS, but the user can see wrong portion of the page for a few moments, which leads to a poor user experience.
I was hoping that somebody knows a way to change scroll position on iOS immediately after orientationchage event.
Thank you.
In the end, I was forced to go with the following code:
var scrollPosition;
var savedScrollPosition;
window.addEventListener('scroll', function() {
scrollPosition = window.scrollY;
});
window.addEventListener('orientationchange', function(event) {
if (Math.abs(window.orientation) === 90) {
savedScrollPosition = scrollPosition;
} else {
if (isIOS()) {
var retryScroll = setInterval(function () {
if (window.scrollX === 0 && window.scrollY == savedScrollPosition) {
clearInterval(retryScroll);
} else {
window.scrollTo(0, savedScrollPosition);
}
}, 10 );
} else {
window.scrollTo(0, savedScrollPosition);
}
}
});
The user will see a small visual glitch, but it's still the best solution.

orientation change VS jquery events

The website: http://negativgraffiti.hu/uj/
If you jumps from one page to another, every page has a different height, but they are all in one div, just they are not visible all the time.
I'm resizing the parent div everytime to the current page's height (not the full code, just a sample):
var magassag = jQuery("#post-5");
var egymagas = jQuery(".elsofo").height();
if (i == 1) {
magassag.animate({
height: egymagas
}, 100 );
}
it's working fine, but when i test it on tablet/mobile the height is ruins when i change the orientation, and i don't know why.
Use $(window).on('resize', fn) to detect window resizing.
$(window).on('resize', function() {
// re-animate the height for the current page
});
Although this works fine for tablet resizing, it will be very inefficient for desktop users who are resizing the window with their mouse. It is good to throttle the resize callback for that reason.
// Use `throttle` from any of the various throttle libraries available.
$(window).on('resize', throttle(function() {
// re-animate the height for the current page
}));

Jquery, Remove class when width screen is 1050px

This is the JS code i'm using:
$("document").ready(function($){
var nav = $('#menu2');
$(window).scroll(function () {
if ($(this).scrollTop() > 90) {
nav.addClass("f-nav");
} else {
nav.removeClass("f-nav");
}
});
But i can't seem to get this into my code.
function checkWidth(init){
/*If browser resized, check width again */
if ($(window).width() < 514) {
$('html').addClass('mobile');
}
else {
if (!init) {
$('html').removeClass('mobile');
}}}$(document).ready(function() {
checkWidth(true);
$(window).resize(function() {
checkWidth(false);
});
And what i want is that when .f-nav is added to #menu2, when the screen is <1050 the classshould be removed.
To change html to #menu2, just replace one with the other. jQuery is pretty simple in this respect
if ($(window).width() < 514) {
$('#menu2').addClass('f-nav');
} else {
$('#menu2').removeClass('f-nav');
}
JSFiddle
There are a few ways to do that:
Javascript only
See it in action: Fiddle
$(window).resize(function() {
if ($(window).width() < 1050) {
$selector.removeClass('my-class');
} else {
$selector.addClass('my-class');
}
}).resize(); // trigger resize event initially
And don't forget: You don't have to place $(window).resize inside $(document).ready.
Mixed Javascript & CSS
See it in action: Fiddle
This technique is explained here: http://www.senaeh.de/media-query-variablen-javascript-auslesen/
Basic principle: set a variable with a CSS pseudo element and get it with javascript.
This workaround is good if you have to use Javascript even if media queries are used, because you don't have to declare the breakpoint twice.
CSS
#media screen and (max-width: 1050px) {
body:after {
content: 'tablet';
display: none;
}
}
Javascript
var mode = window.getComputedStyle(document.body,':after').getPropertyValue('content');
Be aware: IE < 9 doesn't support getComputedStyle. You have to use a polyfill like this one.
this is best achieved with a media query
#media screen and (max-width:1050px){
.mobile{
/* will only apply on devices narrower than 1050px */
}
}
EDIT: also possible to use media queries with javascript in modern browsers
if (matchMedia) { // check if browser supports media queries from JavaScript
var mq = window.matchMedia("(max-width: 1050px)");
WidthChange(mq);
// every time width changes, check the media query
mq.addListener(function WidthChange(mq){
if(mq.matches){
//we are in a mobile size browser
$('#menu2').addClass('mobile');
$('#menu2').removeClass('f-nav');
} else{
// desktop browser
$('#menu2').addClass('f-nav');
$('#menu2').removeClass('mobile');
}
});
}
When you load a website on a screen bigger than your breakpoint, the script wont work, because you need to re-calculate the screen size(refresh the page in this case). You need to get the width of the screen on resize. Use resize() method, and inside it place your test condition, and assign the class to your element. Reference to help you: http://api.jquery.com/resize/
If you want to change the class of a div in JS, you can do something like that:
document.getElementById("#YourId").className = "YourNewClass"
It will just change your class attribute :-)
Like that, you can also check which class is used and do what you want to do with that.
Edit thanks to Olaf Dietsche: this must be a duplicated post, here can be your answer: jquery, add/remove class when window width changes

iPad canvas rotation

I created a canvas element and I'm using javascript to make it as big as possible in the viewport, while maintaining the aspect ratio.
When you rotate the iPad, the device first rotates the page and only after that launches the resize event.
The problem is, if you come from landscape (about 800px wide) to portrait (about 400px), a part of the body is not being displayed, because the resize didn't happen yet at that moment. After this, the resize event resizes the canvas to the correct size, but then a part of the canvas (& document) is still outside the viewport.
So basically the problem exists because the resize event only launches after the iPad already cut off a part of the body on both sides because the body is too wide.
I could fix this by setting a margin to the canvas to compensate, but it's a dirty solution... does anyone have a better suggestion?
This could also be considered a dirty solution, but in the past I have used a setTimeout to deal with this issue, and it seems to always be reliable.
window.onorientationchange = function() {
canvasResize();
}
function canvasResize() {
window.setTimeout(function () {
//Your code here based on new size
}, 100);
}
Or if you are looking for a slightly less dirty solution, you should be able to just keep track of the viewport width yourself, and then wait until that changes to do your updates. Add to your script somewhere:
var viewportWidth = window.innerWidth;
And change canvasResize:
function canvasResize() {
if(window.innerWidth != viewportWidth) {//Dimensions have changed for sure
viewportWidth = window.innerWidth; //Update viewportWidth for future use
//Your code here based on new size
}
else {
//Delay and try again
window.setTimeout(function () {
canvasResize();
}, 100);
}
}
Both of are pretty quick and dirty, and I'd be interested if there's a more elegant solution, but I haven't found one yet.

Categories

Resources