sol acyon sol acyon - 7 months ago 14
Javascript Question

Masking issue when sliding multiple divs behind a line

I have a CSS animation effect that's difficult to implement due to layering problems. See the snippet below:



var toggle = document.getElementById('toggle');

function toggleF() {
'use strict';
document.querySelector('nav').classList.add('fuzzyState');
}

toggle.addEventListener('click', toggleF);

nav ul { height:150px; margin:0; padding:0; font-size:150% }
nav li {
width:140px; height:140px; margin:5px; float:left; list-style:none;
user-select:none; -webkit-user-select:none
}
nav button {
display:block; position:relative; top:50%; width:100%; height:100%;
background:transparent; border:0; text-transform:uppercase;
transform:translateY(-50%)
}
nav button:hover { background:#022; color:#eee }
nav button:active { background:#033; color:#fff }
ul hr {
position:relative; top:50%; width:1px; height:90px; margin:10px;
background:#eee; border:0; float:left; transform:translateY(-50%);
z-index:2
}
nav.fuzzyState #dos { transform:translateX(230px) }
nav.fuzzyState #uno {
transform:translateX(400px); -webkit-filter:blur(1px)
}
nav.fuzzyState #tres { /*transform:translateX(-230px)*/}
nav #tres { position:relative; z-index:1 }
#leftNavMask{
background:#fff;
position:absolute; top:15%; right:0; left:356px; width:200px; height:190px;
text-align:justify; transform:translateY(-50%);
}
#rightNavMask{
background:#fff;
position:absolute; top:15%; right:0; left:156px; width:200px; height:190px;
text-align:justify; transform:translateY(-50%); z-index:-1
}
#dos, #tres{ transition:transform 0.7s ease-in-out }
#uno{ transition:transform 1s ease-in-out, -webkit-filter 1s ease-in-out; }

<head>
<style>
html, body { height:90%; color:#222; text-align:center overflow:hidden; }
button { outline:0; cursor:pointer }
#toggle {
float:left; width:38px; height:38px; padding:5px; margin:auto;
background:#fff; color:#666; border:0; font-size:150%
}
#toggle:hover {
background:#222; color:#eee; user-select:none; -webkit-user-select:none
}
#toggle:active { background:#022; color:#fff }
nav ul:after { content""; display:block; clear:both }/* <<clearfix */
</style>
</head>
<body>
<button id = "toggle">+</button>
<nav>
<ul>
<li id = "uno"><button>uno</button></li>
<li id = "dos"><button>dos</button></li><hr>
<li id = "tres"><button>tres</button></li>

<div id = "leftNavMask"></div>
<div id = "rightNavMask"></div>
</ul>
</nav>
</body>





After the "+" button is clicked my goal is to make the "tres" button slide to the left while being masked just like the "uno" and "dos" buttons, except in the opposite direction. It seems impossible to pull off because whatever
z-index
I give any elements there's no way to have the left mask on top of the correct elements while simultaneously having the right mask do its job. Are there any simple ways to do this without jquery? Thanks.

To clarify: The "Uno" and "Dos" buttons are currently going "under" a div that is colored to match the background. I need the "tres" button to slide left "under" a second div that is somehow on top of the "tres" button to mask it, but also below the "uno" and "dos" buttons so they aren't blocked to begin with.

Answer

You don't need to have separate divs matching the background color layered in a complicated (impossible) way to perform masking like this. You can remove those divs and just create 2 container divs for each side, directly parenting the list elements you want to mask. After absolutly positioning them, just give them both: overflow:hidden and that will mask each side accordingly. No complicated layers needed!

var toggle = document.getElementById('toggle');

function toggleF() {
  'use strict';
  document.querySelector('nav').classList.add('fuzzyState');
}

toggle.addEventListener('click', toggleF);
nav ul { height:150px; margin:0; padding:0; font-size:150% }
nav li {
  width:140px; height:140px; margin:5px; float:left; list-style:none;
  user-select:none; -webkit-user-select:none
}
nav button {
  display:block; position:relative; top:50%; width:100%; height:100%; 
  background:transparent; border:0;  text-transform:uppercase; 
  transform:translateY(-50%)
}
nav button:hover { background:#022; color:#eee }
nav button:active { background:#033; color:#fff }
ul hr {
  position:relative; top:50%; width:1px; height:90px; margin:10px; 
  background:#eee; border:0; float:left; transform:translateY(-50%);
  z-index:2; left:350px
}
nav.fuzzyState #dos { transform:translateX(230px) }
nav.fuzzyState #uno {
  transform:translateX(400px); -webkit-filter:blur(1px)
}
nav.fuzzyState #tres { transform:translateX(-230px) }
nav #tres { position:relative; z-index:1 }

#dos, #tres{ transition:transform 1s ease-in-out }
#uno{ transition:transform 1s ease-in-out, -webkit-filter 1.3s ease-in-out; }

#rightMask{
  width:150px; height:150px; position:absolute; 
  right:300px; left:414px; overflow:hidden;
}
#leftMask{
  width:300px; height:150px; position:absolute; 
  left:100px; overflow:hidden;
    
}
<head>
  <style>
    html, body { height:90%; color:#222; text-align:center overflow:hidden; } 
    button { outline:0; cursor:pointer }
    #toggle {
      float:left; width:38px; height:38px; padding:5px; margin:auto; 
      background:#fff; color:#666; border:0; font-size:150%
    }
    #toggle:hover {
      background:#222; color:#eee; user-select:none; -webkit-user-select:none
    }
    #toggle:active { background:#022; color:#fff }
     nav ul:after { content""; display:block; clear:both }/* <<clearfix */
   </style>
</head>
<body>
  <button id = "toggle">+</button>
  <nav>
    <ul>
      <div id = "leftMask">
        <li id = "uno"><button>uno</button></li>
        <li id = "dos"><button>dos</button></li>
      </div>
      <hr>
      <div id = "rightMask"><li id = "tres"><button>tres</button></li></div>
    
      <div id = "leftNavMask"></div>
      <div id = "rightNavMask"></div>
    </ul>
  </nav>
</body>

Comments