How to manipulate the screen width via js? - javascript

I'll try to explain my use case here. In my site I have a break point for desktop view, and break point for tablet view (which is more compact). I'm trying to add a function to allow seeing the tablet view when browsing from desktop, cause some members prefer the compact design in their desktop as well.
For doing that, I figured I would need to trick the '#media(max-width:X)' query. I'm looking for a JS code that can manipulate the screen width value, so when the browser calculates max-width, it would be against a value that I specified.
One thing to note, this is suppose to work on desktop browsers, so the meta viewport can't be used here.

One solution is to apply a specific class (e.g: .tablet) to the body.
<body class="tablet"></body>
In your CSS:
#media screen and (/* your query */) {
.tablet .my-class {
/* tablet specific stuff */
}
}
You could then remove the .tablet class and replace it with .desktop via JavaScript
var body = document.body;
var switchToDesktop = function() {
body.className = body.className.replace('tablet', 'desktop');
}
var switchToTablet = function() {
body.className = body.className.replace('desktop', 'tablet');
}
var toggleView = function() {
(body.className.indexOf("tablet") > -1) ?
switchToDesktop() :
switchToTablet();
}
If you are using SASS or LESS, you can nest the tablet-specific styles.
#media screen and (/* your query */) {
.tablet {
h1 {
/* tablet specific h1 */
}
.my-div {
color: red;
}
/* etc... */
}
}

Related

JavaScript if statement alternative syntax

I want to check the size of the screen and toggle a class depending on the size of the screen.
Html
<div id="item" class="test"></div>
Script
window.addEventListener("load", toggleClass);
window.addEventListener("resize", toggleClass);
function toggleClass() {
var w = window.innerWidth;
item = document.getElementById("item");
if ( w > 700 ) {
item.classList.remove("test");
}else {
if ( item.classList.contains("test")) {
}else {
item.classList.add("test");
}
}
}
You don't need to test for whether test is included in the classList first - you can just add it unconditionally. Also, avoid implicitly creating global variables - always declare a new variable name with var (or, preferably, const, or let):
function toggleClass() {
var w = window.innerWidth;
var item = document.getElementById("item");
if ( w > 700 ) {
item.classList.remove("test");
}else {
item.classList.add("test");
}
}
You can also use the Conditional (ternary) operator
function toggleClass() {
var item = document.getElementById("item");
(window.innerWidth > 700) ? item.classList.remove("test") : item.classList.add("test");
}
A different approach - rather than adding a class on the smaller size - use a media query to apply the styling that you want - obviously if you are using the class for a purpose other than styling - this approach may not work - but if all you are doing is styling an element based on the width of the screen - then a media query is your friend.
The benefit of this approach (if its purely styling changes you are doing) is that there is no js required - the browser will automatically use whatever styling the media query matches. This is better for performance because the re is no js to run.
#media screen and (max-width: 699px) {
p {
font-size: 14px
}
}
#media screen and (min-width: 700px) {
p {
font-size: 16px
}
}

How can I force a matching window.matchMedia to execute on page load?

