6

If I've got elements like this:

<a href="something">A</a>
<a href="something_else">B</a>
<a href="something">A</a>
<a href="...">C</a>

I know I can use something like

body
{
    counter-reset:section;
}

a:before
{
    counter-increment:section;
    content:counter(section)". ";
}

to get

1. A
2. B
3. A
4. C

but is there a way to get the following?

1. A
2. B
1. A
3. C

ie. uniquely identify all links on a page by prefixing the text with the same number.

Note: hardcoding specific URLs isn't an option, I'm potentially dealing with hundreds of links and don't know the URLs ahead of time.

I realize this would be easy/possible with javascript, I am only interested in CSS-based solutions or an explanation of why this isn't possible with CSS.

Emory
  • 324
  • 3
  • 12

5 Answers5

2

I don't think you can get this behaviour with pure CSS, and you need Javascript. And there are always cases like this:

http://google.com/
http://google.com
google.com
google.com/
www.google.com

You get the point.


In jQuery this is quite trivial, so I'd suggest you use that.

orlp
  • 112,504
  • 36
  • 218
  • 315
2

Ok, I got what you mean with your question. Just with plain CSS it's not possible (at least not cross-platform..)

If you can use javascript, you have several possibilities.

My preference would be to use a data-attribute to hold the value, for this example I chose data-counter. If you do like this, the CSS becomes trivial:

CSS

a:before
{
   content:attr(data-counter)". ";
}​

And the Javascript would look like this if you have jQuery:

JS with jQuery

var linkcounter = {};
var counter = 0;
$("a").each(function() {
    if (!linkcounter.hasOwnProperty($(this).attr("href"))) {
        counter++;
        linkcounter[$(this).attr("href")] = counter;
    }
    $(this).attr("data-counter", linkcounter[$(this).attr("href")]);
});

​ or like this without jQuery:

vanilla JS

var linkcounter = {};
var counter = 0;
var anchors = document.getElementsByTagName('a');
for(var i = 0; i < anchors.length; i++) {
    if (!linkcounter.hasOwnProperty(anchors[i].getAttribute("href"))) {
        counter++;
        linkcounter[anchors[i].getAttribute("href")] = counter;
    }
    anchors[i].setAttribute("data-counter", linkcounter[anchors[i].getAttribute("href")]);
}

You can view the version without jQUery here: http://jsfiddle.net/ramsesoriginal/CVW7Y/5

And the version with jQuery here: http://jsfiddle.net/ramsesoriginal/CVW7Y/4

Sadly there is no CSS only way to do this (yet). I hope this helps. ​

ramsesoriginal
  • 1,860
  • 1
  • 13
  • 16
  • Thanks! As an aside, is there a way to hide duplicate links using CSS? If my results were 1. A, 2. B, 3. C that would be better than nothing (can't use JS.) – Emory Jul 17 '12 at 09:25
  • 1
    @Emory: You won't be able to unless the links are all contained in the same parent and you know the URLs beforehand. – BoltClock Jul 17 '12 at 09:28
  • Ok, well, I guess there's nothing left to do but mark this as solved and move on. Thanks @BoltClock! – Emory Jul 17 '12 at 09:30
  • @BoltClock nailed it: if they are in the same parent, and you know the links beforehand, you can work with `:first-child` and similar. You can also use `HTML Components` (http://msdn.microsoft.com/en-us/library/ms531018.aspx) you you are in a Internet-Explorer only environment.. but I would strongly recommend to stay away from such ugly solutions. – ramsesoriginal Jul 17 '12 at 09:34
0

You could use :contains but I'm not sure how supported it is so you might be better off with JavaScript.

a:contains("A") {
    /* Styles here */
}

a:contains("B") {
    /* Styles here */
}

EDIT:

Apparently :contains isn't supported at all. I'll leave this up here though so no one else bothers putting it.

You could use :contains in jQuery though and add a class accordingly.

$('a:contains(A)').addClass('CLASS_NAME');
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
SpaceBeers
  • 13,617
  • 6
  • 47
  • 61
  • 1
    `:contains()` is not supported at all (except some builds of KHTML which I don't think are in use anymore). – BoltClock Jul 17 '12 at 08:44
  • I appreciate the help, and I know jQuery is good tech, but I'm asking about CSS here =/ – Emory Jul 17 '12 at 08:55
  • Not a problem. I'm not sure it's possible so just providing an alternative if needed. – SpaceBeers Jul 17 '12 at 08:57
  • Cool, I just wanted people suggesting perfectly valid javascript-based solutions to understand why I'm not accepting answers yet! XD – Emory Jul 17 '12 at 09:01
  • @BoltClock, they even left an explicit *blank* entry where the `:contains` spec used to be, down at the W3C recommendations (also assigned with an eerie number, 'sup with that?) **: )** – Eliran Malka Jul 25 '12 at 18:17
  • @Eliran M. - Why did you edit this answer? From what I can see, all you've done is remove all lines of code and put them back! – techfoobar Jul 25 '12 at 18:41
  • @techfoobar - just added google-highlighter code comments (see the edit description) - i have a nasty habit of highlighting code even when it's a one-liner :) – Eliran Malka Jul 25 '12 at 18:46
  • 1
    @Eliran M.: Yes, you can still find a definition [here](http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#content-selectors) - in the same section number, [oddly enough](http://stackoverflow.com/questions/4781141/why-doesnt-the-selector-h3nth-child1containsa-work/4781167#comment-5294495). – BoltClock Jul 25 '12 at 18:56
0

If using jQuery is OK, this can be done by manipulating the :before pseudo element's content:

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

JS

var labels = [
    "1",
    "2",
    "1",
    "3"
    // and so on...    
];

// OR maybe put in some algo for this sequence

$('a').each(function(i) {
    $(this).attr('data-label', labels[i] + '. ');
});

CSS

a:before {
    content: attr(data-label);
    color: red;
    text-align: left;
    padding-right: 10px;
    font-size: 11px;
    display: inline;
}
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
techfoobar
  • 65,616
  • 14
  • 114
  • 135
  • @Eliran M. - Why did you edit this answer? From what I can see, all you've done is remove all lines of code and put them back! – techfoobar Jul 25 '12 at 18:41
-1

try this code:

var counter = 0, cache = {};
$('a').each(function (i, a) {
    a = $(a);
    var href = a.attr('href');
    var c = cache[href];
    if (!c) {
        counter++;
        c = counter;
        cache[href] = c;
    }
    a.text(c + '. ' + a.text());
});
​

I'm using jQuery, and that's how it works: http://jsfiddle.net/pDLbQ/

Pavel Reznikov
  • 2,968
  • 1
  • 18
  • 17