How to target alternate odd/even text lines
Demo 1
http://jsfiddle.net/Fptq2/2/
Should work in all modern browsers.
Essentially it:
- Splits the source into individual words once
- Wraps each word in a span (ugly but effective-any style can now be applied to the span)
- Uses a simple position calculation to determine if the element is lower than the previous
- Changes colors based on index change
- Performs #3-5 on resize (this should definitely be throttled!)
$(".stripe").each(function(){
var obj = $(this);
var html = obj.html().replace(/(\S+\s*)/g, "<span>$1</span>");
obj.html(html);
});
function highlight(){
var offset = 0;
var colorIndex = 0;
var colors = ["#eee","#000"];
var spans = $(".stripe span");
// note the direct DOM usage here (no jQuery) for performance
for(var i = 0; i < spans.length; i++){
var newOffset = spans[i].offsetTop;
if(newOffset !== offset){
colorIndex = colorIndex === 0 ? 1 : 0;
offset = newOffset;
}
spans[i].style.color = colors[colorIndex];
}
}
highlight();
$(window).on("resize", highlight);
Demo 2
Fiddle: http://jsfiddle.net/Fptq2/4/
- Uses a larger block of text
- Shows effect applied to multiple elements
- Caches the "all spans" selector
- Adds resize throttling
(function () {
$(".stripe").each(function () {
var obj = $(this);
var html = obj.html().replace(/(\S+\s*)/g, "<span>$1</span>");
obj.html(html);
});
var offset = 0;
var colorIndex = 0;
var colors = ["#ccc", "#000"];
var spans = $(".stripe span");
function highlight() {
for (var i = 0; i < spans.length; i++) {
var newOffset = spans[i].offsetTop;
if (newOffset !== offset) {
colorIndex = colorIndex === 0 ? 1 : 0;
offset = newOffset;
}
spans[i].style.color = colors[colorIndex];
}
}
highlight(); // initial highlighting
var timeout;
function throttle(){
window.clearTimeout(timeout);
timeout = window.setTimeout(highlight, 100);
}
$(window).on("resize", throttle);
})();
Output
Here is one possible solution. It generates a number of <div>
elements that are placed behind the text. <div>
elements inherit font size from the parent container, so the markup shouldn't be damaged.
HTML:
<div id="test">Lorem ipsum ...</div>
JavaScript:
var div = document.getElementById("test"),
layer = document.createElement("div"),
text = div.innerHTML,
lineHeight;
layer.appendChild(document.createTextNode("\u00A0"));
div.insertBefore(layer, div.firstChild);
lineHeight = layer.offsetHeight;
div.style.position = "relative";
div.style.overflow = "hidden";
div.style.color = "transparent";
layer.style.position = "absolute";
layer.style.zIndex = "-1";
window.addEventListener("resize", (function highlight() {
while (layer.firstChild)
layer.removeChild(layer.firstChild);
for (var i = 0, n = Math.ceil(div.offsetHeight / lineHeight); i < n; i++) {
var line = document.createElement("div"),
block = document.createElement("div");
line.style.height = lineHeight + "px";
line.style.color = i % 2 ? "#ccc" : "#aaa";
line.style.overflow = "hidden";
block.innerHTML = text;
block.style.marginTop = -i * lineHeight + "px";
line.appendChild(block);
layer.appendChild(line);
}
return highlight;
})(), false);
DEMO: http://jsfiddle.net/M3pdy/2/