Can I change the media query using javascript / jQuery? - javascript

I have a style.css with a media query. In my javascript-file, I have a value for the desired mobile-width stored in a variable.
By changing the variable, I want to change the value of the media query automatically. Is it somehow possible to alter the contents of the .css-file with javascript like I can change the DOM?
Adding a HTML <style>-element to the DOM using javascript is not my desired solution, because I want to keep all css in the .css-file

The best option would be to have two sets of media queries which are only applied based on a parent class being present.
#media (max-width: 600px) {
.w600 .myDiv{
color:red;
}
}
#media (max-width: 400px) {
.w400 .myDiv{
color:red;
}
}
You could then add/remove w600 or w400 to the body class to allow the required media query to work.
Using jQuery this could be done like:
$("body").addClass("w600")
.removeClass("w400");
I appreciate you may have more than just one style and would therefore like to reduce code duplication.
In which case you could use a CSS transpiler such as Less with mixins:
#mediaqueryruleset:{
.myDiv{
color:red;
}
.myOtherDiv{
color:blue;
}
}
#media (max-width: 600px) {
.w600 {
#mediaqueryruleset();
}
}
#media (max-width: 400px) {
.w400 {
#mediaqueryruleset();
}
}
Which would output:
#media (max-width: 600px) {
.w600 .myDiv {
color: red;
}
.w600 .myOtherDiv {
color: blue;
}
}
#media (max-width: 400px) {
.w400 .myDiv {
color: red;
}
.w400 .myOtherDiv {
color: blue;
}
}

You can set the rule directly using .media.mediaText of document.styleSheets[0].cssRules
document.styleSheets[0].cssRules[0].media.mediaText = /* new media rule here */;
plnkr http://plnkr.co/edit/qzLO5J4KlWZLQnjMIy7i?p=preview

You can write by using $(window).width()
value=959;
if($(window).width() < value)
{
$(".classname").css("color","white");
}

You can use Enquire.js jQuery plugin.
It is a JavaScript library for dealing with media queries in JavaScript.
This is quick start code sample:
enquire.register("screen and (max-width:45em)", {
// OPTIONAL
// If supplied, triggered when a media query matches.
match : function() {},
// OPTIONAL
// If supplied, triggered when the media query transitions
// *from a matched state to an unmatched state*.
unmatch : function() {},
// OPTIONAL
// If supplied, triggered once, when the handler is registered.
setup : function() {},
// OPTIONAL, defaults to false
// If set to true, defers execution of the setup function
// until the first time the media query is matched
deferSetup : true,
// OPTIONAL
// If supplied, triggered when handler is unregistered.
// Place cleanup code here
destroy : function() {}
});

Yes. Maybe. Inspired by #guest271314 answer. This seems to allow the changing of the media query conditions via JavaScript.
document.styleSheets[0].cssRules[0].conditionText = "(min-width: 0px)";
Of course, check if the rule has media query applied:
var currentQuery = {index:0,rule:null,mediaText:null};
var inclusionQuery = "(min-width: 0px)";
var exclusionQuery = "(min-width: 99999px)";
var numberOfMediaQueries = 0;
function hideAllMediaQueries() {
var rules = document.styleSheets[0].cssRules;
var firstQueryIndex = 0; // show this query
var queryIndex = 0;
var numberOfRules = rules!=null ? rules.length : 0;
// loop through rules and hide media queries except selected
for (var i=0;i<numberOfRules;i++) {
var rule = rules[i];
if (rule.media!=null) {
if (queryIndex==firstQueryIndex) {
currentQuery.mediaText = rule.conditionText;
currentQuery.index = firstQueryIndex;
currentQuery.rule = rule;
rule.conditionText = inclusionQuery;
}
else {
rule.conditionText = exclusionQuery;
}
queryIndex++;
}
}
numberOfMediaQueries = queryIndex;
}
Note: The example above only applies to existing media queries in your CSS. It does not add or remove queries. It checks if media query exists by checking that the rule.media property is not null.

Related

JS match.Media with media query range

