CodeinWP CodeinWP

CSS3 Attribute Selectors: Substring Matching

CSS3 Attribute Selectors: Substring MatchingThree of the attribute selectors in the CSS3 spec allow you to check the value the specified attribute for a string match. These attribute selectors are referred to as substring matching attribute selectors.

These can open endless possibilities, so I think it’s useful to have them in mind. And as a bonus, these selectors have strong support as far back as IE7, so pending thorough tests I think they are quite safe to use in many current projects.

Here’s a brief outline of each one, with some examples.

“Begins With” Attribute Selector

The first of these three attribute selectors lets you target an element in your CSS based on whether the attribute’s value begins with a given string. Here it is:

a[href^="http://"] {
  color: green;
}

This one uses the caret (^) character to tell the browser: “If this link has an href attribute that starts with http://, make it green.” Now, this specific example looks like an easy way to target external links.

But be careful, because if your CMS is adding your site’s URL to the beginning of certain links (like WordPress does), or if you’ve built your site with a “path” variable prepended to all links, then this would target all links that begin with “http://”, regardless of whether they are external or not. So this example might work only in specific circumstances.

To combat this, you might try:

a[href^="http://"] {
  color: green;
}

a[href^="http://www.domain.com"], a[href^="http://domain.com"] {
  color: blue;
}

But even this is not perfect, because it doesn’t target “https”. So testing is crucial. Nonetheless, this clearly illustrates what this attribute selector does, so you can use it where you think it fits.

Another important note: Don’t confuse this one with what’s been commonly referred to as the “language” attribute selector, which uses the vertical pipe character (|). That attribute selector will only match the specified string if it is at the start of the value and if it precedes a hyphen. This one is commonly used for matching values in the hreflang attribute on links.

“Ends With” Attribute Selector

This next one is exactly the opposite: You can target an element based on the ending of an attribute value. Here it is:

a[href$=".pdf"] {
  background: url(../images/pdf.png) no-repeat center right;
  padding-right: 20px;
}

This selector uses the dollar sign ($). Now we have what looks like a fairly reliable matching process. We know that all anchor elements that point to PDF documents are going to have the extension “.pdf”, so with this code we can add some right padding to those links and add a PDF icon to the link’s background.

“Contains” Attribute Selector

Finally, this selector targets elements based on any string match within an attribute value. So the specified string could occur anywhere in the value, not just at the beginning or the end.

div[class*="post-"] p {
  color: green;
}

The asterisk character (*) is well-known in computing as a wildcard character, so this one’s easy to remember.

The example I’m using may remind you of how WordPress sites attach a number of classes to specific elements, often with prefixes like “post-“. This might not be extremely practical, because usually there is another primary class with which to target the element. But again, it illustrates what can be done, and the type of values you’d be targeting with the wildcard character.

Got Any Use Cases?

Depending on how you build your app, your markup, and how you define certain attributes, the sky is really the limit with these selectors. I’d be glad to hear of any practical ways anyone has used these in their projects.

7 Responses

  1. found this very helpful, many thanks!

  2. Art says:

    for your http/https example you can double up selectors:

    
    a[href^="http"] {  
        color: green;  
    }  
      
    a[href^="http"][href*="://www.domain.com"], a[href^="http"][href*="://domain.com"] {  
        color: blue;  
    } 
    

    ^="http" will match http or https. *="://www.domain.com" and *="://domain.com" match your domains, although you could simplify this if you wanted to match all subdomains:

    
    a[href^="http"] {  
        color: green;  
    }  
      
    a[href^="http"][href*=".domain.com"] {  
        color: blue;  
    } 
    
    • Thomas says:

      This is problematic with URLs like http://someservice.com/recommend?url=http://domain.com (which are invalid, but still widely used).

      Another way is to use the not pseudo-class to exclude internal links

      
      a[href^="http"]:not([href^="http://domain.com"]):not([href^="http://www.domain.com"]):not([href^="https://domain.com"]):not([href^="https://www.domain.com"])
      
      • Art says:

        Good point on the improper matching of those invalid, but widely used, URLs.

        I see no easy way of excluding those, which means you’d have to list out every combination of http or https and any valid sub domains to exclude or include.

        Perhaps there’s a way I’m missing, but without wildcards I can’t think of how to exclude the URL as a parameter scenario.

  3. Ana says:

    Use case: different style for external links. Sometimes even showing the favicon of the website the link leads to – example.

  4. I’ve found attribute selectors and substring matching quite useful for SEO and HTML debugging purposes. For example you can target images without or with empty alt attribute (img:not([alt]) and img[alt=""]) or links with rel=nofollow (a[rel*="nofollow"]).

    You might find it interesting to read about how CSS can help with other issues like forgotten <title> or description: http://radiatingstar.com/how-to-improve-seo-with-css

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).