Browser Viewport detection with plain JavaScript - javascript

I am using plain JavaScript code to detect browser viewport and which is as follows:
function setLocation(url) {
if (window.location.href.indexOf(url) === -1)
window.location = url;
}
function reloadPage(width) {
if (width < 701) {
setLocation("layout700.php");
} else if (width < 900) {
setLocation("layout900.php");
} else {
setLocation("layout1200.php");
}
}
var done = false;
function ready() {
if(!done) {
done = true;
reloadPage(document.width);
}
}
if(window.addEventListener) {
window.addEventListener('DOMContentLoaded', ready, false);
window.addEventListener('load', ready, false);
} else if(window.attachEvent) {
window.attachEvent('onload', ready);
}
window.onresize = function() {
reloadPage(document.width);
};
My question is : How can I define width range in this?
What I mean is.... Is it correct if I use as
function reloadPage(width) {
if (width <= 701 && >= 480) {
setLocation("layout700.php");
} else if (width <= 900 && >= 701) {
setLocation("layout900.php");
} else {
setLocation("layout1200.php");
}
}
If this is not correct then what is the correct syntax? Kindly help.

function reloadPage(width) {
if( width >= 480 ) {
if (width <= 701 ) {
setLocation("layout700.php");
} else if ( width <= 900 ) {
setLocation("layout900.php");
} else {
setLocation("layout1200.php");
}
}
}
What is changed from your code ?
- After the logical operator " && " you did not mention the variable name, which is incorrect.
- You need not check for " width > 701 " in the second condition, because, if it was <= 701, the first condition would have been satisfied.
EDIT : Added a wrapper if() to check the page is greater than 480, since you don't have any layouts specific to that.

Start at the largest and move to the smallest. Also, because setLocation should immediate halt execution, you can optionally leave out the "else" stuff. Finally, I assume if width is less than 900, you should go to layout700, even if the width is less than 700? It seems like it would be the closest-fit for a very thin browser.
if (width>1200) {
setLocation("layout1200.php"); }
if (width>900) {
setLocation("layout900.php"); }
setLocation("layout700.php");

I'd be tempted to borrow this (http://adactio.com/journal/5429/) technique that Jeremy Keith has just blogged about and use the content attribute to store the correct page for the relevant dimensions - you could then use media queries to differentiate between the various sizes.
Something else you might want to consider... is using Device Atlas or
WUFRL to detect the end users browser and serve them out the correct layout to start - redirects are poor experience for end users and particularly slow over mobile.

Related

Javascript won't properly add class to HTML element

I've written scripts before that target HTML elements and add or remove classes based on conditions before, but this current script always adds mobile-class no matter what the display width of my window is. The console.log correctly outputs desktop at window widths above 992px, but the class doesn't correctly change. If I manually set the top statement to equal to desktop, then the classes update accordingly, so it seems that my displaySizeReader isn't correctly assigning a value to my displaySize variable. Where is the break in my logic here?
let displaySize = '';
function changeToMobile() {
document.querySelector('.custom-menu-class').classList.remove('desktop-class');
document.querySelector('.custom-menu-class').classList.add('mobile-class');
}
function changeToDesktop() {
document.querySelector('.custom-menu-class').classList.remove('mobile-class');
document.querySelector('.custom-menu-class').classList.add('desktop-class');
}
function displaySizeReader() {
if (screen.width < 992) {
let displaySize = 'mobile';
console.log(displaySize);
}
else {
let displaySize = 'desktop';
console.log(displaySize);
}
function displayChanger() {
if(displaySize == "mobile") {
changeToMobile();
} else if(displaySize == "desktop") {
changeToDesktop();
} else {
changeToMobile();
}
}
displayChanger();
}
displaySizeReader();
The screen object is not going to change unless you are using different displays. If you are trying to change these classes for a responsive type of scenario, the following should help you.
Make this change:
function displaySizeReader() {
if (window.innerWidth < 992) {
displaySize = 'mobile';
console.log(displaySize);
}
else {
displaySize = 'desktop';
console.log(displaySize);
}
function displayChanger() {
if(displaySize == "mobile") {
changeToMobile();
} else if(displaySize == "desktop") {
changeToDesktop();
} else {
changeToMobile();
}
}
displayChanger();
}
You have let in front of displaySize in your if/else statement, hence defining a new variables instead of using the one you declared in the first line.