I noticed a difference between css media query definition and the javascript window.matchMedia media query definition:
The css rules are apllied initially to a loaded page.
The rules defined in javascript are not executed after the page load, but only after a new condition is entered.
An example:
I have two different pages with equivalent media query definitions, the first one defined in css and the second one defined in javascript:
the css version (defined in a style element):
#media (min-width: 401px) and (max-width: 600px) { body {background-color: red; } }
#media (min-width: 601px) and (max-width: 800px) { body {background-color: blue; } }
the javascript version (defined either globally or in a function called after body onload):
window.matchMedia("(min-width: 401px) and (max-width: 600px)")
.addListener(function(e) {
if (e.matches) {
document.body.style.background = "red";
}
});
window.matchMedia("(min-width: 601px) and (max-width: 800px)")
.addListener(function(e) {
if (e.matches) {
document.body.style.background = "blue";
}
});
When I load a page and the window is 700 px wide
the css version page is blue
the javascript version is white and changes its state only after a new condition is met, i.e. the window is sized below 601 px.
How can I force a matching window.matchMedia to execute on page load?
To fire a matchMedia on load, you could do like this instead (with a somewhat cleaner code base).
Stack snippet
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
document.addEventListener("DOMContentLoaded", function(e) {
// medias (as an array to make it a little easier to manage)
var mqls = [
window.matchMedia("(max-width: 400px)"),
window.matchMedia("(min-width: 401px) and (max-width: 600px)"),
window.matchMedia("(min-width: 601px) and (max-width: 800px)"),
window.matchMedia("(min-width: 801px)")
]
// event listeners
for (var i=0; i<mqls.length; i++){
mqls[i].addListener(mqh)
}
// matches methods
function mqh(){
if (mqls[0].matches) {
console.log("CALLBACK (max-width: 400px)");
document.body.style.background = "green";
} else if (mqls[1].matches) {
console.log("CALLBACK (max-width: 600px)");
document.body.style.background = "red";
} else if (mqls[2].matches) {
console.log("CALLBACK (max-width: 800px)");
document.body.style.background = "blue";
} else if (mqls[3].matches) {
console.log("CALLBACK (min-width: 801px)");
document.body.style.background = "gray";
}
console.log("window.innerWidth: " + window.innerWidth);
}
// call once on load
mqh();
});
</script>
</head>
<body>
</body>
</html>
Org. src: http://www.javascriptkit.com/javatutors/matchmediamultiple.shtml
A callback function bound to window.matchMedia is not called on page load.
A solution to the problem would be:
to define a function in which the media queries are explicitly checked via if(window.matchMedia("...").matches){
to call that function on page load via <body onload
to call that function on resize via window.onresize
I was facing the same problem today, and I've used the following solution inspired by Nathan:
const gate = 800
function listener(
matches,
) {
document.getElementById('tag').innerHTML = matches ? 'wider' : 'narrower'
}
window.onload=() => {
const match = window.matchMedia(`(min-width: ${gate}px)`)
match.addListener(e => listener(e.matches))
listener(match.matches)
}
<h1>
This window is
<span id='tag'></span>
than 800px
</h1>
The core concept is to run your listener function once with MediaQueryList.matches passed as a parameter.
And if someone is trying to achieve this with a framework, do remember to register and trigger the listener during the component mount event.

How to get current css value defined by media query in javascript?

I am developing a site where I want to access a menu display property. If the menu is closed (display: none) then I want to open it, if it's open (display: block) then I want to close it.
I define the menu as closed in responsive media query (if width is higher then menu is always visible with !important in media query), the rest I control in Javascript:
var attach_menu_control = function() {
var $sidebar = document.querySelector('.sidebar')
var $sidebar_content = document.querySelector('.sidebar .content')
var $menu_opener = document.querySelector('.sidebar .menu-closed')
var hide_menu = function() {
console.log('Hide menu is run.')
$sidebar_content.style.display = 'none'
$menu_opener.style.display = 'block'
$sidebar.style.width = '40px'
}
var show_menu = function() {
console.log('Show menu is run.')
$sidebar_content.style.display = 'block'
$menu_opener.style.display = 'none'
$sidebar.style.width = '270px'
}
var click_handler = function(e){
console.log('Click handler is run.')
debugger
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
if ($sidebar_content.style.display == 'none') { // Here it is `""` instead of `none`
show_menu()
} else if (width <= 724) {
hide_menu()
}
}
var $main = document.querySelector('main')
$main.addEventListener('click', hide_menu)
$sidebar.addEventListener('click', click_handler)
var event = new Event('click');
$sidebar.dispatchEvent(event)
}
Problem is, the first time this is run - the $sidebar_content.style.display is an empty string "" even though if I check it is definitely display: none in media query:
#media only screen and (max-width: 724px) {
/* Force sideback to be in closed mode when new page is opened */
.sidebar {
width: 40px;
}
.sidebar .content {
display: none;
}
}
Where can I get the values defined by media queries in Javascript? I don't want to access the rules themselves, I just want to know what's the current set value..
The site is here: www.saulesinterjerai.lt
If I understand the original question correctly, then the desire is to be able to read the current CSS values once #media settings have been taken into account.
I believe that the following should suffice as it reads out the current rendered state of the element.
window.getComputedStyle($sidebar_content)
Important note - In modern browsers, there can be a delay between setting a style or class, and the re-flow of the page. It may therefore be necessary to set a timeout and read the computed value after a short pause. YMMV.

