5

I am trying to detect overlapping of my fixed element(with class fixed) with other static/moveable elements. Based on the result true/false I am changing the font color of my fixed element.

So when fixed element overlaps a black box the font color of it becomes white and black otherwise. My problem is, this is working only with the third moving element.

First and second moving element is overlapping too but the font color of my fixed element is not changing. So the IF condition is only working for the third moving element.

Can anyone help me to fix my code, so that my fixed element's font color changes while overlapping all three moving elements?

My Pen

function collision($fixed, $moving) {
  var x1 = $fixed.offset().left;
  var y1 = $fixed.offset().top;
  var h1 = $fixed.outerHeight(true);
  var w1 = $fixed.outerWidth(true);
  var b1 = y1 + h1;
  var r1 = x1 + w1;
  var x2 = $moving.offset().left;
  var y2 = $moving.offset().top;
  var h2 = $moving.outerHeight(true);
  var w2 = $moving.outerWidth(true);
  var b2 = y2 + h2;
  var r2 = x2 + w2;

  if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
  return true;
}

$(window).scroll(function() {
  $(".moving").each(function() {
    //console.log($(this));
    if (collision($(".fixed"), $(this))) {
      $('.fixed').css('color', 'white');
    } else {
      $('.fixed').css('color', 'black');
    }
  });
});
.fixed {
  color: black;
  position: fixed;
  top: 50px;
}

