2

When I am hovering on a menu, I'd like an arrow will slide from left to the menu item I'm currently hovering on.

In JavaScript I'd bind an event to hover and play with the arrow element's "left" property, but I wonder if I can have a pure css3 animated solution.

The arrow is similar to this thread- Show border triangle in navbar using CSS

But I don't want it to appear and hide- I want the arrow always visible and that it will slide right to left depending on the menu I'm currently hovering on.

This is how it would look if I'd done it in JS:

var arrEle = $("#indication-mark-wrap");
var startHover = $(arrEle).css("left");
$("li").mouseenter(function() {
  var left = $(this).position().left;
  $(arrEle).css("left", left+30);
});

$("li").mouseleave(function() {
  $(arrEle).css("left", startHover);
});
ul {
  list-style-type: none;
  padding: 0px;
}

li {
  display: inline-block;
  width: 80px;
  color: white;
  background-color: black;
  height: 50px;
}

#indication-mark-wrap {
  position: absolute;
  left: 38px;
  top: 56px;
  background: wheat;
  -webkit-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
  -webkit-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
}

.indication-mark {
  position: relative;
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="menu">
  <ul>
    <li>Selection1</li>
    <li>Selection2</li>
    <li>Selection2</li>
  </ul>
</div>

<div id="indication-mark-wrap">
  <canvas width="20" height="20" class="indication-mark"></canvas>
</div>

Sample JSFiddle

Community
  • 1
  • 1
Ziv Weissman
  • 4,400
  • 3
  • 28
  • 61

1 Answers1

3

With a change in your markup, you can do like this.

$(function(){
$("li").click(function(){
  $(".active").removeClass("active");
  $(this).addClass("active");
})
});
ul {
  list-style-type: none;
  padding: 0px;
}

li {
  background-color: black;
}

li:nth-child(-n+3) {
  display: inline-block;
  width: 80px;
  color: white;
  height: 50px;
}

#indication-mark-wrap {
  position: absolute;
  left: 35px;
  top: 56px;
  background: wheat;
  -webkit-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
  -webkit-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
}

.indication-mark {
  position: relative;
  display: block;
}

li:nth-child(2):hover ~ li #indication-mark-wrap {
  left: 118px;
}
li:nth-child(3):hover ~ li #indication-mark-wrap {
  left: 200px;
}
 
li:nth-child(1).active ~ li #indication-mark-wrap {
  left: 35px;
}

li:nth-child(2).active ~ li #indication-mark-wrap {
  left: 118px;
}
li:nth-child(3).active ~ li #indication-mark-wrap {
  left: 200px;
}

#indication-mark-wrap:before,
#indication-mark-wrap:after {
  content: "";
  position: absolute;
  top: 15px;
  width: 0;
  height 0;
  border-left: 15px solid transparent;
  border-right: 15px solid transparent;
  border-bottom: 15px solid white;
}
#indication-mark-wrap:before {
  top: 14px;
  border-bottom-color: black;
}
.active {
  background-color: darkcyan;
}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="menu">
  <ul>
    <li class="active">Selection1</li>
    <li>Selection2</li>
    <li>Selection2</li>
    <li class="test"><div id="indication-mark-wrap"></div></li>
  </ul>
</div>

CSS only

ul {
  list-style-type: none;
  padding: 0px;
}
li {
  background-color: black;
}
li:nth-child(-n+3) {
  display: inline-block;
  width: 80px;
  color: white;
  height: 50px;
}
li:nth-child(-n+3) label {
  display: inline-block;
  width: 100%;
  height: 100%;
  cursor: inherit;
}

#indication-mark-wrap {
  position: absolute;
  left: 35px;
  top: 56px;
  background: wheat;
  -webkit-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition: all 1000ms cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
  -webkit-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -moz-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  -o-transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  transition-timing-function: cubic-bezier(0.000, 0.000, 0.330, 0.990);
  /* custom */
}

.indication-mark {
  position: relative;
  display: block;
}

#s1, #s2, #s3 {
  display: none;
} 
#s1:checked ~ ul #indication-mark-wrap {
  left: 35px;
}
#s2:checked ~ ul #indication-mark-wrap {
  left: 118px;
}
#s3:checked ~ ul #indication-mark-wrap {
  left: 200px;
}
li:nth-child(-n+3):hover {
  background: darkgray;
  cursor: pointer;
}
#s1:checked ~ ul li:nth-child(1),
#s2:checked ~ ul li:nth-child(2),
#s3:checked ~ ul li:nth-child(3) {
  background-color: darkcyan;
  cursor: auto;
}

#indication-mark-wrap:before,
#indication-mark-wrap:after {
  content: "";
  position: absolute;
  top: 15px;
  width: 0;
  height 0;
  border-left: 15px solid transparent;
  border-right: 15px solid transparent;
  border-bottom: 15px solid white;
}
#indication-mark-wrap:before {
  top: 14px;
  border-bottom-color: black;
}
<div class="menu">
  <input type="radio" id="s1" name="s123" checked="checked">
  <input type="radio" id="s2" name="s123">
  <input type="radio" id="s3" name="s123">
  <ul>
    <li><label for="s1">Selection1</label></li>
    <li><label for="s2">Selection2</label></li>
    <li><label for="s3">Selection3</label></li>
    <li class="test"><div id="indication-mark-wrap"></div></li>
  </ul>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • I've added support for "active" tab, only javascript is for the click which is ok because it is added by bootstrap tabs. Now it is perfect for my needs. – Ziv Weissman Jul 14 '16 at 05:29
  • 1
    @ZivWeissman Updated with a 2:nd sample, active tabs using CSS only (if you want to go _no script_) – Asons Jul 14 '16 at 08:03
  • nice I like the label trick... ;) add to style cursor:pointer (not .active) and its a very cool css plug and play menu ! – Ziv Weissman Jul 14 '16 at 09:31