Replace watching window.resize with a CSS media query? - javascript

I need to call a function when a window is resized below the 400px breakpoint. The obvious solution to handle this would be to watch the window.resize() event like this:
Window.Resize Solution
script:
$(window).resize(function(){
if($(window).width() < 400)
console.log("trigger");
});
Window.resize Fiddle
However this triggers continuously as the resize happens, this can result in hundreds of calls on this function, and will trigger at unncessary times like resizing from 300px to 200px;
While trying to find a way to avoid this I came up with a solution using CSS media queries:
CSS Media Query Solution
script:
$(".foo").on('transitionend', function () {
console.log("trigger")
});
css:
.foo
{
width: 0;
height: 0;
color: white;
transition: 0.1s;
}
#media screen and (max-width: 400px) {
.foo {
color: gray;
}
}
CSS Media Query Fiddle
The idea here is that the CSS watches for the window to resize to 400px then applies an arbitrary transition to an invisible element. Once done, the transitionend event is fired and the listener calls on my function. This only happens once when the screen goes below 400px and once when it goes back above.
Now of course there are pitfalls to this solution:
IE8/IE9 don't support transitionend
You must create an unnecessary element for each resize event you want to watch
The code is inherently more confusing as it is a "hacky" technique.
But other than those downfalls I was wondering if this method would be more efficient/better use if you want to avoid the continuous calls. Or is the underlying implementation of media queries doing more work than the resize event would anyway.

I think your main complication is splitting the code over so many places. Yes, CSS is nice and all, but now your code is reliant on two places! The easiest way to sort this is to simply store your value in JS:
var isSmall = false;
$(window).resize(function(){
if(
(window.innerWidth < 400 && !isSmall) ||
(window.innerWidth > 400 && isSmall)
){
console.log('we have passed the treshold!');
isSmall = !isSmall;
}
}).resize();
I guess using the CSS transitionend would work, but it seems so cumbersome to keep in sync.

Related

Differentiate between vertical and horizontal image format jQuery

I want to differentiate if an image is vertical or horizontal format and add a special class. I'm use this to fill my div fully with my image.
My HTML:
<a href="images/gallerie/image-1.jpg" data-lightbox="image-1" class="impression">
<img src="images/gallerie/image-1.jpg">
</a>
My CSS:
.wide {
height: 100%;
width: auto;
}
.tall {
height: auto;
width: 100%;
}
My JS (jQuery):
$('.impression').find('img').each(function() {
if($(this).width() / $(this).height() > 1) {
$(this).addClass('wide');
}
else {
$(this).addClass('tall');
}
});
It works only sometimes, and I don't know why.
On my iPhone it works never (Chrome).
Has anybody an other solution or maybe the reason why it works sometimes?
Thanks!
You need to use a load event handler so image is loaded before you can check dimensions
$('.impression').find('img').on('load',(function() {
// image is loaded now
if($(this).width() / $(this).height() > 1) {
$(this).addClass('wide');
}
else {
$(this).addClass('tall');
}
});
The each is not needed as jQuery will use each internally and this will be image instance
Most probably, you are running the function too soon and your images have not been loaded yet. In order to make sure, you can always console.log() the values of .width() and .height().
The best way to make sure the image has loaded when you check its dimensions is to use the load event.
$('img').on('load', function(){
// do your thing...
})
The rest is wrong, as pointed out by #charlietfl. The load event for img's does not propagate.
Better yet, instead of binding a listener to each img, just bind one on body for all your images, including the ones you will load later on, using some fancy async method:
$('body').on('load', 'img', function(){
// do your thing...
})
This second version will run every time an <img> will load in your DOM, not only when you run the script.

How does the CSS mediaQuery works

I need to know how the CSS media query works.
I mean, if I use #media(min-width: 768px), does this function called every time the window is resized ?
Because I am wondering if I can use a Javascript $(window).bind('resize orientationchange') or if it is more resource intensive.
It is for add or remove a class to a div, an exemple :
http://jsfiddle.net/xbh28o08/
My goal is to enter in the HTML a data attribut which determine when the navbar has to collapse (data-breakpoint"768" for example). And I would get this breakpoint for make a responsive navbar automatically, without change any CSS. My idea was to do it with Javascript but it seems really not a good idea according to your answers
var widthScreen = $(window).width();
if (widthScreen > 768)
$('nav').addClass('large');
else
$('nav').addClass('small');
$(window).bind('resize orientationchange', function() {
widthScreen = $(window).width();
if (widthScreen > 768){
$('nav').addClass('large');
$('nav').removeClass('small');
}
else{
$('nav').removeClass('large');
$('nav').addClass('small');
}
});
to answer your first question: yes a media query does get called every time you do resize the window.
there is no need to add classes with javascript, I provided you with an example:
it does completely the same but no js needed. Its better to avoid using javascript when its not needed.
nav{
background: green;
}
#media(min-width: 768px){
nav{
background: red;
}
}
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
</ul>
</nav>
I suggest you use css media queries instead of javascript as css is faster than javascript
As soon as Your device width is 768px all the css in that will be called and would overwrite the any other if exist
For more info you can check the link below
Css Media Queries
A CSS media query will apply whenever the conditions in it are fulfilled (for instance, media screen and max-width of 768px), and be ignored whenever it is not. It applies to the window size and will update on resize. You can test this on this website by shrinking your browser.
Such a use-case (using the window resize event) is not recommended as it will trigger on every resize event. Not just when the resizing is finished, but also every tick between start and end. The only use case I know of is to add/remove classes, which is both not recommended, and also a downright CPU hog.
Media query will trigger only when particular point (width or height) mentioned in your media query, whereas javascript resize will trigger at every pixel changed during resize. And, JS is more resource intensive IMO whereas CSS is not and faster. Have a read here
So, in your case, instead of removing and adding classes, have one class and override it's properties based on the screen size in your media query. Something like:
.my-class { width: 400px; }
#media(min-width: 768px){
.my-class { width: 200px; }
}
OR
You can have 2 classes all the time, but only one will take effect based on the screen size. This way you don't override properties (which is a bit ugly, but, that's just me)
// screen <= 767
#media(max-width: 767px){
.nav-small {
width: 320px;
}
}
// screen >= 768
#media(min-width: 768px){
.nav-large {
width: 100%;
}
}

