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:
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 am currently running a script on a third-party page to determine the maximum dimensions of the page. At first, this may seem as if I could just use outerWidth() and outerHeight() on my parent wrapper, #base but the problem is that the page wrapper isn't sized from its children. So I might have a parent that is 0x0 and its child is 400x400 and a child inside of that which is 500x500. It seems they just allow overflow. I have tried some CSS tricks in attempt to force the parent #base to size itself correctly, but the children don't seem to drive this change and modifying their CSS causes actual alignment issues on the page. Additionally, there are many hidden items on the page that do not become visible until later or during page interaction so this further prevents me from just grabbing the outer dimensions of #base or something like that.
My current approach is to iterate through every single element on the page. I check to see where it is positioned and what its dimensions are. Based on those, I update my maximum dimensions. I also have to check for horizontal and vertical scrolling elements because those may be on the page too. If a wrapper is 500px wide and the child has a width of 1000px, but is scrolled, I wouldn't want that to affect my maximum dimensions. Anyways, this approach works but it's slow. Sometimes the page may have +15k elements. With these numbers, it takes 10 seconds on my machine. I might be able to optimize some of the conditional statements to use booleans instead of evaluating values, but I don't think this will make a significant difference. I'm hoping there is some process I'm completely overlooking. Below is my current code snippet and a demo showing how the page looks prior to running the code and after the code has been run.
Demo: https://p826ni.axshare.com/#g=1&p=without_code
$('#base *').not('script, style').each(function () {
currentElement = $(this);
// Initialize on first loop.
if (parentElementHorizontal === undefined && parentElementVertical === undefined) {
parentElementHorizontal = currentElement;
parentElementVertical = currentElement;
}
width = currentElement.outerWidth();
height = currentElement.outerHeight();
scrollWidthHidden = currentElement[0].scrollWidth;
scrollHeightHidden = currentElement[0].scrollHeight;
top = currentElement.offset().top;
left = currentElement.offset().left;
// Check if we're still within the parent containing horizontal-scrolling overflow.
if (!$.contains(parentElementHorizontal[0], currentElement[0])) {
hiddenWidth = false;
}
// Check if we're still within the parent containing vertical-scrolling overflow.
if (!$.contains(parentElementVertical[0], currentElement[0])) {
hiddenHeight = false;
}
// Check if we've found an element with horizontal-scrolling content.
if (!hiddenWidth) {
maxWidth = maxWidth < left + width ? left + width : maxWidth;
} else if (currentElement.width() > maxWidth) {
currentElement.addClass('redline-layer');
}
if (scrollWidthHidden > width && !hiddenWidth && width > 0) {
hiddenWidth = true;
parentElementHorizontal = currentElement;
}
// Check if we've found an element with vertical-scrolling content.
if (!hiddenHeight) {
maxHeight = maxHeight < top + height ? top + height : maxHeight;
} else if (currentElement.height() > maxHeight) {
currentElement.addClass('redline-layer');
}
if (scrollHeightHidden > height && !hiddenHeight && height > 0) {
hiddenHeight = true;
parentElementVertical = currentElement;
}
});
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>
I'm trying to optimise my website (http://www.mazion.co.uk).
As such, I tried to create critical CSS for the site using penthouse. (See Critical CSS used here - this was generated by the main developer of penthouse for me).
However, when using critical CSS, one of the subpages on my website does not load properly. BUT, when I fully inline the CSS (or don't do anything to optimise CSS), this sub-page loads correctly.
On this sub-page - http://www.mazion.co.uk/courses, there are a number of boxes that are resized using a JS function (see below) that is run on.ready and on.resize (i.e. when resizing the screen) which ensures that all boxes are of the same size.
When using critical CSS, the resizing function works on.resize but not on.ready. On the other hand, with inline CSS, the resizing function works as expected on.resize and on on.ready...
Thus, I was wondering if someone could help me in identifying the problem. I have tried to inline the styles for the boxes directly into the HTML, but I was unsuccessful...
You can see this problem by going to http://www.mazion.co.uk/courses/ and having a look at the boxes. If you then resize your browser, all the boxes will resize themselves so that they are all the same height... This resizing that make all the boxes the same height should actually happen automatically when the page loads....
Js Function (Not Extremely important to question, but helps in setting the scene)
jQuery(document).ready(function($){
$(window).resize(function() {
resizeCourseBoxes()
resizeTopBespokeCoursesBoxes()
resizeMidBespokeCoursesBoxes()
}).resize(); // Trigger resize handlers.
});
// Ensure that all the courses boxes are the same height (this ensures that the rows are of the same size...)
function resizeCourseBoxes() {
jQuery(function($) {
courseHeader = $('.course_header')
maxTextHeight = Math.max.apply(
Math, courseHeader.map(function() {
return $(this).height()
}).get())
for (var i = 0; i < courseHeader.length; i++) {
currentHeight = courseHeader[i].offsetHeight
new_padding = Number(maxTextHeight) - currentHeight + 10
courseHeader[i].style.marginBottom = new_padding + 'px'
};
})
}
// Ensure that all mid section (prices section) of the bespoke section is the same
function resizeTopBespokeCoursesBoxes() {
jQuery(function($) {
CoursePriceSection = $('.green_bx_top')
maxTextHeight = Math.max.apply(
Math, CoursePriceSection.map(function() {
return $(this).height()
}).get())
for (var i = 0; i < CoursePriceSection.length; i++) {
currentHeight = CoursePriceSection[i].offsetHeight
new_padding = Number(maxTextHeight) - currentHeight + 10
CoursePriceSection[i].style.marginBottom = new_padding + 'px'
};
})
}
// Ensure that all mid section (prices section) of the bespoke section is the same
function resizeMidBespokeCoursesBoxes() {
jQuery(function($) {
CoursePriceSection = $('.green_bx_mid')
maxTextHeight = Math.max.apply(
Math, CoursePriceSection.map(function() {
return $(this).height()
}).get())
for (var i = 0; i < CoursePriceSection.length; i++) {
currentHeight = CoursePriceSection[i].offsetHeight
new_padding = Number(maxTextHeight) - currentHeight
CoursePriceSection[i].style.marginBottom = new_padding + 'px'
};
})
}
The answer to my problem was simple:
Critical CSS is specific for each HTML page. Thus critical CSS for each individual page should be calculated separately...
(I was using the same critical CSS for all my subpages...).
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.