If you're thinking about using JavaScript, then this was my solution to the problem:
The idea is that your element with the text and the canvas
element
are one on top of the other. You keep the text in your element (in
order to allow text selection, which isn't possible with canvas
text), but make it completely transparent (with rgba(0,0,0,0)
, in
order to have the text visible in IE8 and older - that's because you
have no RGBa
support and no canvas
support in IE8 and older).
You then read the text inside your element and write it on the canvas
with the same font properties so that each letter you write on the
canvas is over the corresponding letter in the element with the text.
The canvas
element does not support multi-line text, so you'll have
to break the text into words and then keep adding words on a test line
which you then measure. If the width taken by the test line is bigger
than the maximum allowed width you can have for a line (you get that
maximum allowed width by reading the computed width of the element
with the text), then you write it on the canvas without the last word
added, you reset the test line to be that last word, and you increase
the y coordinate at which to write the next line by one line height
(which you also get from the computed styles of your element with the
text). With each line that you write, you also decrease the opacity of
the text with an appropriate step (this step being inversely
proportional to the average number of characters per line).
What you cannot do easily in this case is to justify text. It can be
done, but it gets a bit more complicated, meaning that you would have
to compute how wide should each step be and write the text word by
word rather than line by line.
Also, keep in mind that if your text container changes width as you
resize the window, then you'll have to clear the canvas and redraw the
text on it on each resize.
OK, the code:
HTML:
<article>
<h1>Interacting Spiral Galaxies NGC 2207/ IC 2163</h1>
<em class='timestamp'>February 4, 2004 09:00 AM</em>
<section class='article-content' id='art-cntnt'>
<canvas id='c' class='c'></canvas>In the direction of <!--and so on-->
</section>
</article>
CSS:
html {
background: url(moving.jpg) 0 0;
background-size: 200%;
font: 100%/1.3 Verdana, sans-serif;
animation: ani 4s infinite linear;
}
article {
width: 50em; /* tweak this ;) */
padding: .5em;
margin: 0 auto;
}
.article-content {
position: relative;
color: rgba(0,0,0,0);
/* add slash at the end to check they superimpose *
color: rgba(255,0,0,.5);/**/
}
.c {
position: absolute;
z-index: -1;
top: 0; left: 0;
}
@keyframes ani { to { background-position: 100% 0; } }
JavaScript:
var wrapText = function(ctxt, s, x, y, maxWidth, lineHeight) {
var words = s.split(' '), line = '',
testLine, metrics, testWidth, alpha = 1,
step = .8*maxWidth/ctxt.measureText(s).width;
for(var n = 0; n < words.length; n++) {
testLine = line + words[n] + ' ';
metrics = ctxt.measureText(testLine);
testWidth = metrics.width;
if(testWidth > maxWidth) {
ctxt.fillStyle = 'rgba(0,0,0,'+alpha+')';
alpha -= step;
ctxt.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
}
else line = testLine;
}
ctxt.fillStyle = 'rgba(0,0,0,'+alpha+')';
alpha -= step;
ctxt.fillText(line, x, y);
return y + lineHeight;
}
window.onload = function() {
var c = document.getElementById('c'),
ac = document.getElementById('art-cntnt'),
/* use currentStyle for IE9 */
styles = window.getComputedStyle(ac),
ctxt = c.getContext('2d'),
w = parseInt(styles.width.split('px')[0], 10),
h = parseInt(styles.height.split('px')[0], 10),
maxWidth = w,
lineHeight = parseInt(styles.lineHeight.split('px')[0], 10),
x = 0,
y = parseInt(styles.fontSize.split('px')[0], 10),
text = ac.innerHTML.split('</canvas>')[1];
c.width = w;
c.height = h;
ctxt.font = '1em Verdana, sans-serif';
wrapText(ctxt, text, x, y, maxWidth, lineHeight);
};