I am having an issue getting my site to respond to matchMedia query range using media.Match.
Updates based on comments: I need to use match.Media instead of CSS media queries because i need to check if a component is present and if true, i then need to add a class to another element if the browser size is between 1400 - 1800px. Also, i do need this to fire every time the browser is resized.
To troubleshoot, I have tried:
Using a single matchMedia('(min-width: 1400px) and (max-width: 1800px)')
Doing a single match (using only min-width: 1400px) and that succeeds. However, when I add in my 2nd variable 'mq.Max' and 'and statement', the whole thing fails.
I have read through MDN and still not seeing how to implement this.
JS below, thank you for any suggestions you may have.
if (jQuery('.jump-nav').length) {
// Create a condition that targets viewports at least 770px wide
window.onresize = function (event) {
console.log(event);
var mqMin = window.matchMedia('(min-width: 1400px)');
var mqMax = window.matchMedia('(max-width: 1800px)');
// check if media query matches#media (min-width: 30em) and (orientation: landscape)
if (mqMin.matches && mqMax.matches) {
console.log('Media Query Matched!')
// add css class for desktop
$('.rowComponent').addClass('jn-rowchange');
} else {
// remove css class if not desktop
$('.rowComponent').removeClass('jn-rowchange');
}
};
}
This is something that worked for me!
let mqMin = window.matchMedia("(min-width: 768px)");
let mqMax = window.matchMedia("(max-width: 960px)");
window.onresize = function () {
if (mqMin.matches && mqMax.matches) {
console.log("Inside Query parametara!");
} else {
console.log("Outside Query parametara!");
}
};

Issue changing javascript function based on media query with event handler

Sorry if this is a basic question. I mainly work with design and am not entirely comfortable with JavaScript.
I have a navigation menu which is prompted to display when clicking an SVG using an Event Listener. Based on the size of the screen on which the menu is being displayed I would like to change the function to a function stating a different height for the navigation on click. This way smaller devices will have a certain height navigation, and larger will have a different height as well.
Here is the code as far as I have dabbled into it
// media query event handler
if (matchMedia) {
const mq = window.matchMedia("(min-width: 500px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
// at least 500px
document.getElementById("onclick").addEventListener("click", menuSize);
function menuSize() {
document.getElementById("mobilemenu").style.height = "35%";
document.getElementById("mobilemenu").style.opacity = "1";
document.getElementById("movbilenav").style.opacity = "0";
}
} else {
// less than 500px
document.getElementById("onclick").addEventListener("click", menusizeL);
function menusizeL() {
document.getElementById("mobilemenu").style.height = "50%";
document.getElementById("mobilemenu").style.opacity = "1";
document.getElementById("movbilenav").style.opacity = "0";
}
}
}
As of now I get no response at all when clicking the navigation menu. Thank you, and sorry if this is a rudimentary question.
I think you should convert your solution to mainly use css. Generally, the more you can solve with css instead of js, the more the browser will take care of everything and keep everything smooth.
You can just add a media query in your stylesheets to handle the height differences. To hide/show your menu, I'd rely on just adding a class via your js. Sample stylesheet:
#mobilemenu {
height: 50%;
opacity: 0;
}
#mobilmenu.showing {
opacity: 1;
}
#media (min-width: 500px) {
#mobilemenu {
height: 35%;
}
}
Then you can just add your class via js:
document.getElementById('menuopener').addEventListener('click', function() {
document.getElementById('mobilemenu').classList.toggle('showing');
});

Is there a more efficient way of adding and removing these CSS classes with jQuery?

I have the below script that uses slidebars to show and hide a side menu.
I need to add and remove a CSS class to another div to tie things together. But looking at the way I am adding and removing classes I feel like there's a more efficient way?
function slidebarsStatus() {
var windowWidth = $(window).width();
breakpoint = 992;
if ( windowWidth > breakpoint ) {
controller.open( 'site-menu' );
$('.site-wrap').addClass('menu-active');
}
else {
controller.close( 'site-menu' );
$('.site-wrap').removeClass('menu-active');
$('.site-wrap').addClass('menu-inactive');
}
}
slidebarsStatus();
$(window).on( 'resize', slidebarsStatus );
Store the jQuery object as a variable:
var siteWrap = $('.site-wrap');
And chain your methods to the variable:
siteWrap.removeClass('menu-active').addClass('menu-inactive');
Or, if possible, media queries in your CSS:
#media screen and (max-width: 991px) {
.site-wrap {
/* active appearance */
}
}
#media screen and (min-width: 992px) {
.site-wrap {
/* inactive appearance */
}
}