JS launches before CSS

This is currently happening in chrome, in firefox I haven't had this issue (yet).
Here is a VERY simplified version of my problem.
HTML:
<div class="thumbnail">
Click me!
</div>
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
}
a {
position: absolute;
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
Javascript:
$(document).ready(function () {
var $parent = $('#clickMe').parent();
function resize() {
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
$(window).on('resize', resize);
resize();
});
The problem:
So what does this give when I resize (without dragging)? Well javascript launches first and sets the position of the <a></a> , then CSS applies the height change if we are < 992 px.
Logically the button is now visually at the outside of the div and not on the border like I had originally defined it to be.
Temporary solution proposed in this post.
jQuery - how to wait for the 'end' of 'resize' event and only then perform an action?
var doit;
$(window).on('resize', function(){ clearTimeout(doit); doit = setTimeout(resize, 500); });
Temporary solution is not what I'm looking for:
However, in my situation I don't really need to only call 'resize' when the resizing event is actually done. I just want my javascript to run after the css is finished loading/ or finished with it's changes. And it just feels super slow using that function to 'randomely' run the JS when the css might be finished.
The question:
Is there a solution to this? Anyone know of a technique in js to wait till css is completely done applying the modifications during a resize?
Additional Information:
Testing this in jsfiddle will most likely not give you the same outcome as I. My css file has many lines, and I'am using Twitter Bootstrap. These two take up a lot of ressources, slowing down the css application (I think, tell me if I'm wrong).
Miljan Puzović - proposed a solution by loading css files via js, and then apply js changes when the js event on css ends.
I think that these simple three steps will achieve the intended behavior (please read it carefully: I also suggest to read more about the mentioned attributes to deeply understand how it works):
Responsive and fluid layout issues should always be primarily (if not scrictly) resolved with CSS.
So, remove all of your JavaScript code.
You have positioned the inner a#clickMe element absolutely.
This means that it will be positioned within its closest relatively positioned element. By the style provided, it will be positioned within the body element, since there is no position: relative; in any other element (the default position value is static). By the script provided, it seems that it should be positioned within its direct parent container. To do so, add position: relative; to the div.thumbnail element.
By the script you provided, it seems that you need to place the a#clickMe at the bottom of div.thumbnail.
Now that we are sure that the styles added to a#clickMe is relative to div.thumbnail, just add bottom: 0px; to the a#clickMe element and it will be positioned accordingly, independently of the height that its parent has. Note that this will automatically rearrange when the window is resized (with no script needed).
The final code will be like this (see fiddle here):
JS:
/* No script needed. */
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
position: relative; //added
}
a {
position: absolute;
bottom: 0px; //added
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
If you still insist on media query change detection, see these links:
http://css-tricks.com/media-query-change-detection-in-javascript-through-css-animations/
http://css-tricks.com/enquire-js-media-query-callbacks-in-javascript/
http://tylergaw.com/articles/reacting-to-media-queries-in-javascript
http://davidwalsh.name/device-state-detection-css-media-queries-javascript
Twitter Bootstrap - how to detect when media queries starts
Bootstrap: Responsitive design - execute JS when window is resized from 980px to 979px
I like your temporary solution (I did that for a similar problem before, I don't think half a second is too long for a user to wait but perhaps it is for your needs...).
Here's an alternative that you most likely have thought of but I don't see it mentioned so here it is. Why not do it all through javascript and remove your #media (max-width.... from your css?
function resize() {
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
if(width<992){
$("div").each(function(e,obj){$(obj).height(200);});
}
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
In the html page, put the link to css file in head section; next, put the link to js file just before the /body tag and see what happens. In this way css will load always before js.
Hope this help you.
Did you try to bind the resize handler not to the window but to the object you want to listen to the resize ?
Instead of
$(window).on('resize', resize);
You can try
$("#clickMe").on('resize', resize);
Or maybe
$("#clickMe").parent().on('resize', resize);
var didResize = false;
$(window).resize(function() {
didResize = true;
});
setInterval(function() {
if (didResize) {
didResize = false;
console.log('resize');
}
}, 250);
I agree with falsarella on that you should try to use only CSS to do what you are trying to do.
Anyway, if you want to do something with JS after the CSS is applied, I think you can use requestAnimationFrame, but I couldn't test it myself because I wasn't able to reproduce the behavior you explain.
From the MDN doc:
The window.requestAnimationFrame() method tells the browser that you
wish to perform an animation and requests that the browser call a
specified function to update an animation before the next repaint. The
method takes as an argument a callback to be invoked before the
repaint.
I would try something like this:
var $parent = $('#clickMe').parent();
function resize(){
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
window.onresize = function(e){
window.requestAnimationFrame(resize);
}
window.requestAnimationFrame(resize);
Anyone know of a technique to wait till css is completely done loading?
what about $(window).load(function() { /* ... */ } ?
(it executes the function only when the page is fully loaded, so after css loaded)

jQuery - If screen is less than specified width (responsive)

How can I make an alert popup if the width of the page is less than 1200px, and made responsive?
Thanks!
You can use something like the breakpoints module. Then you setup a breakpoint to trigger at 1200px and show a dialog and either add a css class that changes the layout, or use straight javascript to make the changes.
breakpoints(1200, function(oldPoint, newPoint) {
alert('The screen width just changed');
});
if you just wanted native jQuery:
$(window).resize(function() {
var width = $(window).width();
if (width < 1200){
alert('Your screen is too small');
}
});
For completeness, heres the CSS media query (still doesn't take care of the alert, but can help with making the website "responsive").
/* some normal style */
.myclass {
font-size: 22pt;
}
/* alter the style when the screen's smaller */
#media screen and (max-width: 1200px) {
.myclass {
font-size: 18pt;
}
}
For future Googlers, a 2019 solution is to use JavaScript's window​.match​Media(). It is supported in all major browsers and IE 10 onwards.
You can use it like this:
if (window.matchMedia('(max-width: 1200px)').matches) {
// functionality for screens smaller than 1200px
}
To make this responsive, you just need to wrap it in a resize function:
$(window).resize(function() {
if (window.matchMedia('(max-width: 1200px)').matches) {
// functionality for screens smaller than 1200px
}
});
This is arguably the most easiest way to check a screen size and it doesn't bloat the code.
Check the Mozilla docs about match​Media to learn more and this one for more info on Testing media queries programmatically.

How to hide a div if it overlaps another div

Is this CSS or javascript? I just need the div to change to display:none if it comes within say 20px of another div. Thanks
Try this
https://github.com/brandonaaron/jquery-overlaps
//Listen to the event that will be triggered on window resize:
window.onresize = function(event)
{
// test if one element overlaps another
if($('#div1').overlaps('#div2'))
{
//Do stuff, like hide one of the overlapping divs
$('#div1').hide();
}
}
Based on your comment:
Yes it is so that if the user makes their browser window small my site
does not look crowded
Instead of answering the question you asked, Here's an answer to the question you didn't ask:
How to resize/position/cssify page elements based on browser size?
There is a new-ish application of css and javascript called Responsive Web Design. Responsive Design allows you to specify different css rules to apply based on different elements. For a great example of this technique, resize your browser around on The Boston Globe's website. They just integrated this technique sometime this week.
Here's an example of the css that would implement this:
#media screen and (min-width: 480px) {
.content {
float: left;
}
.social_icons {
display: none
}
// and so on...
}
example from http://thinkvitamin.com/design/beginners-guide-to-responsive-web-design/
Here is a boilerplate to get you going.
You can add an event handler that gets fired when the window is resized. You could do this with javascript or jquery. jquery makes it easy:
window.onresize = function(event) {
var h=$(window).height();
var w=$(window).width();
if(h<400 && w < 300){
//hide divs
$('#yourdivid1').hide();
}
}
Hope this helps

Categories