3

I know my title is not the best but I tried as best I could. It's a little hard for me to explain my problem, but what I want is to create a horizonal list that has a "triangle" in the active element. I show an image below. Example

It this possible with CSS? I know how I would do with jQuery but I want to use CSS now and no jQuery/Javascript.

I have actually created a fiddle which you can find a link to below:
http://jsfiddle.net/jackbillstrom/3dNcj/

I tried a javacript solution but wasn't satisfied with it because I would like to use CSS instead. My goal is to have that triangle as you can see in the example to "ease" between which <li> you click. Is this even possible or am I dreaming?

Jack
  • 3,632
  • 7
  • 45
  • 67
  • The example doesn't seem to have a JS implementation. Is this intentional? – Asad Saeeduddin Jun 26 '13 at 17:51
  • @Asad Yes, because I want to give it a shot with pure CSS – Jack Jun 26 '13 at 17:55
  • 2
    You could try the vintage technic by using a small picture as a background. See http://stackoverflow.com/a/7073558/1009061 for a CSS3 implementation. – David Bélanger Jun 26 '13 at 17:56
  • Would be perfect if I didn't want that "ease" effect :/ – Jack Jun 26 '13 at 17:58
  • @Jack Can you please elaborate on why you don't want to use JS? – Asad Saeeduddin Jun 26 '13 at 18:14
  • @Asad I don't believe in JS...Not just kidding, I want to push this project to the limit with as little JS as possible :) – Jack Jun 26 '13 at 18:15
  • Well, you're going to find yourself jumping through a lot of hoops, because there is only so much that can be accomplished with declarative layout. Having the freedom of imperative control over layout that JS provides will let you get things done with very little effort, but I guess if this is just on a whim/principle there isn't much I can say to change your mind. – Asad Saeeduddin Jun 26 '13 at 18:19
  • @Asad That comment, did in fact change my mind.. But it would still be something if we could get the answer to the CSS option :) – Jack Jun 26 '13 at 18:21
  • @Jack updated my answer to support pure css3 transitions, have a look, some js will be involved :) – painotpi Jun 26 '13 at 18:49
  • @Jack brentonstrine has managed to come up with an answer that uses no JS at all, which is what you were looking for. – Asad Saeeduddin Jun 26 '13 at 19:39

4 Answers4

9

Just add this to the bottom of your CSS:

ul#objects li {
    overflow: hidden;
    position: relative;
}
ul#objects li.active:after, ul#objects li:hover:after {
    content: "";
    position: absolute;
    width: 15px;
    height: 15px;
    background: #fff;
    box-shadow: 0 0 3px #666;
    transform: rotate(-45deg);
    top:5px;
    right: -8px;
}

JSFiddle Demo. No jQuery and you even get the hover effect for free.

Update 1: Here I used :target so that the arrow only shows up when you click on the element: JSFiddle Demo.

Update 2: Got it. CSS only solution where the arrow slides to follow the one you click on: JSFiddle Demo.

Update 3: And here it is updated so that the arrow slides when you hover as well as when you click. Hopefully you can see in the code that the clicking effect requires the :target code as well as the addition of the links in your HTML, but if you only want to do it with the :hover effect and then switch to the different page, you don't need the links I added to your HTML, you just need to add the .active class into the CSS where I have :target. Hopefully that makes sense. JSFiddle Demo.

brentonstrine
  • 21,694
  • 25
  • 74
  • 120
4

Is this what you want?

Some basic CSS to create the triangle,

.triangle{
    width: 0; 
    height: 0; 
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent; 

    border-right:10px solid white; 
    position: absolute;
    right: -1px;
    top: 10px;
}

A simple js using the .animate() to move the pointer,

$("li").click(function(){
    $this = $(this);
    $(".triangle").animate({
        top: $this.position().top + "px"
    });
});

Test Link

UPDATE

Using CSS3 transitions on browsers that support it, a bit of JS required to re-insert elements to restart the animations.

Brentonstrine has a better Pure CSS3 solution.

Test Link

