Search code examples
htmlcsscolorswebfonts

Multiple colours for one element


I'm writing a site where the logo's going to be a word where the middle characters are a different colour to the outer ones; e.g.

<style type="text/css" media="screen>
    .logoG { color:blue; }
    .logoGo { color:red; }
    .logoGoo { color:yellow; }
    .logoGoog { color:blue; }
    .logoGoogl { color:green; }
    .logoGoogle { color:red; }
</style>
<span class="logoG">G</span><span class="logoGo">o</span><span class="logoGoo">o</span><span class="logoGoog">g</span><span class="logoGoogl">l</span><span class="logoGoogle">e</span>

I want to keep the text as text; not use image substitution tricks to hide the text and replace it with a logo background image. i.e. I want the HTML to look like this:

<span class="logo">Google</span>

...and for the CSS to do the hard work by doing something along the lines of:

logo {visibility: none;}
logo:after {visibility: visible; content: "G"; color:blue;}
logo:after:after {content: "o"; color:red;}
logo:after:after:after {content: "o"; color:yellow;}
logo:after:after:after:after {content: "g"; color:blue;}
logo:after:after:after:after:after {content: "l"; color:green;}
logo:after:after:after:after:after:after {content: "e"; color:red;}

...or better yet:

logo:first-letter  {color:blue;}
logo:nth-letter[2] {color:red;}
logo:nth-letter[3] {color:yellow;}
logo:nth-letter[4] {color:blue;}
logo:nth-letter[5] {color:green;}
logo:nth-letter[6] {color:red;}

So far the closest trick I've found is this trick for rainbow text: http://rainbowcoding.com/how-to-create-rainbow-text-in-html-css-javascript/

I'd also ideally like this solution to avoid javascript if possible; too much?

UPDATE

Here's some sample code which works based on hacking the rainbow - however the moment you resize the text (e.g. ctrl + +) it quickly breaks.

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
  <title>Google Demo</title>
  <style type="text/css" media="screen">
    h1 {
        background-image:-webkit-gradient( 
        linear, left top, right top
        , color-stop(0, blue)
        , color-stop(0.018, blue)
        , color-stop(0.018, red)
        , color-stop(0.030, red)
        , color-stop(0.030, yellow)
        , color-stop(0.040, yellow)
        , color-stop(0.040, blue)
        , color-stop(0.054, blue)
        , color-stop(0.054, green)
        , color-stop(0.058, green)
        , color-stop(0.059, red)
        , color-stop(0.108, red)
        );
        color:transparent;
        -webkit-background-clip: text;      
    }
  </style>
</head>
<body lang="en-US">
<h1>Google</h1>
</body>
</html>

Solution

  • A pure CSS solution is to use a gradient background colour to

    • create your rainbow (background-image: linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red);)
    • use -webkit-background-clip: text; to apply this background only behind text (the actual characters; not the non-character pixels around them)
    • make the text transparent (color: transparent;) so that you can see the background behind those characters.
    • Ensure the width of the background matches the width of the text; since if the gradient takes the full page width whilst the text is just a few chars on the left of the page, you'll only see the left-most colour(s). This can be done via width: fit-content;.
    .rainbow-text {
      background-image: linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red);
      -webkit-background-clip: text;
      color: transparent;
      width: fit-content;
    }
    

    Details and example here: https://w3bits.com/rainbow-text/

    Note: This isn't one colour per character; rather it's a continuous gradient of colours through all characters


    ps. Here's a javascript version for anyone with a similar issue but no js concerns. This uses Jesse's trick of nth child alongside some code to put the relevant tags in play.

    <!DOCTYPE html>
    <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      <title>Google Demo</title>
      <style type="text/css" media="screen">
        h1 .x:nth-child(1) { color: blue; }
        h1 .x:nth-child(2) { color: red; }
        h1 .x:nth-child(3) { color: yellow; }
        h1 .x:nth-child(4) { color: blue; }
        h1 .x:nth-child(5) { color: green; }
        h1 .x:nth-child(6) { color: red; }
      </style>
      <script type="text/javascript" charset="utf-8">
        function fancy() {
            var h1s = document.getElementsByTagName('h1');
            for(var i = 0; i < h1s.length; i++) {
                var h1Text = h1s[i].innerText;
                var h1InnerHTML = '';
                for(var j = 0; j < h1Text.length; j++) {
                    h1InnerHTML += '<span class="x">' + h1Text[j] + '</span>'; //nb: innerHTML is a dodgy hack, but fine for demos / works in Chrome
                }
                h1s[i].innerHTML = h1InnerHTML;
            }
        }
      </script>
    </head>
    <body lang="en-US" onload="fancy();">
        <h1>Google</h1>
    </body>
    </html>