Reading Blinds — a YUI-powered Reading Tool
September 30, 2008 at 12:57 pm by Christian Heilmann | In Accessibility, Development | 10 CommentsEver since I got upgraded to a shiny Macbook Pro and a 24 inch monitor at work I had a web experience that differed a lot from what I had before. Web sites that were easy and nice to read out of a sudden showed a massive amount of white space that actually hurt my eyes. Talking to several people with visual impairments and dyslexia at Scripting Enabled confirmed me that this can be a real issue.
This is why I thought of writing a small script that can be used as a bookmarklet to cover the screen with a dark overlay and only shows a few lines at a time. That way you can concentrate on the bit you are reading at the moment and the rest of the screen does not bother you too much.
Following are two screenshots of the same site with and without reading blinds:


So how to build that?
The task of building a tool like that is actually pretty easy:
- create two DIVs with black background and 85% opacity
- position them fixed to the top and the bottom of the screen
- set their height to 10% and 70% to leave a gap
Then I thought that I should be able to move the highlight on the page. For this I needed a bit more sophistication:
- Detect the mouse cursor position
- Make the top div span from the current top of the document to a few pixels above the cursor position
- Make the bottom div span from a few pixels below the current cursor position to the bottom of the viewport
I could have had a go at it myself, but I don’t want to end in browser inconsistency hell, hence I use YUI.
Here’s the code:
var readingblinds = function(){
var visible = true;
var y,top,bottom;
var info = true;
var size = 70;
function generate(){
top = document.createElement('div');
bottom = document.createElement('div');
document.body.appendChild(top);
document.body.appendChild(bottom);
styleTopBottom();
var message = document.createElement('div');
var note = document.createTextNode(
'Reading Blinds - ' +
'move mouse to highlight section to read. '
);
message.appendChild(note);
top.appendChild(message);
styleMessage(message);
YAHOO.util.Event.on(document, "mousemove", move);
};
function move(e){
y = YAHOO.util.Event.getXY(e);
if(y[1] > size){
render(y);
}
};
function render(y){
var real = y[1]-YAHOO.util.Dom.getDocumentScrollTop();
YAHOO.util.Dom.setStyle(top,'height',real-size+'px');
var h = YAHOO.util.Dom.getViewportHeight()-real+size;
YAHOO.util.Dom.setStyle(bottom,'top',real+size+'px');
YAHOO.util.Dom.setStyle(bottom,'height',h + 'px');
};
function styleMessage(message){
YAHOO.util.Dom.setStyle(message,'font-size','80%');
YAHOO.util.Dom.setStyle(message,'text-align','right');
YAHOO.util.Dom.setStyle(message,'padding','5px');
YAHOO.util.Dom.setStyle(message,'font-family','verdana,sans-serif');
YAHOO.util.Dom.setStyle(message,'color','white');
}
function styleTopBottom(){
YAHOO.util.Dom.batch([top,bottom],function(o){
YAHOO.util.Dom.setStyle(o,'background','#000');
YAHOO.util.Dom.setStyle(o,'width','100%');
YAHOO.util.Dom.setStyle(o,'position','fixed');
YAHOO.util.Dom.setStyle(o,'left','0');
YAHOO.util.Dom.setStyle(o,'height','10%');
YAHOO.util.Dom.setStyle(o,'opacity','.85');
YAHOO.util.Dom.setStyle(o,'overflow','hidden');
});
YAHOO.util.Dom.setStyle(top,'top','0');
YAHOO.util.Dom.setStyle(bottom,'bottom',0);
YAHOO.util.Dom.setStyle(bottom,'height','70%');
};
return{
init:generate
}
}();
readingblinds.init();
The interesting methods are move() and render(); the rest is more or less run-of-the-mill DOM scripting.
The move() method is an event handler that gets called by any mousemove event on the document. YUI’s Dom Collection then makes it easy for me to get the current mouse cursor position with getXY() and I just need to make sure that the mouse is low enough in the browser window to not cause a negative height on the top div.
The render() method then sets the appropriate heights. I determine the upper border of the browser with getDocumentScrollTop() and substract that one from the cursor position. To determine where to end the bottom div I use getViewPortHeight().
Addding dazzle with keyboard controls
This was cool enough, but I wanted to be able to turn the blinds on and off and change the size of the visible part with the keyboard, too. For this, I needed to use the keylistener utility some tool methods to resize the gap or show and hide both of the cover divs. The resizing methods needed to get some boundaries to avoid div overlap or the whole viewport to be uncovered.
var readingblinds = function(){
var visible = true;
var y,top,bottom;
var info = true;
var size = 70;
function generate(){
top = document.createElement('div');
bottom = document.createElement('div');
document.body.appendChild(top);
document.body.appendChild(bottom);
styleTopBottom();
var message = document.createElement('div');
var note = document.createTextNode(
'Reading Blinds - ' +
'move mouse to highlight section to read. ' +
'Press "b" to show and hide, "s" to decrease size,' +
' "l" to increase size'
);
message.appendChild(note);
top.appendChild(message);
styleMessage(message);
var keyspy = new YAHOO.util.KeyListener(
document,
{ keys:66 },
{ fn:peekaboo }
);
keyspy.enable();
var keyspy2 = new YAHOO.util.KeyListener(
document,
{ keys:83 },
{ fn:smaller }
);
keyspy2.enable();
var keyspy3 = new YAHOO.util.KeyListener(
document,
{ keys:76 },
{ fn:larger }
);
keyspy3.enable();
YAHOO.util.Event.on(document, "mousemove", move);
};
function move(e){
y = YAHOO.util.Event.getXY(e);
if(y[1] > size){
render(y);
}
};
function render(y){
var real = y[1]-YAHOO.util.Dom.getDocumentScrollTop();
YAHOO.util.Dom.setStyle(top,'height',real-size+'px');
YAHOO.util.Dom.setStyle(bottom,'top',real+size+'px');
var h = YAHOO.util.Dom.getViewportHeight()-real+size;
YAHOO.util.Dom.setStyle(bottom,'height',h + 'px');
};
function styleMessage(message){
YAHOO.util.Dom.setStyle(message,'font-size','80%');
YAHOO.util.Dom.setStyle(message,'text-align','right');
YAHOO.util.Dom.setStyle(message,'padding','5px');
YAHOO.util.Dom.setStyle(message,'font-family','verdana,sans-serif');
YAHOO.util.Dom.setStyle(message,'color','white');
}
function styleTopBottom(){
YAHOO.util.Dom.batch([top,bottom],function(o){
YAHOO.util.Dom.setStyle(o,'background','#000');
YAHOO.util.Dom.setStyle(o,'width','100%');
YAHOO.util.Dom.setStyle(o,'position','fixed');
YAHOO.util.Dom.setStyle(o,'left','0');
YAHOO.util.Dom.setStyle(o,'height','10%');
YAHOO.util.Dom.setStyle(o,'opacity','.85');
YAHOO.util.Dom.setStyle(o,'overflow','hidden');
});
YAHOO.util.Dom.setStyle(top,'top','0');
YAHOO.util.Dom.setStyle(bottom,'bottom',0);
YAHOO.util.Dom.setStyle(bottom,'height','70%');
};
function peekaboo(){
if(visible === true){
YAHOO.util.Dom.setStyle(top,'display','none');
YAHOO.util.Dom.setStyle(bottom,'display','none');
visible = false;
} else {
YAHOO.util.Dom.setStyle(top,'display','block');
YAHOO.util.Dom.setStyle(bottom,'display','block');
visible = true;
}
};
function smaller(){
if(size > 10){
size -= 5;
render(y);
}
};
function larger(){
if(size < YAHOO.util.Dom.getViewportHeight()/2){
size += 5;
render(y);
}
};
return{
init:generate
}
}();
readingblinds.init();
That was pretty cool already, but as I wanted to make reading blinds a single script include or bookmarklet I had the problem of relying on the YUI. Well, there is a trick to conjure YUI from thin air by using the YAHOO_config object with the listener method creating a script node to get the YUI Loader.
So instead of calling readingblinds.init() directly, I used the following magic YUI trick:
if(typeof YAHOO=="undefined"||!YAHOO){
YAHOO_config = function(){
var s = document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src','http://yui.yahooapis.com/2.5.2/'+
'build/yuiloader/yuiloader-beta-min.js');
document.getElementsByTagName('head')[0].appendChild(s);
return{
listener:function(o){
if(o.name === 'get'){
window.setTimeout(YAHOO_config.ready,1);
}
},
ready:function(){
var loader = new YAHOO.util.YUILoader();
var dependencies = ['yahoo','dom','event'];
loader.require(dependencies);
loader.loadOptional = true;
loader.insert({
onSuccess:function(){
readingblinds.init();
}
});
}
};
}();
} else {
readingblinds.init();
}
That’s the lot. You can download readingblinds.js and include it in your site, or you can drag the following link to your links toolbar: Reading Blinds.
Share and extend: Bookmark with Yahoo! My Web | Bookmark with del.icio.us | digg it! | reddit!
10 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a comment