painotpi
  • 6,894
  • 1
  • 37
  • 70
  • That is exactly what I want, but, isn't there a way with only CSS? – Jack Jun 26 '13 at 17:59
  • 2
    Let me try, give me some time :) only CSS(3) would not be supported on lower browsers btw. – painotpi Jun 26 '13 at 18:00
  • @Jack I think Jack you should have all versions: background, CSS3 and Javascript. You fall back from CSS3 > JS > Image – David Bélanger Jun 26 '13 at 18:05
  • 1
    Looks like we have a winner! I found this very hopeful and I think others will find this useful as well :D Cheers! – Jack Jun 26 '13 at 19:16
  • 1
    This isn't pure CSS3 at all. You're still using JS to slide the thing around. That said, I think JS is the only approach here. – Asad Saeeduddin Jun 26 '13 at 19:19
  • Yeah, I don't get it, this solution still uses JS. My solution is indeed pure CSS. – brentonstrine Jun 26 '13 at 19:22
  • @Asad and brentonstrine check this, http://jsfiddle.net/d3athR0n/3dNcj/13/, I've mentioned in a comment above that some JS will be used, in this case, just to re-insert the element, so the css animation restarts. It uses pure CSS3 to animate the `.triangle` however. Also, using a fallback for browsers that don't support css3 animations – painotpi Jun 26 '13 at 19:24
  • @badZoke, your solution doesn't work at all without Javascript, as far as I can tell. I deleted the JS from your example and it doesn't work. – brentonstrine Jun 26 '13 at 19:30
  • @brentonstrine it won't, that's what I've mentioned in my comment, my solution uses a bit of JS – painotpi Jun 26 '13 at 19:31
  • It's just confusing because you said "Using pure css3 on browsers that support it." – brentonstrine Jun 26 '13 at 19:34
  • @badZoke "Pure CSS" and "uses a bit of JS" are mutually exclusive. brentonstrine's is the correct answer here. – Asad Saeeduddin Jun 26 '13 at 19:37
  • 1
    Updated my answer to fix the ambiguity. – painotpi Jun 26 '13 at 19:38
  • Thanks for clearing the ambiguity. For the record, @badZoke's solution, while not "pure CSS", may still be a better solution for some people, since my solution depends on advanced CSS3 things that older browsers won't support. I'm an advocate of "graceful degradation"/"progressive enhancement" though, so basically, if people want to use old browsers, they can still use the website (no functionality is broken) but they don't get the full experience. – brentonstrine Jun 26 '13 at 19:50
4

Here is one way to accomplish this with pseudoelements. This uses pure CSS, but relies on CSS 3:

#objects > li:hover:after{
    content: ' ';
    border-color: transparent #fff transparent transparent;
    border-style: solid;
    border-width: 13px;
    position: absolute;
    right: 0px;
    top: 10px;
}
#objects > li:hover{
    position:relative;
}

Here is a demo: http://jsfiddle.net/wFege/

I've been racking my brains for a bit, but unfortunately can't think of any way to make this incorporate the "sliding" effect in badZoke's answer. Would you care to elaborate on why you can't use JS? If the problem is merely not wanting to include jQuery, you can accomplish the same thing with native JS.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
1

Asad's pure CSS solution is really good. I did a similar thing which makes a horizontal list (which you mentioned).

http://jsfiddle.net/teAPW/

ul, li {
    list-style:none;
    margin:0;
    padding:0;
}
li {
    display:inline-block;
    width:100px;
    height:100px;
    border:1px solid #AAA;
    border-left:none;
    text-align:center;
    line-height:100px;
    background:#DDD;
    color:#999;
    position:relative;
}
ul > li:first-child { border-left:1px solid #AAA; }
ul > li.active { border-right:none; }
ul > li.active + li { margin-left:10px; border-left:1px solid #AAA }
ul > li.active:after {
    position:absolute;
    top:40px;
    right:0;
    border:13px solid;
    border-color:transparent #FFF transparent transparent;
    content:"";
}
Ian Clark
  • 9,237
  • 4
  • 32
  • 49