2

First, I realize pseudo-elements aren't part of the DOM and thus can't be targeted with jQuery. I'm wondering if perhaps there's another way (pure css, or some creative use of jQuery) to set a property of an :after pseudo-element (border-width, in this case) to be dependent on the parent element's width.

I'm styling a navigation menu using the technique described in this article, but would like to have the triangular shaped part be the full width of the navigation element:

nav menu example

However, the navigation elements won't all or always be the same width, thus the need to set the border-width based on the parent element's width. Any suggestions on how to accomplish this?

Edit: added a jsfiddle demo: http://jsfiddle.net/bcAQc/1/

Note: for some reason, I had to just different values for top and left on the :after pseudo element in jsfiddle than on my site. On my site, and in the example article I linked above, top is set to 100% and left is set to 50%.

Community
  • 1
  • 1
Travis Northcutt
  • 24,666
  • 9
  • 42
  • 51
  • 3
    Would you please add your relevant HTML markup and CSS to the post so we can reproduce this? Perhaps take it a step further and set up a http://jsfiddle.net demo? I get what you're trying to do, but consider that wider navigation items will mean wider and *taller* triangles with this trick (they will not be aligned) OR it will mean different angles for each triangle. Please explain what you want to happen. – Wesley Murch Dec 28 '11 at 18:22
  • Updated OP with link to jsfiddle demo. I'd like to end up with different angles for each triangle, and consistent heights. – Travis Northcutt Dec 29 '11 at 16:18

2 Answers2

2

I think Scott is right on the money when he says:

CSS does not allow percentage values to generate border widths (which would be ideal in this situation.

Since you have this tagged "jquery", I assume you're open to jquery solutions? I'm afraid this may not be possible with just CSS, using the border/triangle trick. Of course javascript opens this is up to a ton of possible solutions, here's one:

Demo: http://jsfiddle.net/bcAQc/2/

$('a').each(function(){
    var self = $(this),
        width = (self.width() / 2) + 10; // +10 for <a> padding
    self.append('<span class="triangle" />');
    $('.triangle', self).css({
        'border-left-width' : width,
        'border-right-width' : width
    });
});
.triangle {
    position: absolute;
    border: 40px solid transparent;
    border-top-color: blue;
    display:block;
    top:20px;
    left: 0;
}

Although this seems to do what you want, I find the different angles in the demo make it look kind of ugly. If it was me, I would consider fixed-width list items: it would make this totally possible with just CSS and IMO would look a lot nicer.

Community
  • 1
  • 1
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
  • I did just end up going with fixed-width list items - having variable padding around the text definitely looks much better than variable angles on the pointed section. – Travis Northcutt Jan 09 '12 at 16:55
0

Since CSS does not allow percentage values to generate border widths (which would be ideal in this situation), I think your only solution is to dynamically write css rules (adding a style tag to the head element via JQuery) that then builds the width and height of your triangles based off of the widths of your nav tags at runtime.

I assume you would want the triangles to be equal height, which means they need to accommodate the height needed for the widest triangle. So something like the following, which is a combination real/pseudo code (though there are other ways of building the css rule), where you would need to set a class on each element of the navigation (this assumes the li element has been set to position: relative):

$("<style type='text/css'> 
 #Nav li:after { 
     content: ''; 
     display: block;
     width: 0;
     height: 0;
     position: absolute;
     top: 100%;
     left: 0;
     border-style: solid;
     border-color: transparent;
     border-top-color: blue; /* your desired color of the triangle */
     border-width: ??px; /* set this to the calculated value of your desired standard height; I believe it should be at least 25% of the width of the widest nav element */
 } 

 #Nav li.yourNavElement1Class:after {
     border-left-width: ??px;  /* 50% of NavElement1 width */
     border-right-width: ??px; /* 50% of NavElement1 width */
 }

 #Nav li.yourNavElement2Class:after {
     border-left-width: ??px;  /* 50% of NavElement2 width */
     border-right-width: ??px; /* 50% of NavElement2 width */
 }

 #Nav li.yourNavElementEtcClass:after {
     border-left-width: ??px;  /* 50% of NavElementEtc width */
     border-right-width: ??px; /* 50% of NavElementEtc width */
 }
 </style>").appendTo("head");

Note that this rule writing was based off the answer to this question: Create a CSS rule / class with jQuery at runtime, and there are other ways to bring about the rule creation.

Community
  • 1
  • 1
ScottS
  • 71,703
  • 13
  • 126
  • 146