JavaScript execute page resize and reload event simultaneously

I am trying to execute a window resize and page reload event simultaneously. When the screen size is less than 768 px, I am adding an attribute to an element. I also need that attribute added when the page is reload and a specific size as well, not just when its resized. The code I have below works, except when my screen size hs < 769 px, it takes a few seconds for the attribute to be added which affects how it looks. Any tips on how I can fix this?
window.onload = function(event) {
var element = document.querySelector('.filter-select');
if (window.innerWidth < 768) {
element.classList.add('testing');
element.removeAttribute("size", "4")
element.removeAttribute("multiple", "yes")
} else {
element.classList.remove('testing');
}
}
document.addEventListener("DOMContentLoaded", function(event) {
var element = document.querySelector('.filter-select');
function resize() {
if (window.innerWidth < 768) {
element.classList.add('testing');
element.removeAttribute("size", "4")
element.removeAttribute("multiple", "yes")
} else {
element.classList.remove('testing');
}
}
window.onresize = resize;
});
My only guess is that you doubled up the same process under different events and these events happen at different times thus the NOTICABLE lag.. if this doesn't solve.. this is an amazing question I already upvoted..
function resize() {
var element = document.querySelector('.filter-select')
if (window.innerWidth < 768) {
element.classList.add('testing')
element.removeAttribute("size", "4")
element.removeAttribute("multiple", "yes")
}
else {
element.classList.remove('testing');
}
}
window.onload=resize

Detect resize and execute code at X resolution in JQuery