Detect dynamic media queries with JavaScript without hardcoding the breakpoint widths in the script?

I've been searching for a lightweight, flexible, cross-browser solution for accessing CSS Media Queries in JavaScript, without the CSS breakpoints being repeated in the JavaScript code.
CSS-tricks posted a CSS3 animations-based solution, which seemed to nail it, however it recommends using Enquire.js instead.
Enquire.js seems to still require the Media Query sizes to be hardcoded in the script, e.g.
enquire.register("screen and (max-width:45em)", { // do stuff }
The Problem
All solutions so far for accessing Media Queries in Javascript seem to rely on the breakpoint being hardcoded in the script. How can a breakpoint be accessed in a way that allows it to be defined only in CSS, without relying on .on('resize')?
Attempted solution
I've made my own version that works in IE9+, using a hidden element that uses the :content property to add whatever I want when a Query fires (same starting point as ZeroSixThree's solution):
HTML
<body>
<p>Page content</p>
<span id="mobile-test"></span>
</body>
CSS
#mobile-test {
display:none;
content: 'mq-small';
}
#media screen only and (min-width: 25em) {
#mobile-test {
content: 'mq-medium';
}
}
#media screen only and (min-width: 40em) {
#mobile-test {
content: 'mq-large';
}
}
JavaScript using jQuery
// Allow resizing to be assessed only after a delay, to avoid constant firing on resize.
var resize;
window.onresize = function() {
clearTimeout(resize);
// Call 'onResize' function after a set delay
resize = setTimeout(detectMediaQuery, 100);
};
// Collect the value of the 'content' property as a string, stripping the quotation marks
function detectMediaQuery() {
return $('#mobile-test').css('content').replace(/"/g, '');
}
// Finally, use the function to detect the current media query, irrespective of it's breakpoint value
$(window).on('resize load', function() {
if (detectMediaQuery() === 'mq-small') {
// Do stuff for small screens etc
}
});
This way, the Media Query's breakpoint is handled entirely with CSS. No need to update the script if you change your breakpoints. How can this be done?
try this
const mq = window.matchMedia( "(min-width: 500px)" );
The matches property returns true or false depending on the query result, e.g.
if (mq.matches) {
// window width is at least 500px
} else {
// window width is less than 500px
}
You can also add an event listener which fires when a change is detected:
// media query event handler
if (matchMedia) {
const mq = window.matchMedia("(min-width: 500px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
// window width is at least 500px
} else {
// window width is less than 500px
}
}
See this post from expert David Walsh Device State Detection with CSS Media Queries and JavaScript:
CSS
.state-indicator {
position: absolute;
top: -999em;
left: -999em;
}
.state-indicator:before { content: 'desktop'; }
/* small desktop */
#media all and (max-width: 1200px) {
.state-indicator:before { content: 'small-desktop'; }
}
/* tablet */
#media all and (max-width: 1024px) {
.state-indicator:before { content: 'tablet'; }
}
/* mobile phone */
#media all and (max-width: 768px) {
.state-indicator:before { content: 'mobile'; }
}
JS
var state = window.getComputedStyle(
document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')
Also, this is a clever solution from the javascript guru Nicholas C. Zakas:
// Test a media query.
// Example: if (isMedia("screen and (max-width:800px)"){}
// Copyright 2011 Nicholas C. Zakas. All rights reserved.
// Licensed under BSD License.
var isMedia = (function () {
var div;
return function (query) {
//if the <div> doesn't exist, create it and make sure it's hidden
if (!div) {
div = document.createElement("div");
div.id = "ncz1";
div.style.cssText = "position:absolute;top:-1000px";
document.body.insertBefore(div, document.body.firstChild);
}
div.innerHTML = "_<style media=\"" + query + "\"> #ncz1 { width: 1px; }</style>";
div.removeChild(div.firstChild);
return div.offsetWidth == 1;
};
})();
I managed to get the breakpoint values by creating width rules for invisible elements.
HTML:
<div class="secret-media-breakpoints">
<span class="xs"></span>
<span class="tiny"></span>
<span class="sm"></span>
<span class="md"></span>
<span class="lg"></span>
<span class="xl"></span>
</div>
CSS:
$grid-breakpoints: (
xs: 0,
tiny: 366px,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
);
.secret-media-breakpoints {
display: none;
#each $break, $value in $grid-breakpoints {
.#{$break} {
width: $value;
}
}
}
JavaScript:
app.breakpoints = {};
$('.secret-media-breakpoints').children().each((index, item) => {
app.breakpoints[item.className] = $(item).css('width');
});
I found an hackish but easy solution :
#media (min-width: 800px) {
.myClass{
transition-property: customNS-myProp;
}
this css property is just a markup to be able to know in JS if the breaking point was reached. According to the specs, transition-property can contain anything and is supported by IE (see https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property and https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident).
Then just check in js if transition-property has the value. For instance with JQuery in TS :
const elements: JQuery= $( ".myClass" );
$.each( elements, function (index, element) {
const $element = $( element );
const transition = $element.css( "transition-property" );
if (transition == "custNS-myProp") {
// handling ...
}
});
Of course there is a word of warning in the wiki that the domain of css property identifiers is evolving but I guess if you prefix the value (for instance here with customNS), you can avoid clashes for good.
In the future, when IE supports them, use custom properties instead of transition-property
https://developer.mozilla.org/en-US/docs/Web/CSS/--*.

