5

I am doing an assignment and I am trying to puzzle out why my jquery code is only working when I have console opened. The odd part about this behavior is that it works fine in Edge/IE but not chrome or firefox. I have searched through various threads and I doubled checked that my doc ready function was correctly formated and bracketed. EDIT: Added HTML and CSS

    <!DOCTYPE html>
    <html lang="en">    
    <head>
        <meta charset="UTF-8">
        <title>Project 5: P3</title>
        <meta name="author" content="Mia Kollia"><meta name="robots" content="noindex, nofollow">
       <!-- STANDARD @IMPORT Google Font Gamja Flower -->
        <link href="https://fonts.googleapis.com/css?family=Gamja+Flower" rel="stylesheet"> 
    </head>
    <body>
        <aside class="logo">
            <img src = "sftwear.png" alt="logo"><br>
        </aside>
        <aside class="Home">
          <a href="../home.html">Home</a><br> <!-- Home link -->
        </aside>
        <article class="content">
            <section class="intro">
                <h1> Behold My Cats </h1>
            </section>
          <section class="pic">
        <img class="image" src="pic2.jpg" height="200px" width="200px"> 
        <img class="image" src="pic3.jpg" height="200px" width="200px">
        <img class="image" src="pic4.jpg" height="200px" width="200px">
        <img class="image" src="pic5.jpg" height="200px" width="200px">
          </section>
       <div id="savedspot"></div> <!-- used div here instead of p as I do not expect the viewer to see this -->
        <p id="alertsection"></p>
        <p id="alertsection2"></p> <!-- hidden until used by something -->
        </article>
        <style type="text/css">
          body {
            width:50em; /* Limits the space used by the document */
            margin: auto;
            text-align: center; /*aligns all text */
            font-family: 'Gamja Flower', cursive;
        }
    
        article, aside >img{
             background: linear-gradient(to bottom, #eab92d 0%,#c79810 100%);
             border-radius: 1em;
        }
          .pic > img:nth-of-type(1){
            position: relative;
            display: block;
            border-radius: 1em;
            font-size: .8em;
            padding: .5em;
            margin: .5em;
            color:black;
            background: linear-gradient(to bottom, #4eacdb 0%,#1f96d1 50%,#007ebc 51%,#0084c5 100%) /* Tried to make a fancy gradient did not realllllly work */
        }
    
        .pic > img:nth-of-type(2){
            position: relative;
            display: block;
            border-radius: 1em;
            font-size: .8em;
            padding: .5em;
            margin: .5em;
            color:black;
            background: linear-gradient(to bottom, #4eacdb 0%,#1f96d1 50%,#007ebc 51%,#0084c5 100%) /* Tried to make a fancy gradient did not realllllly work */
        }
    
        .pic > img:nth-of-type(3){
            position: relative;
            display: block;
            border-radius: 1em;
            font-size: .8em;
            padding: .5em;
            margin: .5em;
            color:black;
            background: linear-gradient(to bottom, #4eacdb 0%,#1f96d1 50%,#007ebc 51%,#0084c5 100%) /* Tried to make a fancy gradient did not realllllly work */
        }
    
        .pic > img:nth-of-type(4){
            position: relative;
            display: block;
            border-radius: 1em;
            font-size: .8em;
            padding: .5em;
            margin: .5em;
            color:black;
            background: linear-gradient(to bottom, #4eacdb 0%,#1f96d1 50%,#007ebc 51%,#0084c5 100%) /* Tried to make a fancy gradient did not realllllly work */
        }
        </style>
      
    
            <script src="http://code.jquery.com/jquery-latest.min.js"></script>
            <script>
             "use strict"; 
                $(document).ready(function() {
                    console.log("I'm ready!")
                    $(".pic > img:nth-of-type(1)").click(function(){
                    var imgPosition1 = $(this).position(); 
                        if (imgPosition1.left>=300) {
                            $(this).stop().animate({left: 1}, 3000);
                        }
                        else{
                            $(this).stop().animate({left: 300}, 3000);
                        }
                        console.log(imgPosition1)
                    });
        
                    $(".pic > img:nth-of-type(2)").click(function(){
                        var imgPosition2 = $(this).position(); 
                        if (imgPosition2.left>=300) {
                            $(this).stop().animate({left: 1}, 3000);
                        }
                        else {
                            $(this).stop().animate({left: 300}, 3000);
                        }
                        console.log(imgPosition2)
                    });
        
                    $(".pic > img:nth-of-type(3)").click(function(){
                        var imgPosition3 = $(this).position(); 
                        if (imgPosition3.left>=300) {
                            $(this).stop().animate({left: 1}, 3000);
                        }
                        else {
                            $(this).stop().animate({left: 300}, 3000);
                        }
                        console.log(imgPosition3)
                    });
                
                    $(".pic > img:nth-of-type(4)").click(function(){
                        var imgPosition4 = $(this).position(); 
                        if (imgPosition4.left>=300) {
                            $(this).stop().animate({left: 1}, 3000);
                        }
                        else {
                            $(this).stop().animate({left: 300}, 3000);
                        }
                        console.log(imgPosition4)
                    });
        });
        </script>
    </body>
        <!-- gallery code above -->
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
Mia
  • 85
  • 5
  • 1
    Please post the accompanying HTML and CSS as well. – Scott Marcus May 08 '18 at 14:38
  • 2
    You know when your code runs fine in Edge/IE but not in Chrome/Firefox that you have *serious* problems – j08691 May 08 '18 at 14:39
  • I have appended the HTML and CSS in my original posting, and yes it is embarrassing that IE seems to run it. – Mia May 08 '18 at 14:41
  • Are there any console errors? – Mikey May 08 '18 at 14:43
  • As long as you reference JQuery, it works for me in Chrome. – Scott Marcus May 08 '18 at 14:43
  • There are no console errors, it works on chrome ONLY if I am within the console which makes me think its a doc ready issue. Also could you clarify what you meant by reference JQuery? Sorry if it is a dumb question, I am still learning. – Mia May 08 '18 at 14:44
  • you are forgetting the closing `;` for all your `console.log()` calls – Velimir Tchatchevsky May 08 '18 at 14:44
  • @VelimirTchatchevsky While adding the `;` is good practice, it's not the problem here. – Scott Marcus May 08 '18 at 14:45
  • I just fixed the console logs, thank you Velimir for pointing it out. I did not realize I had to do that. Still doesn't seem to work outside of the console. – Mia May 08 '18 at 14:46
  • also you are animating the 'left' property, while your elements are positioned `relative`, it you position them `absolute` the animation is executed. – Velimir Tchatchevsky May 08 '18 at 14:52
  • @VelimirTchatchevsky since it will fire properly in console I had reasonable suspicious the animation was correctly coded, but Andrei in another comment actually solved the problem. Apparently, I just discovered onload exists and that document ready fires *before* images are ready so there are no images to animate. Interestingly enough, upon this discovery I read more threads on stack overflow to get an idea of how onload works and IE and Edge will throw act as if DOM finished loading when interrupted. See here: https://stackoverflow.com/questions/3698200/window-onload-vs-document-ready – Mia May 08 '18 at 14:56
  • @Mia can you open the console in a different window and try again? – Velimir Tchatchevsky May 08 '18 at 18:51

1 Answers1

7

It looks like your condition

if ($(this).position().left>=300) {...}

returns true when console is open. The animation does happen, but it's from left:0 to left: 1px, over 3 seconds. Impossible to notice.

An improved version of it would be:

"use strict";
let t0 = performance.now();
$(document).ready(console.log("Ready in " + (performance.now() - t0) + 'ms.'))
$(window).on('load', () => {
  console.log("Loaded in " + (performance.now() - t0) + 'ms.');
  $('.pic').on('click tap', 'img', e => {
    $(e.target).toggleClass('transformed')
  })
});
@import('//fonts.googleapis.com/css?family=Gamja+Flower');
body {
  margin: 0;
  text-align: center;
  font-family: 'Gamja Flower', cursive;
}

article,
aside>img {
  background: linear-gradient(to bottom, #eab92d 0%, #c79810 100%);
  border-radius: 1em;
}

.pic>img {
  position: relative;
  display: block;
  border-radius: 1em;
  font-size: .8em;
  padding: .5em;
  margin: .5em;
  color: black;
  background: linear-gradient(to bottom, #4eacdb 0%, #1f96d1 50%, #007ebc 51%, #0084c5 100%);
  transition: transform 3s cubic-bezier(.4,0,.2,1);
  transform: translateX(0);
}
.pic>img.transformed {
  transform: translateX(300px);
}
<script src="//code.jquery.com/jquery-latest.min.js"></script>
<aside class="logo">
  <img src="//picsum.photos/100/100" alt="logo"><br>
</aside>
<aside class="Home">
  <a href>Home</a><br>
</aside>
<article class="content">
  <section class="intro">
    <h1> Behold My Cats </h1>
  </section>
  <section class="pic">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
  </section>
</article>

And here's a list of advantages:

  • it's DRY - there's no need to repeat the same code for each image. You can code it once for all.
  • It only binds once, on the parent, for all images, including future ones added later on to .pic, because the event is bound on the parent and only evaluates if the child is an <img> when the event happens. If you had 1k images, you'd still bind only once and it would be as light, while using your method you'd need 1k bindings.
  • instead of using jQuery's .animate(), which is notoriously slow and resource expensive, it uses CSS animation.
  • instead of animating left (which triggers repaint on subsequent elements), it animates transform, which only triggers updates on the rendering layer - the element doesn't move in DOM. Only its' projection on the rendering layer is updated, without affecting anything else.
  • instead of calculating the current position to determine if you need to move it one way or the other, you simply control direction using existence of a class on the element, allowing you to turn the animation mid-transition, as many times as you want, with minimal cost and no position calculation.

Note: whenever you want to calculate/position images in a page, it's preferred to bind your code on window.onload event (when all sync resources finished loading) rather than on DOM.ready (when the DOM elements map was finished - when parser reached </html> tag). ready fires before onload and typically images (especially if large) have not been loaded and the browser does not know their real size - therefore causing wrong calculations.

Another note: you should always try to perform your animations using CSS, as they're the least expensive (resource wise). Most times you will be able to perform everything you need animating transform or opacity and that's what you should aim for, as they are among the cheapest properties to animate. But CSS animations do have one downside: they don't have a complete/done callback. A way to perform an action or trigger an event when they've completed. When in need to chain animations, you need this callback and that's when you should turn to JavaScript animation libraries. When you do, my advice is to choose .velocity() over jQuery's .animate(). It's well worth the overhead.

$(window).on('load', () => {
  $(".pic").on('click tap', '.image', function() {
    $(this).velocity({
        transform: $(this).position().left > 299.9 ? 
          "translateX(1px)":
          "translateX(300px)"
      }, {
        duration: 1500,
        easing: [ .42, 0, .2, 1 ]
      });
  });
});
@import('https://fonts.googleapis.com/css?family=Gamja+Flower');
body {
  width: 100%;
  margin: 0;
  text-align: center;
  font-family: 'Gamja Flower', cursive;
}

article,
aside>img {
  background: linear-gradient(to bottom, #eab92d 0%, #c79810 100%);
  border-radius: 1em;
}

.image {
  position: relative;
  display: block;
  border-radius: 1em;
  font-size: .8em;
  padding: .5em;
  margin: .5em;
  color: black;
  background: linear-gradient(to bottom, #4eacdb 0%, #1f96d1 50%, #007ebc 51%, #0084c5 100%)
}
<script src="//code.jquery.com/jquery-latest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/velocity/2.0.2/velocity.min.js"></script>

<aside class="logo">
  <img src="//picsum.photos/80/80" alt="logo"><br>
</aside>
<aside class="Home">
  <a href>Home</a><br>
  <!-- Home link -->
</aside>
<article class="content">
  <section class="intro">
    <h1> Behold My Cats </h1>
  </section>
  <section class="pic">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
    <img class="image" src="//picsum.photos/200/200" height="200px" width="200px">
  </section>
</article>

I should make a note here on the future of web animations, which takes best of both worlds (JS & CSS): Web Animations API. As light as CSS, without losing JS versatility. However, it still lacks support in IE and Safari, but on both the status is "Under consideration". So it'll be usable in production environments without polyfills in ~2-3 years.

Final note: you don't need the performance.now() or the log()s in the script, they're only there to show you when document.ready and window.load happen and how much they take from when script is parsed. Here's the short, clean version of that script:

$(window).on('load', () => {
  $('.pic').on('click tap', 'img', e => $(e.target).toggleClass('transformed'))
});
tao
  • 82,996
  • 16
  • 114
  • 150
  • Sorry for the noobish question, but I assumed DOM finishing building = all assets have loaded? I'll try onload and get back to you on that. – Mia May 08 '18 at 14:48
  • `DOM.ready` means: dom parser reached ` – tao May 08 '18 at 14:57
  • 1
    OP does not depend on getting the `.position()` "on `document.ready`", she does it on `click` which is why the code originally does change the `left` property. The interesting part was the fact that is "worked" when the console was opened, which is because she had it opened in the window and thus made it smaller and the offset from the left edge exceeded the one that was set by the `margin: auto`. Note: everything you say in the answer is worth noting though – Velimir Tchatchevsky May 08 '18 at 18:46
  • You were correct, @Velimir. I revised my answer, giving the correct answer. I let the initial observations there, as general advice, hoping they might be useful for future visitors. Thanks for your observation. – tao May 08 '18 at 20:04