.moving {
  width: 400px;
  height: 100px;
  background-color: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="fixed">
  Fixed Element
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

4
  • 1
    @CommercialSuicide how this is a duplicate ? only the title is a duplicate ... Commented Feb 15, 2018 at 22:16
  • I checked it, its not duplicate, my problem is very precise and specific which has been solved by @Temani Afif, thanks Commented Feb 15, 2018 at 22:18
  • Another option to consider: using mix-blend-mode to make your text the opposite color of the color below it. Commented Feb 16, 2018 at 7:02
  • Have you considered using a css filter? css-tricks.com/reverse-text-color-mix-blend-mode Commented Feb 16, 2018 at 22:58

2 Answers 2

4

Simply because your apply the logic for each one and thus only the last one is considered. Each one will change the font color for the same element and only the last change will remain.

For example, when you are in the first black box you will test all the three. The first will give true, the second false, the third false and you will endup with false because it's the last. That's why it only works with the last because when the last gives true, you will get the white color after the other two have applied the black color.

Instead you need to apply an OR logic and when one gives true you stop and don't check the others:

function collision($fixed, $moving) {
  var x1 = $fixed.offset().left;
  var y1 = $fixed.offset().top;
  var h1 = $fixed.outerHeight(true);
  var w1 = $fixed.outerWidth(true);
  var b1 = y1 + h1;
  var r1 = x1 + w1;
  var x2 = $moving.offset().left;
  var y2 = $moving.offset().top;
  var h2 = $moving.outerHeight(true);
  var w2 = $moving.outerWidth(true);
  var b2 = y2 + h2;
  var r2 = x2 + w2;

  if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
  return true;
}

$(window).scroll(function() {
      var all = $(".moving");
      for (var i = 0; i < all.length; i++) {
         if (collision($(".fixed"), all.eq(i))) {
             $('.fixed').css('color', 'white');
             break; //no need to test the others !
           } else {
             $('.fixed').css('color', 'black');
           }
         }
      });
.fixed {
  color: black;
  position: fixed;
  top: 50px;
}

.moving {
  width: 400px;
  height: 100px;
  background-color: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="fixed">
  Fixed Element
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="moving">
</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

Sign up to request clarification or add additional context in comments.

4 Comments

omg !! what a perfect solution and wonderful explanation...thanks a lot buddy...I got my mistake now...cheers !!
Should use an .each() loop with jQuery.
@PHPglue but this the main issue, if we use the each then the logic will be executed with each element and we need to avoid this ... we need to loop over the element and stop when we have true.
You can just return in the .each() loop.
0

I painstakingly wrote the following collision code - ENJOY

//<![CDATA[
/* collider.js - written by Jason Raymond Buckley */
$(function(){
$.fn.extend({
  allCollided:function(jQueryNode, includeBorders, includeMargins){
    var r = true, im = !!includeMargins;
    this.each(function(i, e){
      var o = $(e), ow = o.width(), oh = o.height(), os = o.offset(), ot = os.top, ob = oh+ot, ol = os.left, or = ow+ol;
      var oT = parseFloat(o.css('borderTopWidth')), oR = parseFloat(o.css('borderRightWidth')), oB = parseFloat(o.css('borderBottomWidth'));
      var oL = parseFloat(o.css('borderLeftWidth'));
      if(includeBorders){
        if(im){
          oB += parseFloat(o.css('marginBottom'))+oT; oT += parseFloat(o.css('marginTop')); oR += parseFloat(o.css('marginRight'))+oL;
          oL += parseFloat(o.css('marginLeft')); ot -= oT; or += oR; ob += oB; ol -= oL;
        }
        else{
          or += oR+oL; ob += oB+oT;
        }
      }
      else{
        ot += oT; or += oR; ob += oB; ol += oL;
      }
      jQueryNode.each(function(i, e){
        var t = $(e), tw = t.width(), th = t.height(), ts = t.offset(), tt = ts.top, tb = th+tt, tl = ts.left, tr = tw+tl;
        var tT = parseFloat(t.css('borderTopWidth')), tR = parseFloat(t.css('borderRightWidth')), tB = parseFloat(t.css('borderBottomWidth'));
        var tL = parseFloat(t.css('borderLeftWidth'));
        if(includeBorders){
          if(im){
            tB += parseFloat(t.css('marginBottom'))+tT; tT += parseFloat(t.css('marginTop')); tR += parseFloat(t.css('marginRight'))+tL;
            tL += parseFloat(t.css('marginLeft')); tt -= tT; tr += tR; tb += tB; tl -= tL;
          }
          else{
            tr += tR+tL; tb += tB+tT;
          }
        }
        else{
          tt += tT; tr += tR+tL; tb += tB; tl += tL;
        }
        if(!((ot <= tb && ob >= tt || tt <= ob && tb >= ot) && (ol <= tr && or >= tl || tl <= or && tr >= ol))){
          r = false;
          return false;
        }
      });
      if(r === false){
        return false;
      }
    });
    return r;
  },
  anyCollided:function(jQueryNode, includeBorders, includeMargins){
    var r = false, im = !!includeMargins;
    this.each(function(i, e){
      var o = $(e), ow = o.width(), oh = o.height(), os = o.offset(), ot = os.top, ob = oh+ot, ol = os.left, or = ow+ol;
      var oT = parseFloat(o.css('borderTopWidth')), oR = parseFloat(o.css('borderRightWidth')), oB = parseFloat(o.css('borderBottomWidth'));
      var oL = parseFloat(o.css('borderLeftWidth'));
      if(includeBorders){
        if(includeMargins){
          oB += parseFloat(o.css('marginBottom'))+oT; oT += parseFloat(o.css('marginTop')); oR += parseFloat(o.css('marginRight'))+oL;
          oL += parseFloat(o.css('marginLeft')); ot -= oT; or += oR; ob += oB; ol -= oL;
        }
        else{
          or += oR+oL; ob += oB+oT;
        }
      }
      else{
        ot += oT; or += oR; ob += oB; ol += oL;
      }
      jQueryNode.each(function(i, e){
        var t = $(e), tw = t.width(), th = t.height(), ts = t.offset(), tt = ts.top, tb = th+tt, tl = ts.left, tr = tw+tl;
        var tT = parseFloat(t.css('borderTopWidth')), tR = parseFloat(t.css('borderRightWidth')), tB = parseFloat(t.css('borderBottomWidth'));
        var tL = parseFloat(t.css('borderLeftWidth'));
        if(includeBorders){
          if(includeMargins){
            tB += parseFloat(t.css('marginBottom'))+tT; tT += parseFloat(t.css('marginTop')); tR += parseFloat(t.css('marginRight'))+tL;
            tL += parseFloat(t.css('marginLeft')); tt -= tT; tr += tR; tb += tB; tl -= tL;
          }
          else{
            tr += tR+tL; tb += tB+tT;
          }
          tw = t.outerWidth(im); th = t.outerHeight(im);
        }
        else{
          tt += tT; tr += tR+tL; tb += tB; tl += tL;
        }
        if((ot <= tb && ob >= tt || tt <= ob && tb >= ot) && (ol <= tr && or >= tl || tl <= or && tr >= ol)){
          r = true;
          return false;
        }
      });
      if(r === true){
        return false;
      }
    });
    return r;
  }
});
/* collider.js - written by Jason Raymond Buckley */
var fixedL = $('#fixedL'), fixedR = $('#fixedR'), fixedM = $('#fixedM'), moving = $('.moving');
if(moving.anyCollided(fixedL, true)){
  fixedL.css('color', 'white');
}
$(window).scroll(function(){
  if(moving.anyCollided(fixedR)){
    fixedR.css('color', 'orange');
  }
  else{
    fixedR.css('color', '#000');
  }
  if(fixedM.anyCollided(moving, true, true)){
    fixedM.css('color', '#0a0');
  }
  else{
    fixedM.css('color', '#000');
  }
  if($('#red').allCollided(fixedL, true)){
    fixedL.css('color', 'red');
  }
  else if($('#tiny_w_margins').allCollided(fixedL, true, true)){
    fixedL.css('color', 'yellow');
  }
  else if($('#borders_only').allCollided(fixedL, true)){
    fixedL.css('color', 'lightBlue');
  }
  else if($('#green').allCollided(fixedL)){
    fixedL.css('color', 'lightGreen');
  }
  else if(fixedL.allCollided($('#blue'))){
    fixedL.css('color', 'blue');
  }
  else if(fixedL.anyCollided(moving)){
    fixedL.css('color', 'white');
  }
  else{
    fixedL.css('color', 'black');
  }
});
});
//]]>
/* external.css */
html,body{
  padding:0; margin:0;
}
body{
  background:#fff; overflow-y:scroll;
}
.main{
  width:940px; background:#ccc; padding:20px; margin:0 auto;
}
.fixed{
  color:#000; position:fixed;
}
#fixedL{
  top:50px;
}
#fixedR{
  right:100px;
}
#fixedM{
  bottom:10px; left:150px; border-right:35px solid #700; margin:7px 35px 25px 15px;
}
.moving {
  width:400px; height:100px; background-color:#000;
}
.space{
  height:200px;
}
#blue,#red{
  width:700px; margin-left:150px;
}
#tiny_no_margins,#tiny_w_margins{
  width:10px; height:80px;
}
#tiny_w_margins{
  border:15px solid purple; margin:5px 10px 5px 250px;
}
#borders_only{
  width:40px; border:25px solid brown; margin:80px;
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta http-equiv='content-type' content='text/html;charset=utf-8' />
    <meta name='viewport' content='width=device-width' />
    <title>jQuery Collider</title>
    <link type='text/css' rel='stylesheet' href='external.css' />
    <script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script>
    <script type='text/javascript' src='collider.js'></script>
  </head>
<body>
  <div class='main'>
    <div id='out'>
      <div id='fixedL' class='fixed'>Fixed Left</div>
      <div id='fixedR' class='fixed'>Fixed Right</div>
      <div id='fixedM' class='fixed'>Fixed with Border and Margins</div>
      <div class='moving'></div>
      <div class='space'></div>
      <div id='green' class='moving'></div>
      <div class='space'></div>
      <div id='blue' class='moving'></div>
      <div class='space'></div>
      <div id='red' class='moving'></div>
      <div class='space'></div>
      <div id='tiny_no_margins' class='moving'></div>
      <div class='space'></div>
      <div id='tiny_w_margins' class='moving'></div>
      <div class='space'></div>
      <div id='borders_only' class='moving'></div>
      <div class='space'></div>
      <div class='moving'></div>
      <div class='space'></div>
    </div>
  </div>
</body>
</html>

1 Comment

its a bit too much for me as a solution, lol, but thanks anyway for your kind effort...cheers !!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.