Trying to determine Device Type using CSS and Jquery not working as intended

I am trying to detect the clients device dimensions using a mixture between CSS and Javascript. [From this tutorial] I created an element that I appended to the body and assigned it a class that holds a value called "z-index" that determines the device type. However when running the following code I get "undefined" as the response.
How can I get a numeric value instead of undefined?
$(document).ready(function() {
var indicator = document.createElement('div');
indicator.className = 'state-indicator';
document.getElementsByTagName('body')[0].appendChild(indicator);
function getDeviceState() {
var index = parseInt(window.getComputedStyle(indicator).getPropertyValue('z-index'), 10);
var states = {
0: 'desktop',
1: 'small-desktop',
2: 'large-tablet',
3: 'medium-tablet',
4: 'phone'
};
return states[index];
}
console.log(getDeviceState());
});
/*default */
.state-indicator {
z-index: 0;
}
#media all and (max-width: 1200px) {
/* start of small desktop */
.state-indicator {
z-index: 1;
}
}
/* end of desktop styles */
#media screen and (max-width: 991px) {
/* start of large tablet styles */
.state-indicator {
z-index: 2;
}
}
#media screen and (max-width: 767px) {
/* start of medium tablet styles */
.state-indicator {
z-index: 3;
}
}
#media screen and (max-width: 479px) {
/* start of phone styles */
.state-indicator {
z-index: 4;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
z-index only works on positioned elements, if you check what the actual value is it is auto and states[parseInt('auto')] is undefined
Css adjustment that fixes immediate issue:
.state-indicator {
z-index: 0;
position:relative;
}
Since you are using jQuery here's a slightly simpler version that also removes the element once the needed value is obtained
$(function() {
function getDeviceState() {
var $indicator = $('<div>', {'class': 'state-indicator'});
$('body').append($indicator);
var index = $indicator.css('z-index');
// got the value, so remove the test element
$indicator.remove();
// technically js property names can not be numeric, and will get cast to string but not all browsers will
var states = {
'0': 'desktop',
'1': 'small-desktop',
'2': 'large-tablet',
'3': 'medium-tablet',
'4': 'phone'
};
return states[index];
}
console.log(getDeviceState());
});
DEMO
The problem is z-indexwhich is auto can not be parsed to a number. The resolution of this code is to find NaN property of states object and the right answer is undefined.
So, right question is why does window.getComputedStyle(indicator).getPropertyValue('z-index') returns auto and how to make it works.
The main problem is to find right media-query resolution from whithin JS.
There is a lot of good example how to combine JS and media query work. Try this one:
http://theme.co/blog/cubit-a-more-flexible-media-query/
http://thenewcode.com/948/Triggering-JavaScript-Actions-With-CSS-Media-Queries
You can improve this code with ideas inside links I gave you.

Categories

Resources