wj R.
wj R.

Reputation: 359

Setting up pure css arrows to menu with transparent or image background?

I am trying to apply a pure css arrow to my SELECTED link of horizontal and vertical menu but can't seem to figure out the outcome I wanted. Some similar solutions here at stackoverflow but it doesn't solve my issue.

UL has a border and that's where the problem is coming from... But I shouldn't remove the UL border.

FIDDLE HERE

<li class="selected"><a href="#">Arrow please</a></li>

Objective

ul.hor {
  border-bottom: 3px solid blue;
}
ul li {
  display: inline-block;
  position: relative;
}
ul li a {
  display: block;
  padding: 10px 15px;
}
ul li.selected a {
  color: green;
}
ul li.selected:after {
  content: "";
  width: 12px;
  height: 12px;
  position: absolute;
  background: #fff;
  border-top: 3px solid blue;
  border-right: 3px solid blue;
}
ul.hor li.selected:after {
  left: 0;
  right: 0;
  bottom: -8px;
  margin: 0 auto;
  -moz-transform: rotate(315deg);
  -webkit-transform: rotate(315deg);
  -ms-transform: rotate(315deg);
}
ul.ver li.selected:after {
  right: -8px;
  top: 50%;
  margin-top: -6px;
  -moz-transform: rotate(225deg);
  -webkit-transform: rotate(225deg);
  -ms-transform: rotate(225deg);
}
ul.ver {
  width: 200px;
  border-right: 3px solid blue;
}
ul.ver li {
  display: block;
}
ul.ver li a {
  display: block;
  padding: 10px 15px;
}
body {
  width: 90%;
  margin: 20px auto;
  background: rgb(229, 180, 230);
  background: -moz-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -webkit-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -o-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -ms-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: linear-gradient(120deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
}
<ul class="hor">
  <li><a href="#">Lorem</a></li>
  <li><a href="#">Ipsum</a></li>
  <li class="selected"><a href="#">Sit amet</a></li>
  <li><a href="#">Consectetur</a></li>
</ul>
<br>
<ul class="ver">
  <li><a href="#">Lorem</a></li>
  <li><a href="#">Ipsum</a></li>
  <li class="selected"><a href="#">Sit amet</a></li>
  <li><a href="#">Consectetur</a></li>
</ul>

Upvotes: 9

Views: 2857

Answers (5)

jamez88
jamez88

Reputation: 585

This one is easier to position and has a perfect triangle. We are still using transform rotate but no need for transform skew. No need to calculate width as well. Fiddle here.

ul {
    overflow: hidden;
}
li {    
    display:inline-block;position: relative;
}
ul li a {
  display: block;padding:20px 15px;
}
ul li.selected a {
  color: green;
}
ul.hor li.selected:before,
ul.hor li.selected:after {
   content: "";
   bottom: 0;
   position: absolute;
   border-bottom:3px solid blue;
   width:9999px;
   margin:0 10px;left:50%;
}
ul.hor li.selected:after {
    left:auto;right:50%;
}
/*vertical menu starts*/
ul.ver {
  width: 200px;
}
ul.ver li {
  display: block;
}
ul.ver li a {
  padding:10px 15px;
}
ul.ver li.selected:before,
ul.ver li.selected:after {
   content: "";
   position: absolute;
   top:50%;
   right: 0;
   border-right:3px solid blue;
   height:9999px;
   margin:10px 0
}
ul.ver li.selected:after {
    top:auto;bottom:50%;
}

/*arrow starts*/
ul li.selected a:after {
    content: "";
    width: 15px;
    height: 15px;
    position: absolute;
    border: solid blue;
    border-width: 3px 3px 0 0;  
}

ul.hor li.selected a:after {
    top:100%;
    left: 0;
    right: 0;
    margin: -10px auto 0; 
    -moz-transform: rotate(315deg);
    -webkit-transform: rotate(315deg);
    -ms-transform: rotate(315deg);
}
ul.ver li.selected a:after {
    left:100%;
    margin-left:-10px;
    -moz-transform:rotate(225deg);
    -webkit-transform:rotate(225deg);
    -ms-transform:rotate(225deg);
}
body {
    width:90%;margin:20px auto;
    background: rgb(229, 180, 230);
background: -moz-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -webkit-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -o-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -ms-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: linear-gradient(120deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
}
<ul class="hor">
	    <li><a href="#">Lorem</a></li>
	    <li class="selected"><a href="#">Ipsum</a></li>
	    <li><a href="#">Sit amet</a></li>
	    <li><a href="#">Consectetur</a></li>
	</ul>
<br>
	<ul class="ver">
	    <li class="selected"><a href="#">Lorem</a></li>
	    <li><a href="#">Ipsum</a></li>
	    <li><a href="#">Sit amet</a></li>
	    <li><a href="#">Consectetur</a></li>
	</ul>

Upvotes: 9

Blake
Blake

Reputation: 84

I made this:

ul li.selected a {
    color:green
}

ul.hor {
    border-bottom:3px solid blue
}

ul.ver {
    width:200px;
    border-right:3px solid blue;
}

ul li {
    display:inline-block;position:relative
}
ul li a {
    display:block;padding:10px 15px;
}

}

ul.ver {
    width:200px;border-right:3px solid blue
}
ul.ver li {
    display:block;
}
ver li a {
    display:block;padding:10px 15px;
}


body {
    width:90%;margin:20px auto;
    background: rgb(229, 180, 230);
background: -moz-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -webkit-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -o-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: -ms-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
background: linear-gradient(120deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);

}

.ver {
	position: relative;
}
.ver:after, .arrow_box:before {
    left: 177px;
    top: 95px;
	border: solid;
	content: " ";
	height: 0;
	width: 0;
	position: absolute;
	pointer-events: none;
}

.ver:after {
	border-color: rgba(136, 183, 213, 0);
	border-right-color: blue;
	border-width: 12px;
	margin-top: -12px;
}

.hor {
	position: fixed;
}

.hor:after, .hor:before {
	top: 20px;
	left: 194px;
	border: solid transparent;
	content: " ";
	height: 0;
	max-width: 0;
	position: absolute;
	pointer-events: none;
}

.hor:before {
	border-color: rgba(194, 225, 245, 0);
	border-bottom-color: blue;
	border-width: 10px;
	margin-left: -10px;
}
<ul class="hor">
  <div class="arrow_box-vertical">
    <li><a href="#">Lorem</a>
    </li>
    <li><a href="#">Ipsum</a>
    </li>
    <li class="selected"><a href="#">Sit amet</a>
    </li>
    <li><a href="#">Consectetur</a>
    </li>
</ul>
<br>
<br>
<br>
<ul class="ver">
  <li><a href="#">Lorem</a>
  </li>
  <li><a href="#">Ipsum</a>
  </li>
  <li class="selected"><a href="#">Sit amet</a>
  </li>
  <li><a href="#">Consectetur</a>
  </li>
</ul>

It looks horrible in the snippet, please look at the JSFiddle.

Upvotes: 0

Bitwise Creative
Bitwise Creative

Reputation: 4105

Update: Found using 50.6% on the width calc for the a element borders greatly reduces the sub-pixel issues at certain window widths. Snippet updated and here's the fiddle link: http://jsfiddle.net/5wLe4r3h/

Disclaimer: I don't consider this to be elegant.

I moved the main border to the li elements. I'm clearing out the li.selected border, and adding before/after partial borders to the a elements.

ul.hor li {
    border-bottom:3px solid blue;
    float: left;
}
ul.hor li.selected {
    border-bottom: none;
}
ul.hor li.selected a:before {
    content:"";
    position: absolute;
    bottom: -3px;
    left: 0px;
    border-bottom:3px solid blue;
    width: calc(50.6% - 9px);
}
ul.hor li.selected a:after {
    content:"";
    position: absolute;
    bottom: -3px;
    right: 0px;
    border-bottom:3px solid blue;
    width: calc(50.6% - 9px);
}
ul li {
    display:inline-block;
    position:relative
}
ul li a {
    display:block;
    padding:10px 15px;
}
ul li.selected a {
    color:green
}
ul li.selected:after {
    content:"";
    width:12px;
    height:12px;
    position:absolute;
    border-top:3px solid blue;
    border-right:3px solid blue;
}
ul.hor li.selected:after {
    left:0;
    right:0;
    bottom:-8px;
    margin:0 auto;
    -moz-transform:rotate(315deg);
    -webkit-transform:rotate(315deg);
    -ms-transform:rotate(315deg);
}
ul.ver li.selected:after {
    right:-5px;
    top:50%;
    margin-top:-6px;
    -moz-transform:rotate(225deg);
    -webkit-transform:rotate(225deg);
    -ms-transform:rotate(225deg);
}
ul.ver {
    width:200px;
}
ul.ver li {
    display:block;
    border-right:3px solid blue;
}
ul.ver li a {
    display:block;
    padding:10px 15px;
}
ul.ver li.selected {
    border-right: none;
}
ul.ver li.selected a:before {
    content:"";
    position: absolute;
    top: 0px;
    right: 0px;
    border-right:3px solid blue;
    height: calc(50% - 7px);
}
ul.ver li.selected a:after {
    content:"";
    position: absolute;
    bottom: 0;
    right: 0px;
    border-right:3px solid blue;
    height: calc(50% - 10px);
}
body {
    width:90%;
    margin:20px auto;
    background: rgb(229, 180, 230);
    background: -moz-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
    background: -webkit-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
    background: -o-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
    background: -ms-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
    background: linear-gradient(120deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
}
.clear {
    clear: both;
}
<ul class="hor">
    <li><a href="#">Lorem</a>
    </li>
    <li><a href="#">Ipsum</a>
    </li>
    <li class="selected"><a href="#">Sit amet</a>
    </li>
    <li><a href="#">Consectetur</a>
    </li>
</ul>
<div class="clear"></div>
<br>
<ul class="ver">
    <li><a href="#">Lorem</a>
    </li>
    <li><a href="#">Ipsum</a>
    </li>
    <li class="selected"><a href="#">Sit amet</a>
    </li>
    <li><a href="#">Consectetur</a>
    </li>
</ul>

Upvotes: 2

web-tiki
web-tiki

Reputation: 103770

One approach would be to use absolute positioning with pseudo elements on the selected element.

The arrow is made with borders and skewX() skewY() on the pesudo elements. Their with for the horizontal menu and the height for the vertical one are set to a high value and the overflow is hidden on the <ul> element :

ul {
  overflow: hidden;
}
ul li {
  position: relative;
  display: inline-block;
  text-align: center;
}
ul li a {
  display: block;
  padding: 10px 15px;
}
ul li.selected a {
  color: green;
}
.hor .selected:before, .hor .selected:after {
  content: '';
  position: absolute;
  bottom: 0;
  height: 7px;
  width: 9999px;
  border-style: solid;
  border-width: 0px 4px 3px;
  border-color: blue;
}
.hor .selected:before {
  right: 50%;
  margin-right: -2px;
  transform-origin: 100% 0;
  transform: skewX(-45deg);
}
.hor .selected:after {
  left: 50%;
  margin-left: -2px;
  transform-origin: 0 0;
  transform: skewX(45deg);
}
ul.ver {
  width: 200px;
}
ul.ver li {
  display: block;
}
ul.ver li a {
  display: block;
  padding: 10px 15px;
}
.ver .selected:before, .ver .selected:after {
  content: '';
  position: absolute;
  right: 0;
  height: 9999px;
  width: 7px;
  border-style: solid;
  border-width: 4px 3px 4px 0;
  border-color: blue;
}
.ver .selected:before {
  bottom: 50%;
  margin-bottom: -2px;
  transform-origin: 0 100%;
  transform: skewY(-45deg);
}
.ver .selected:after {
  top: 50%;
  margin-top: -2px;
  transform-origin: 0 0;
  transform: skewY(45deg);
}
body {
  width: 90%;
  margin: 20px auto;
  background: rgb(229, 180, 230);
  background: -moz-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -webkit-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -o-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: -ms-linear-gradient(30deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
  background: linear-gradient(120deg, rgb(229, 180, 230) 30%, rgb(90, 140, 250) 70%);
}
<ul class="hor">
  <li><a href="#">Lorem</a></li>
  <li><a href="#">Ipsum</a></li>
  <li class="selected"><a href="#">Sit amet</a></li>
  <li><a href="#">Consectetur</a></li>
</ul>
<br>
<ul class="ver">
  <li><a href="#">Lorem</a></li>
  <li><a href="#">Ipsum</a></li>
  <li class="selected"><a href="#">Sit amet</a></li>
  <li><a href="#">Consectetur</a></li>
</ul>

Upvotes: 4

Emke
Emke

Reputation: 357

Take a look at what I did for the horizontal list.

ul.hor {
    overflow: hidden;
    padding-bottom: 5px;
}

ul.hor li.selected a:after, 
ul.hor li.selected a:before {
    content: "";
    width: 1000%;
    height: 20px;
    position: absolute;
    left: 59px;
    bottom: -3px;
    border-bottom:3px solid blue;
    z-index: -1;
}
ul.hor li.selected a:after {
    left: auto;
    right: 58px;
}

Basically, don't add border for the ul, instead, add fake border to active element which is Really big. Hide overflow of the ul and voila!

'http://jsfiddle.net/wvs9o8oy/12/'

Upvotes: 1

Related Questions