7

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">
  <a href='#' id="clickMe">Click me!</a>
</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.

Community
  • 1
  • 1
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • 2
    Is the CSS/JS added inline or as external resources? Do you add it in `head` or before closing `body`? – Sergiu Paraschiv Jun 12 '14 at 09:04
  • **feel free to let me know if I should make my question more clear.. first one I've ever asked. Thanks** – kemicofa ghost Jun 12 '14 at 09:04
  • @Sergiu they are being loaded in the head. My company is using CMS wordpress. – kemicofa ghost Jun 12 '14 at 09:06
  • 1
    Try reading this http://stackoverflow.com/questions/1324568/is-document-ready-also-css-ready – Sergiu Paraschiv Jun 12 '14 at 09:08
  • jQuery `window ready` basically cannot not guarantee the CSS has been rendered, just that it's been loaded. – Sergiu Paraschiv Jun 12 '14 at 09:10
  • I see, I was really hopping for a solution other than the one I already had. Right now it works, but you can see a jump when the javascript kicks in to place the elements in the right area. – kemicofa ghost Jun 12 '14 at 09:20
  • I know. It's a pretty common problem called "flash of unstyled content": http://stackoverflow.com/questions/11640238/how-to-stop-flash-of-unstyled-content – Sergiu Paraschiv Jun 12 '14 at 09:22
  • 2
    How about this: insert css with js, and when that event is finished insert/apply rest of js? – Miljan Puzović Jun 12 '14 at 09:44
  • I think it's a good idea. I'd be interested in seeing a demo on how that works. – kemicofa ghost Jun 12 '14 at 12:16
  • 1
    I don't really understand the problem. Can someone clarify it for me? – Muqito Jun 13 '14 at 08:50
  • On a normal page, where there isn't much js and/or css there isn't much of a difference. However, on the contraire, I'm working on this website which uses more resources. Pretty much js runs quicker than css. Say I modify the position with js of a link, and I place it on the border of it's parent. And at the same time my css modifies the parent height... If JS runs first, the link will be at the location of the old height. So my question is: I need a way to wait for the CSS modifications to be finished before running my JS. – kemicofa ghost Jun 13 '14 at 08:58
  • 1
    The edits being (a) at the top before the actual problem statement and (b) explicit additions as opposed to part of the text is very confusing to new readers (threw me off, it did). Perhaps it's better to edit them into the question? – Jeroen Jun 14 '14 at 09:16
  • Very well, I'll work on it. Thanks for the advice. – kemicofa ghost Jun 14 '14 at 09:23

7 Answers7

5

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):

  1. Responsive and fluid layout issues should always be primarily (if not scrictly) resolved with CSS.

    So, remove all of your JavaScript code.

  2. 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.

  3. 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

Community
  • 1
  • 1
falsarella
  • 12,217
  • 9
  • 69
  • 115
  • I agree that it might be simpler to just do everything in either javascript or css, I would still like to know how to wait for css to get finished before applying JS. – kemicofa ghost Jun 18 '14 at 07:54
4

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()
    });

}
James
  • 4,146
  • 1
  • 20
  • 35
  • I like to try and do certain things in css, if I can't do it in css I do it in JS. I think the best solution is to do either all of it in css or js. But I feel I will fall upon this problem again one day, so I would really like to know how to wait till the exact moment css is done applying changes. – kemicofa ghost Jun 18 '14 at 07:57
2

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.

Azincourt
  • 935
  • 5
  • 13
  • 29
  • 1
    That would be for the initial load. I'm talking about when everything has already been loaded and when a resize event occurs. – kemicofa ghost Jun 16 '14 at 12:48
2

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);
fougerejo
  • 51
  • 1
  • 6
1
var didResize = false;
$(window).resize(function() {
    didResize = true;
});
setInterval(function() {
    if (didResize) {
        didResize = false;
        console.log('resize');
    }
}, 250);
Tobiasz
  • 350
  • 1
  • 8
  • This only checks if the javascript event resize got called and finished. I want to see when the css modifications of a resize get finished. – kemicofa ghost Jun 12 '14 at 09:19
1

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);
Danziger
  • 19,628
  • 4
  • 53
  • 83
-1

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)

hl037_
  • 3,520
  • 1
  • 27
  • 58
  • I should have made myself a little more clear. I also want to wait for the css modifications at the end of a resize to actually get finished. I did try loading and it only fixes part of the problem. The resizing is really the frustrating part. – kemicofa ghost Jun 12 '14 at 09:16