I want the following:
Detect page width on load and add/remove class if it's below/above 959px
If I resize the page I want to do the same
$(window).on("resize load", function(e) {
e = $("body").width();
if (e <= 959) {
$("#button").addClass("active")
}
if (e >= 960) {
$("#button").removeClass("active")
}
})
This code works, but it removes the active class even if I resize the window from 500px to 501px. I want that to only add the class if I go above 960px or remove it if I go below 959px. How can I do that?
EDIT
Thanks for the answers! In the meantime I figured out a solution that works and suit my needs.
$(window).one("load", function () {
r = $("body").width();
if (r >= 960) {
$("body").attr("mobile","0")
//do something
}
if (r <= 959) {
$("body").attr("mobile","1")
//do something
}
});
$(window).on("resize", function() {
r = $("body").width();
if ($("body").attr("mobile") == "0") {
if (r <= 959) {
//do something
$("body").attr("mobile","1")
}
}
if ($("body").attr("mobile") == "1") {
if (r >= 960) {
//do something
$("body").attr("mobile","0")
}
}
})
Explanation:
It's a very specific solution since I modify the tabindex values in mobile view and I don't want to change these values back to 0 on a simple resize, only in the case I switch from mobile view to desktop.
The width of the window is different than the width of the body. Using $('body').width() will account for the overflow, whereas using $(window).width() will give you the actual screen width.
$(window).on('load resize', function() {
$('#button').toggleClass('active', $(this).width() <= 959)
});
However, using media queries is much more straight forward if in fact, you are just adding CSS properties.
#button {
opacity: 0.5;
}
#media (max-width: 959px) {
#button {
opacity: 1;
}
}
You could ouse window.matchMedia for this. If you look at the perf test, matchMedia is a lot faster than resize.
var mq = window.matchMedia("(min-width:959px)");
// onload
setButton(mql);
// add listener for the query
mq.addListener(setButton);
function setButton(mq) {
if (mql.matches) {
// do something with your setButton
} else {
// no match....
}
}
Here you go with a solution https://jsfiddle.net/hLkv1xan/1/
$(window).on("resize load", function(e) {
e = $("body").width();
if (e <= 959) {
$("#button").addClass("active")
} else {
$("#button").removeClass("active")
}
});
.active{
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">
Submit
</button>
I just modified your code a bit, change in the condition.
Hope this will help you.

React.js Scroll Threshold for Revealing Navigation

Using React.js, another dev wrote this code to toggle the appearance of a navigation element called ArticleNav. It reveals itself as your scrolling down but hides itself when you scroll back up.
onScroll: function () {
var mainColumn = document.getElementsByClassName('main-column')[0];
var firstTextElement = mainColumn.querySelector('.dek');
if (!firstTextElement) {
firstTextElement = mainColumn.querySelector('.body-text');
}
if (window.scrollY >= firstTextElement.offsetTop) {
if (!this.state.hideForArticleNav) {
this.setState({hideForArticleNav: true});
}
} else {
if (this.state.hideForArticleNav) {
this.setState({hideForArticleNav: false});
}
}
}
This works great but the use of if (window.scrollY >= firstTextElement.offsetTop) makes this jump back and forth too rapidly and I wanted to create a, let's say..., 50px threshold to confirm that the user is actually scrolling in the opposite direction.
Do y'all have any recommendations on how to approach this? I am more jQuery-minded than React, so all of my normal fixes don't exactly translate here.
I feel like I'm missing part of your question. Can't you simply add 50 px to the firstTextElement.offsetTop?
window.scrollY >= firstTextElement.offsetTop + 50
It sounds like you have a good setup to determine whether the user is scrolling up or down, so instead of setting this.state.hideForArticleNav you could set this.state.lastDirectionChangeOffset to the current window offset when the direction changes. Then you can check against that state value to see if it's +/- 50px.
onScroll: function () {
var mainColumn = document.getElementsByClassName('main-column')[0];
var firstTextElement = mainColumn.querySelector('.dek');
if (!firstTextElement) {
firstTextElement = mainColumn.querySelector('.body-text');
}
if (window.scrollY >= firstTextElement.offsetTop) {
if (!this.state.hideForArticleNav) {
this.setState({ lastDirectionChangeOffset: window.scrollY });
}
} else {
if (this.state.hideForArticleNav) {
this.setState({ lastDirectionChangeOffset: window.scrollY });
}
}
if (window.scrollY > this.state.lastDirectionChangeOffset + 50) {
this.setState({ hideForArticleNav: true })
} else if (window.scrollY < this.state.lastDirectionChangeOffset - 50) {
this.setState({ hideForArticleNav: false })
}
}

window onresize perform actions on breakpoints in Jquery

What I would like to do is create window breakpoints, like 300, 400, 500
and perform a certain action when the window reaches a certain breakpoint, ideally could be something like:
300: function(){...}
400: function(){...}
500: function(){...}
and the following code is how I tried to fire only 1 time a certain function associated to a certain breakpoint, but actually I'm stuck because I don't know how to pass them dynamically inside a single little function, and because all breakpoints in my code look pretty the same and they are useless repeated...
breakpoints = [300, 400, 500];
function screenBreakpoints(){
var regex = / ?breakpoint[0-9] ?/;
if( $(window).width() < breakpoints[0] ){
if( !$('html').hasClass('breakpoint0') ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass('breakpoint0');
console.log('breakpoint0');
$('li.MOVING').insertBefore('ul li.one'); // breakpoint function (fires only one time)
}
}
else if( $(window).width() > breakpoints[0] && $(window).width() < breakpoints[1] ){
if( !$('html').hasClass('breakpoint1') ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass('breakpoint1');
console.log('breakpoint1');
$('li.MOVING').insertBefore('ul li.two'); // breakpoint function (fires only one time)
}
}
else if( $(window).width() > breakpoints[1] && $(window).width() < breakpoints[2] ){
if( !$('html').hasClass('breakpoint2') ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass('breakpoint2');
console.log('breakpoint2');
$('li.MOVING').insertBefore('ul li.three'); // breakpoint function (fires only one time)
}
}
else if( $(window).width() > breakpoints[1] ){
if( !$('html').hasClass('breakpoint3') ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass('breakpoint3');
console.log('breakpoint3');
$('li.MOVING').insertBefore('ul li.four'); // breakpoint function (fires only one time)
}
}
}
$(window).resize(function(){
screenBreakpoints();
});
FIDDLE
First you get the window width using jquery's width() function.
Then declare three variables accordingly for the three sizes and write your functions inside that variable according to the condition
Keep the other two variables empty based on the width size and call the screenBreakpoints
NOTE: As #flowtron said in the comments, you can use <= or >= in the if condition based on your requirements
$(window).resize(function(){
var viewportWidth = $(window).width();
if(viewportWidth == 300){ // Use <= or >= based on ur requirements
var function300= function300(){};
var function400 ='';
var function500='';
screenBreakpoints(function300,function400,function500);
}
else if(viewportWidth == 400){ // Use <= or >= based on ur requirements
var function400= function400(){};
var function300 ='';
var function500='';
screenBreakpoints(function300,function400,function500);
}
else if(viewportWidth == 500){ // Use <= or >= based on ur requirements
var function500= function500(){
var function300 ='';
var function400='';
};
screenBreakpoints(function300,function400,function500);
}
});
Then in your screenBreakpoints function check which parameter is empty
For Ex:
function screenBreakpoints(function300,function400,function500){
if( $(window).width() < breakpoints[0] ){
if(function300 != null && function300 != undefined){
if( !$('html').hasClass('breakpoint0') ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass('breakpoint0');
console.log('breakpoint0');
$('li.MOVING').insertBefore('ul li.one'); // breakpoint function (fires only one time)
}
}
}
}
In my work I've come to use a set of DIVs (usually invisible, not via display: none though!) that have an ID of "ThisIsMediaQuery_Alpha", .. Beta, Gamma .. however you name them and as many as you need - then each breakpoint you're interested in just has to modify one of these from the default settings all got initially - I usually use a background-color (legacy from when they were created to FIX a MediaQuery-usage and were visible), but anything you like can work really. Then just call whichMediaQueryIsThis() on $(window).resize(), which iterates over the DIVs and finds out which one has the "marker value" (e.g. cur.style.backgroundColor=="red"). Then just use a case to switch out the appropriate values when calling your manageMediaQuerySwitch(arg0,arg1,arg2) function. HTH
The upside of this is, it also works with MediaQueries that aren't pixel-oriented! ;-)
Here is a complete edit that is done to the js file from the jsfiddle
the you provided. Just copy paste this over there or, just run this jsfiddle. I found it working. What I'm doing is, I'm just making a single function and calling it with different parameters.
Here is your modified js
breakpoints = [300, 400, 500];
function screenBreakpoints(breakpoint,listName){
var regex = / ?breakpoint[0-9] ?/;
if( !$('html').hasClass(breakpoint) ){
$('html')[0].className = $('html')[0].className.replace(regex, '');
$('html').addClass(breakpoint);
console.log(breakpoint);
$('li.MOVING').insertBefore(listName); // breakpoint function (fires only one time)
}
}
$(window).resize(function(){
if( $(window).width() < breakpoints[0] ){
screenBreakpoints("breakpoint0","ul li.one");
}
else if( $(window).width() < breakpoints[1] ){
screenBreakpoints("breakpoint1","ul li.two");
}
else if( $(window).width() < breakpoints[2] ){
screenBreakpoints("breakpoint2","ul li.three");
}
else{
screenBreakpoints("breakpoint3","ul li.four");
}
});

Categories