CSS Secret Message Generator

Avatar of Chris Coyier
Chris Coyier on

I know ya’ll were just thinking to yourselves: man, I hope Chris posts some super nerdy article today with some nearly-useless technique that if I talked about in public would clinch the fact that I’m not getting laid anytime soon. Don’t worry, I got your back! Check out the CSS Secret Message Generator.

Using it is (I hope) fairly straightforward. You click some letters, then those are the letters which secretly reveal themselves when the text is selected.

There are a few interesting things worth touching on, so we’ll do that in this article.

The Big Idea

The empowering concept here is the fact that you can change the text selection color (and background-color) in modern browsers. WebKit and Chrome use ::selection { } and Mozilla uses ::-moz-selection { }.

In our example we wrap every single letter of a big block of text in a <span>. Then we have a little UI system for marking individual letters. All that does is toggle a specific class name on those spans. Non-marked spans have a color and background-color of white, which means they effectively disappear when selected. The marked spans change color. So when the whole block is highlighted, the secretly marked letters reveal themselves.

For the record, there is really not reason it’s laid out in a grid, other than it’s just kinda easier to click the letters and it looks more secret-message-y.

jQuery

Like about everything fancy we do around here, it uses jQuery. I’m not gonna do a code-dump. If you want to see the the whole thing, it’s only 85 lines fully commented.

I’ve done a couple of other grid-clicky things in the past and one thing I’ve always wanted to figure out (but never could) was a click-and-drag way to toggle cells. A way finally dawned on me…

I bound a “mousedown” event to the grid itself. When that fires, set some data to indicate that the mouse is currently down. Conversely, on “mouseup”, set that data to indicate the mouse is now up. Useless by itself, but then we can attach a “mouseenter” event to all the cells. If the mouse is “down” when that hover event happens, do the same toggling that would happen with a click. At the moment this only works for turning on cells (not mass-erasing), but it could probably be tweaked to do that too.

$("#grid")
    // clicking on a cell toggles the selected state in the grid and the demo
    .delegate("span", "click", function() {
        // get the first class only (the position), otherwise would fail when it has that plus "selected"
        attrTest = $(this).attr("class").split(" ")[0];
        $(this).toggleClass("selected");            
        $("#secret-message ." + attrTest).toggleClass("selected");
    })
    // if the mouse is currently pressed, set some data so we can check for that
    .bind("mousedown", function() {
        $(this).data("mouseIsDown", true)
    })
    // when the mouse comes back up, change data to say so
    .bind("mouseup", function() {
        $(this).data("mouseIsDown", false)
    })
    // allows the "drawing by dragging"...
    .delegate("span", "mouseenter", function() {
        // which is only allowed while the mouse is pressed down
        if ($("#grid").data("mouseIsDown")) {
             attrTest = $(this).attr("class");
             $(this).addClass("selected");            
             $("#secret-message ." + attrTest).toggleClass("selected"); 
        }
    });

WebKit doesn’t allow “none” backgrounds for text selection?

For the grid, because of the click-and-drag ability, I wanted to turn off highlighting in that area entirely (it’s just annoying while you are trying to “draw”). I set the text selection color the standard way, for both rendering engines. Firefox respects it, Opera respects it, but neither of the big WebKit browsers will.

#grid-area ::-moz-selection { background: none; } /* Works */
#grid-area ::selection { background: none; } /* Doesn't Work */

This may be some kind of bad-usability-prevention thing on WebKit’s part, but it seems more like a bug to me. If I specifically write CSS to eliminate background coloring on text selection, that’s what I want.