Hide leading characters with css

2015-01-18

I wanted to hide the http:// and https:// bits of a url when displayed. In context of a js1k demo it's quite irrelevant whether the link goes to a secure or insecure page. It'll never be a security related page.

So while doing that from JS is trivial, and from the server is a bit involved (though still trivial), I wanted to see whether I could just hack it in plain CSS. After all, I didn't mind the page having the http bit, I'd just be slightly happier if it wasn't shown at all.

I didn't want to go for the monospace hack. The monospace hack pretty much involves "guessing" the width of your characters and then applying a negative width and hope the prefix drops off. But it's the guessing that makes it ugly because I may not like showing the protocol, but showing small parts of a character is even worse. And confusing to the visitor (what's that dot hanging in the middle?).

However. At the time of writing there is no way and no planned way to do a substring in pure CSS. So you can't say anything like "show just the last 10 characters" or any variation thereof. It is possible to use an ellipsis in CSS these days. But that's not helping me because I was looking to hide some leading characters and I have a variable width anyways. The ellipsis will cut off after a set width and replace the rest with . I guess I wouldn't have wanted those dots there either, anyways.

So back to monospace. Turns out there actually is a monospace hack that's pretty solid for this case. I had totally forgotten about the ch CSS unit type. Thanks to @mahonnaise for pointing it out to me. The ch unit is the current width of the 0 character (details). So with a monospace font that means ch is the width of any character.

So to hide the first n characters of some text you can do this:

Code:
/* css */
div.link>a { overflow:hidden; }
div.link>a { font-family: monospace; margin-left: -8ch; margin-left:calc(.5px - 8ch); }
div.links>a { font-family:monospace; margin-left: -9ch; margin-left:calc(.5px - 9ch); }

<!-- html -->
<a href="http://js1k.com/1555">http://js1k.com/1555</a><br>
<a href="https://twitter.com/mahonnaise/status/556498196718166016">https://twitter.com/mahonnaise/status/556498196718166016</a><br>
<a href="weblog">weblog</a>

Quite elegant, as you can see in this fiddle :) It also shows that embedding in a text gets ugly though.

For my purpose I wanted to use it in a DL where the DT would float left and the DD would be a normal block (see same fiddle). For that case, this solution sufficed. It just needed overflow on the DD as well.

Code:
<style>
dt { float: left; width: 80px; }
dt:after { content: ":"; }
dd { overflow: hidden; }
dd>a[href^="http:"], dd>a[href^="https:"] { overflow:hidden; font-family: monospace; }
dd>a[href^="http:"] { margin-left: -7ch; margin-left:calc(.5px - 7ch); }
dd>a[href^="https:"] { margin-left: -8ch; margin-left:calc(.5px - 8ch); }
</style>

<dl>
<dt>Tree</dt>
<dd><a href="http://en.wikipedia.org/wiki/Tree">http://en.wikipedia.org/wiki/Tree</a></dd>

<dt>Woods</dt>
<dd><a href="https://en.wikipedia.org/wiki/Woods">https://en.wikipedia.org/wiki/Woods</a></dd>
</dl>


For regular texts it'll get a bit more involved. I'll leave that as an exercise for the reader ;)