I have this function that moves a HTML element around the DOM based on whether the window size is less than 640px or more. I'm moving the image with prepend and append, but because the function fires every time the window is resized I think I'm asking for performance issues.
The code:
function moveDealsImage() {
var mobile_width = 640;
var wi = $(window).width();
if (wi < mobile_width) {
$( ".deals-header" ).prepend( $("div.htp") );
} else {
$( ".deals-header" ).append( $("div.htp") );
}
}
window.addEventListener("resize", moveDealsImage);
moveDealsImage();
I need to keep the listener in there.
Is there a way to do that, but then only prepending/appending the element once each time that the if or else statements become true? (instead of it happening on every pixel change)
There are a few things that you can do to optimize this.
A first option is to only execute your moveDealsImage function when the state changes from mobile to desktop or reverse. All the other resizes can just be ignored.
This can be accomplished by using something like following code:
var mobile_width = 640;
var is_mobile = (window.innerWidth <= mobile_width);
function moveDealsImage(e) {
// Only execute the function when then state changes from mobile to desktop or reverse
if(
! is_mobile && window.innerWidth > mobile_width ||
is_mobile && window.innerWidth <= mobile_width
)
return;
// Update state
is_mobile = (window.innerWidth <= mobile_width);
console.log('your code here');
}
window.addEventListener("resize", moveDealsImage);
moveDealsImage();
Another and better solution would be to use CSS media queries. This can be done with the following CSS and HTML.
.desktop-deals-header {
display: block;
}
.mobile-deals-header {
display: none;
}
#media only screen
and (max-width : 640px) {
.desktop-deals-header {
display: none;
}
.mobile-deals-header {
display: block
}
}
and in your HTML you add two headers, one for desktop and one for mobile.
<div class="mobile-deals-header">Mobile header</div>
<div class="desktop-deals-header">Desktop header</div>
Related
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
}
}
I would like to remove a click event listener on a certain screen size, while resizing browser.
The problem is that the code below works where I refresh the page and desired result is there. However, while resizing the browser, it stays in the state of either being clickable if under the wanted width or being non clickable over the wanted width.
let viewPort = window.innerWidth || document.documentElement.clientWidth;
let dropToggle = document.querySelectorAll(".someparent");
let dropMenu = document.querySelectorAll(".somechild");
for (let i = 0; i < dropToggle.length; i++) {
dropToggle[i].addEventListener('click', function a(event) {
if (viewPort < 786) {
dropMenu[i].classList.toggle("drop");
if (event.dropToggle == 2);
event.stopPropagation();
}
else {
dropToggle.removeEventListener('click', a);
/*update*/
dropMenu[i].classList.remove("drop");
}
/*update*/
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
}, true);
});
}
So basically, I would need the function to kick in when the browser is being resized without refreshing the page. Any help would be appreciated.
EDIT updated code with partial solution.
New problem: The toggle classList.toggle "drop" remains open if not closed on the smaller width. Adding a classList.remove to the "drop" within the else condition does not work either, this actually removes the function entirely on resize. Is there a way to reset the classList.toggle on resize?
You need to update the value of viewPort every time you resize your window. At the moment viewPort is initialized when you load your page but is never reinitialized again. To do this you can add a resize event listener to your window:
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
}, true);
You need to define your event listener call outside of your for loop
& pass the callback as a reference in add/remove event listener method.
Also you need to add window.resize event listener (As shown below)
This code should work fine for you
let dropToggle = document.querySelectorAll(".someparent");
let dropMenu = document.querySelectorAll(".somechild");
function a(event) {
dropMenu[i].classList.toggle("drop");
if (event.dropToggle == 2);
event.stopPropagation();
}
for (let i = 0; i < dropToggle.length; i++) {
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
if (viewPort < 786) {
dropToggle[i].addEventListener("click", a);
} else {
dropToggle[i].removeEventListener("click", a);
}
});
}
Matchmedia can handle this - and allow javascript functions when the media (window) matches the criteria.
References can be found here (https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) and here (https://www.sitepoint.com/javascript-media-queries/)
Effectively its media queries for javascript. And the syntax is essentially the same as for CSS media queries.
// media query event handler
if (matchMedia) {
const mq = window.matchMedia("(min-width: 768px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
// do what you want when window width is at least 768px
} else {
// do what you want when window width is less than 768px
}
}
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.
I'm having a trouble debugging a site that's not acting very responsively. I have media queries like so:
#media (min-width: 768px) and (max-width: 992px)
{
.radio-page {
height: 1470px;
}
}
#media (min-width: 993px) and (max-width: 1199px)
{
.radio-page {
height: 1525px;
}
}
(There are a few more breaks at larger screen dimensions but I don't think they are relevant)
I haven't specified a height for this class at dimensions less than 768, instead opting for the following javascript/jquery:
function confirmer() {
if ($(window).innerWidth() < 767) {
var inHeight = $('.iright-4 p').offset().top +
$('.iright-4 p').height() - $('.inner-radio').offset().top;
var outHeight = inHeight + $('.inner-radio').offset().top - 42;
$('.inner-radio').css('height', inHeight + 20);
$('.radio-page').css('height', outHeight + 50);
}
// debug code to report element height
console.log('radio-page is ' + $('.radio-page').css('height'));
}
$(document).ready(function() {
confirmer();
$(window).resize(confirmer);
});
All is well when it loads. The problem occurs specifically when the window is resized from below 767px into something higher. For some reason the media queries no longer change the height value of the .radio-page element, despite the javascript changed being isolated to < 767px. .radio-page stays at exactly whatever height it was when the resize passed the threshold.
Also, I have a suspicion that the confirmer function is being disabled altogether when the window is > 767px, because I'm losing console updates. All is well when I re re-size to < 767px (the jquery operates as intended).
Any help is most appreciated,
SOLUTION
function confirmer() {
if ($(window).innerWidth() < 767) {
...
} else {
$('.inner-radio').css('height', '');
$('.radio-page').css('height', '');
}
...
When the javascript code sets your elements to have a specific height at < 767px, it is changing the style attribute of those elements. When you resize to 767 px or above, your CSS is trying to take over for the javascript, but that style attribute defining the height is still there. One possible solution is to clear it in your code:
function confirmer() {
if ($(window).innerWidth() < 767) {
var inHeight = $('.iright-4 p').offset().top +
$('.iright-4 p').height() - $('.inner-radio').offset().top;
var outHeight = inHeight + $('.inner-radio').offset().top - 42;
$('.inner-radio').css('height', inHeight + 20);
$('.radio-page').css('height', outHeight + 50);
}else{
$('.inner-radio').css('height', '');
$('.radio-page').css('height', '');
}
// debug code to report element height
console.log('radio-page is ' + $('.radio-page').css('height'));
}
$(document).ready(function() {
confirmer();
$(window).resize(confirmer);
});
As per the jQuery docs on $.css():
Setting the value of a style property to an empty string — e.g. $(
"#mydiv" ).css( "color", "" ) — removes that property from an element
if it has already been directly applied, whether in the HTML style
attribute, through jQuery's .css() method, or through direct DOM
manipulation of the style property. It does not, however, remove a
style that has been applied with a CSS rule in a stylesheet or
element.
In regards to losing console updates, I cannot answer that part of the question. Perhaps you are getting updates, but because the height value is the same, your browser recognizes them as identical messages and collapses them into one? Check if there is a small number next to your message. Here's an example from Chrome:
I'm using the following two pieces of CSS and JS code:
#media (max-width: 720px) {
// a code to make arrows in a carousel disappear
}
if(jQuery(window).width() <= 720){
// a code to make arrows in the carousel stop working
}
The problem with them is that the latter executes on exactly width=738px and not 720px. I suspect that this is because of browser's vertical scrollbar that has width equal to 18px in Chrome.
Is there a way to unify this? I'd like these actions to happen at the same moment in all browsers regardless of the scrollbar's width.
Tests (when browser is # 720px and CSS has already executed):
jQuery(document).innerWidth() = 703
jQuery(window).innerWidth() = 703
jQuery(document).width() = 703
jQuery(window).width() = 703
jQuery('body').width() = 703
jQuery('html').width() = 703
I had to tackle the same problem a while ago, and so far the most correct solution I found is to use media queries to pass the actual window size to Javascript. You have to follow these steps:
Add a hidden element to your page,
Use media queries to alter the max-width property of that element,
Read back the max-width property of that element through Javascript.
For instance, add the following element to your page:
<div id="currentMedia"></div>
Then write the following CSS rules:
#currentMedia {
display: none;
}
#media (max-width: 720px) {
/* Make arrows in the carousel disappear... */
#currentMedia {
max-width: 720px;
}
}
Then, from the Javascript side, you can write:
if (parseInt(jQuery("#currentMedia").css("max-width"), 10) <= 720) {
// Make arrows in the carousel stop working...
}
And it will be accurate regardless of the scrollbar size, since the value comes from the same media query that triggers the carousel's disappearance.
I tested this solution on all major recent browsers, and it gives correct results.
You will find the big summary of what properties are supported on what browsers on this page on quirksmode.org.
Your best bet is probably to grab an element in the page (using document.body where supported, or document.getElementById or whatever), walk its offsetParent chain to find the topmost element, then examine that element's clientWidth and clientHeight.
innerWidth documentation
innerWidth() says this method is not applicable to window and document objects; for these, use .width()
try
How can I get the browser's scrollbar sizes?
From Alexandre Gomes Blog
function getScrollBarWidth () {
var inner = document.createElement('p');
inner.style.width = "100%";
inner.style.height = "200px";
var outer = document.createElement('div');
outer.style.position = "absolute";
outer.style.top = "0px";
outer.style.left = "0px";
outer.style.visibility = "hidden";
outer.style.width = "200px";
outer.style.height = "150px";
outer.style.overflow = "hidden";
outer.appendChild (inner);
document.body.appendChild (outer);
var w1 = inner.offsetWidth;
outer.style.overflow = 'scroll';
var w2 = inner.offsetWidth;
if (w1 == w2) w2 = outer.clientWidth;
document.body.removeChild (outer);
return (w1 - w2);
};
in your code
if(jQuery(window).width()-getScrollBarWidth(); <= 720){
// a code to make arrows in the carousel stop working
}
A bit outdated thread, but i've found this solution
function getWidth(){
return ((window.innerWidth > 0) ? window.innerWidth : screen.width);
}
If you are using Bootstrap > 3 then I will suggest you something.
Bootstrap ships with .container class in its Css and predefined. And its altering with #media queries.So my working code sample for this is below.
function detectWidth(){
var width = $('.container').eq(0).outerWidth() ;
console.log(width);
if(width<750){
// do something for XS element
}else if(width>=750 && width<970){
// do something for SM element
}else if(width>=970 && width<1170){
// do something for MD element
}else{
// do something for LG element
}
}
I realize this is an old thread, but I think it can still benefit from this answer.
var width = window.outerWidth;
This will give you the width of the window including scrollbars, which is what media queries use, I believe.