Copyright © 2006-2010 Yahoo! Inc. All rights reserved. Privacy Policy - Terms of Service
Powered by WordPress on Yahoo! Web Hosting.

Christian, most people with those big display’s don’t full screen the browser. Not only does it make websites way too wide, it can also make sites with relative width’s end up being wide enough to make it challenging to scan from one line to the next, hence why newspapers have very narrow columns. Typical sites are build around 1024 pixels wide, so if you set your browser at a more realistic width, and then make your desktop a darker color you’d be golden. But anyway, nice job on the bookmarklet, those are always very cool to see.
Comment by SeanBlader — September 30, 2008 #
That just solved one of my problem. Thanks!
I prefer to differ from “SeanBlader” because its not just about big screen size. I really feel the pain in my eyes when I read a lot of webpages in their white background. I just used this for a while and I can see a huge difference.
One small suggestion, I think the blinds should get disabled when you’re in a text area, I just experienced it going on and off when I typed this comment ;)
Comment by Manoj — September 30, 2008 #
Manoj, good catch! This is really annoying. Tricky though. I guess I can turn off the keyboard detect while you are in a form field.
Comment by Chris Heilmann — September 30, 2008 #
@manoy the easiest is to change the code for showing and hiding the blinds to ESC instead of b. The change is:
var keyspy = new YAHOO.util.KeyListener(document,
{ keys:27 },
{ fn:peekaboo }
);
Comment by Chris Heilmann — October 1, 2008 #
Very nice. Thanks for this. Also, changing the opacity using the keyboard would be handy.
Comment by NICCAI — October 1, 2008 #
[...] If you’ve ever had trouble concentrating on a piece of text in a vast sea of white space, try closing the blinds, using some awesome YUI magic. Chris Heilmann goes into meticulously gory detail in the linked [...]
Pingback by Yahoo! Cool thing of the Day » Blog Archive » Going blinds — October 3, 2008 #
[...] 地址在这里:reading blinds [...]
Pingback by 阅读大量长篇么?让它保护你的眼睛吧-[Reading Blinds] - GENMICHA | 趣站酷软 — October 4, 2008 #
[...] 地址在这里:reading blinds [...]
Pingback by 阅读大量长篇么?让它保护你的眼睛吧-[Reading Blinds] - 山歌好比春江水 — October 7, 2008 #
On a Mac try pressing ctrl-alt-apple-8 and the screen colours invert making reading much easier on the eyes.
Comment by John — October 7, 2008 #
I am using Vimperator, an add-in for Firefox. To pass keys from Vimperator, I need to enable its “PASS THROUGH” mode. Esc key is for quitting the mode. Therefore, Esc key is not the option.
Actually, just refreshing the web page will remove the injected scripts reading blinds codes.
Comment by David Chu — April 13, 2009 #