Links Are Showing Of Next Slide In A Slider. Why?

I am working on a slider and all things is working fine but the problem is that it is showing link on next slide in current slide. How to fix it? You can see live DEMO at http://jsfiddle.net/gwbqvqjs/
<script type='text/javascript'>
//<![CDATA[
/* general variables */
var galleryId = 'gallery'; /* change this to the ID of the gallery list */
var gallery; /* this will be the object reference to the list later on */
var galleryImages; /* array that will hold all child elements of the list */
var currentImage; /* keeps track of which image should currently be showing */
var previousImage;
var preInitTimer;
preInit();
/* functions */
function preInit() {
/* an inspired kludge that - in most cases - manages to initially hide the image gallery list
before even onload is triggered (at which point it's normally too late, and the whole list already
appeared to the user before being remolded) */
if ((document.getElementById)&&(gallery=document.getElementById(galleryId))) {
gallery.style.visibility = "hidden";
if (typeof preInitTimer != 'undefined') clearTimeout(preInitTimer); /* thanks to Steve Clay http://mrclay.org/ for this small Opera fix */
} else {
preInitTimer = setTimeout("preInit()",2);
}
}
function fader(imageNumber,opacity) {
/* helper function to deal specifically with images and the cross-browser differences in opacity handling */
var obj=galleryImages[imageNumber];
if (obj.style) {
if (obj.style.MozOpacity!=null) {
/* Mozilla's pre-CSS3 proprietary rule */
obj.style.MozOpacity = (opacity/100) - 0;
} else if (obj.style.opacity!=null) {
/* CSS3 compatible */
obj.style.opacity = (opacity/100) - 0;
} else if (obj.style.filter!=null) {
/* IE's proprietary filter */
obj.style.filter = "alpha(opacity="+opacity+")";
}
}
}
function fadeInit() {
if (document.getElementById) {
preInit(); /* shouldn't be necessary, but IE can sometimes get ahead of itself and trigger fadeInit first */
galleryImages = new Array;
var node = gallery.firstChild;
/* instead of using childNodes (which also gets empty nodes and messes up the script later)
we do it the old-fashioned way and loop through the first child and its siblings */
while (node) {
if (node.nodeType==1) {
galleryImages.push(node);
}
node = node.nextSibling;
}
for(i=0;i<galleryImages.length;i++) {
/* loop through all these child nodes and set up their styles */
galleryImages[i].style.position='absolute';
galleryImages[i].style.top=0;
galleryImages[i].style.zIndex=0;
/* set their opacity to transparent */
fader(i,0);
}
/* make the list visible again */
gallery.style.visibility = 'visible';
/* initialise a few parameters to get the cycle going */
currentImage=0;
previousImage=galleryImages.length-1;
opacity=100;
fader(currentImage,100);
/* start the whole crossfade process after a second's pause */
window.setTimeout("crossfade(100)", 1000);
}
}
function crossfade(opacity) {
if (opacity <= 100) {
/* current image not faded up fully yet...so increase its opacity */
fader(currentImage,opacity);
/* fader(previousImage,100-opacity); */
opacity += 5;
window.setTimeout("crossfade("+opacity+")", 10);
} else {
/* make the previous image - which is now covered by the current one fully - transparent */
fader(previousImage,0);
/* current image is now previous image, as we advance in the list of images */
previousImage=currentImage;
currentImage+=1;
if (currentImage>=galleryImages.length) {
/* start over from first image if we cycled through all images in the list */
currentImage=0;
}
/* make sure the current image is on top of the previous one */
galleryImages[previousImage].style.zIndex = 0;
galleryImages[currentImage].style.zIndex = 100;
/* and start the crossfade after a second's pause */
opacity=0;
window.setTimeout("crossfade("+opacity+")", 5000);
}
}
/* initialise fader by hiding image object first */
addEvent(window,'load',fadeInit)
/* 3rd party helper functions */
/* addEvent handler for IE and other browsers */
function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+, NS6 and Mozilla
// By Scott Andrew
{
if (elm.addEventListener){
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent){
var r = elm.attachEvent("on"+evType, fn);
return r;
}
}
//]]>
</script>
<style type="text/css">
#slider {max-height:700px;background: url("https://lh6.googleusercontent.com/-LLFEz-EyGbk/UyV9SbGPuhI/AAAAAAAAMgY/JNqf8X11dbk/s220/slider-loader.gif") #2e2e2e no-repeat 50% 50%;}
#gallery {padding:0;position:relative;margin:0 auto;max-width:1920px;}
#gallery li {list-style-type:none;width:100%;display:block;}
.gallery_img img {max-width:100%;}
.gallery_text {width:1000px;margin:0 auto;text-align:center;position:absolute;top:50%;left:50%;margin-left:-500px;margin-top:-110px;}
.gallery_text h2 {padding:0;line-height:70px;font-size:50px;font-weight:inherit;color:#fff;}
.gallery_text p {margin:20px 0;line-height:24px;font-size:20px;color:#ffee66;}
.gallery_text a {background:#77aa00;display:inline-block;padding:20px 70px;font-size:18px;font-weight:700;text-transform:uppercase;color:#fff;text-decoration:none;}
.gallery_text a:hover {background:#fff;color:#000;}
</style>
<div class='clear'/>
<div id='slider'>
<ul id='gallery'>
<li style='position:relative!important;'>
<div class='gallery_img'><img alt='Google' src='https://lh4.googleusercontent.com/-Nh50j1-Bqws/UyV9Pv_wd3I/AAAAAAAAMf8/nsYUnwm35Gs/s1920/slide_1.jpg' title='Google'/></div>
<div class='gallery_text'><h2>Google</h2><p>Google is an American multinational corporation specializing in Internet-related services and products. These include online advertising technologies, search, cloud computing, and software. Most of its profits are derived from AdWords.</p><a href='http://www.google.com'>Open Google</a></div>
</li>
<li>
<div class='gallery_img'><img alt='Bing' src='https://lh4.googleusercontent.com/-eGrPYj9dz1c/UyV9QgDIh5I/AAAAAAAAMgM/mlcDdyufQJs/s1920/slide_2.jpg' title='Bing'/></div>
<div class='gallery_text'><h2>Bing</h2><p>Bing is a search engine that brings together the best of search and people in your social networks to help you spend less time searching and more time doing.</p><a href='http://www.bing.com'>Open Bing</a></div>
</li>
<li>
<div class='gallery_img'><img alt='Yahoo' src='https://lh6.googleusercontent.com/-L_s8vxgupPY/UyV9RKToZeI/AAAAAAAAMgQ/TWs-wy7lbrk/s1920/slide_3.jpg' title='Yahoo'/></div>
<div class='gallery_text'><h2>Yahoo</h2><p>Yahoo! Inc. is an American multinational Internet corporation headquartered in Sunnyvale, California.</p><a href='http://www.yahoo.com'>Open Yahoo</a></div>
</li>
</ul>
</div>
<div class='clear'/>
When you will move your mouse at link then you will see that the link is showing of next slide. Here I am also adding the codes to view it here too.
See http://jsfiddle.net/gwbqvqjs/2/
Changing these lines:
galleryImages[previousImage].style.zIndex = 0;
galleryImages[currentImage].style.zIndex = 100;
to this:
galleryImages[previousImage].style.zIndex = 100;
galleryImages[(currentImage + 1) % galleryImages.length].style.zIndex = 0;
and changing other code to:
opacity=0;
window.setTimeout(function() {
galleryImages[previousImage].style.zIndex = 0;
galleryImages[previousImage].style.opacity = 0;
crossfade(opacity);
}, 5000);
fixes it. Your code is more complicated than it needs to be, swapping currentImage with previousImage previousImage=currentImage; etc. make it hard to see what's going on. Try to simplify it.
use this.. :) <a>position will change but link jumping perfectlly.
<a style="position:absolute; margin-left:-50%; top:318px;" href='http://www.google.com'>Open Google</a>
<a style="position:absolute; margin-left:-15%; top:318px;" href='http://www.bing.com'>Open Bing</a>
<a style="position:absolute; margin-left:24%; top:318px;" href='http://www.yahoo.com'>Open Yahoo</a>
Good Luck!

Mega menu conversion to mobile dropdown

I have applied a mega menu in one of my websites i.e. http://www.risenotes.com but when I try to convert it into a single and shortened menu for mobile view, it does not work. I succeeded initially for mobile view but only either of the two views work. Can anyone guide about any javascript code for displaying mega menu as regular mobile menu.
I tried using the below javascript but it succeeded me in my work on mobile version only while regular website version failed. Also, please that I have installed a mobile menu on http://www.risequotes.com which works perfect. That website is built in wordpress while my mega menu site is a php based website. Is there a way to apply my wordpress menu style to my php site? I mean some script.
I have tried below script which worked for conversion into mobile menu (including icons) but I need a bit more sophisticated version.
<script type="text/javascript">
function responsiveMobileMenu() {
$('.rmm').each(function() {
$(this).children('ul').addClass('rmm-main-list'); // mark main menu list
var $style = $(this).attr('data-menu-style'); // get menu style
if ( typeof $style == 'undefined' || $style == false )
{
$(this).addClass('graphite'); // set graphite style if style is not defined
}
else {
$(this).addClass($style);
}
/* width of menu list (non-toggled) */
var $width = 0;
$(this).find('ul li').each(function() {
$width += $(this).outerWidth();
});
// if modern browser
if ($.support.leadingWhitespace) {
$(this).css('max-width' , $width*1.05+'px');
}
//
else {
$(this).css('width' , $width*1.05+'px');
}
});
}
function getMobileMenu() {
/* build toggled dropdown menu list */
$('.rmm').each(function() {
var menutitle = $(this).attr("data-menu-title");
if ( menutitle == "" ) {
menutitle = "Menu";
}
else if ( menutitle == undefined ) {
menutitle = "Menu";
}
var $menulist = $(this).children('.rmm-main-list').html();
var $menucontrols ="<div class='rmm-toggled-controls'><div class='rmm-toggled-title'>" + menutitle + "</div><div class='rmm-button'><span> </span><span> </span><span> </span></div></div>";
$(this).prepend("<div class='rmm-toggled rmm-closed'>"+$menucontrols+"<ul>"+$menulist+"</ul></div>");
});
}
function adaptMenu() {
/* toggle menu on resize */
$('.rmm').each(function() {
var $width = $(this).css('max-width');
$width = $width.replace('px', '');
if ( $(this).parent().width() < $width*1.05 ) {
$(this).children('.rmm-main-list').hide(0);
$(this).children('.rmm-toggled').show(0);
}
else {
$(this).children('.rmm-main-list').show(0);
$(this).children('.rmm-toggled').hide(0);
}
});
}
$(function() {
responsiveMobileMenu();
getMobileMenu();
adaptMenu();
/* slide down mobile menu on click */
$('.rmm-toggled, .rmm-toggled .rmm-button').click(function(){
if ( $(this).is(".rmm-closed")) {
$(this).find('ul').stop().show(300);
$(this).removeClass("rmm-closed");
}
else {
$(this).find('ul').stop().hide(300);
$(this).addClass("rmm-closed");
}
});
});
/* hide mobile menu on resize */
$(window).resize(function() {
adaptMenu();
});
</script>
My current use of CSS hides the menu for mobile view and displays only parent Lists.
Instead of using JavaScript, can you use CSS media queries?
/* Mobile styling goes here */
#media screen and (min-width: 500px) {
/* Desktop styling overrides go here */
}
Here's an example (I'm not going to copy what you did, but you should get the gist of it) http://jsfiddle.net/1gw19yqg/

Categories