Monday, March 23, 2009

Making it large - and knowing about it

In my previous post (in which we reached a clear concensus that people do change the text size), I mentioned in passing that I had been experimenting with detection of user text resizing.

Why would you want to do this? Well, perhaps out of curiosity. More importantly, because you may wish to apply different styles, or a different layout, when the text is large (or enlargened). Now that we can safely assume users do change text size, this is pretty useful.

I've stumbled across various ways of doing this in the past, and it's not entirely straightforward. You do have to go round the houses a bit. And, it turns out, through the kitchens, out the back door, across the patio and over the back fence.

The first step is to find out what the text size is. This ain't too bad - put in an element with a width or height of 1EM and measure it's size (offsetHeight / offsetWidth). Ideally you want to do this before the page is fully rendered, so you can manage the outcome before it causes any visual shifts.

Only problem here is that Safari doesn't accurately measure dimensions until the page is fully rendered.

The second step
is to detect when the user changes text size. This is less trivial. It's not in the document, so the document has no access to this event. I've seen solutions which conducted regular polling. I don't like that. I did however once talk to a chap called Julian, who had a solution involving resize events fired by an iframe - the dimensions of which are set in EMs.

This I always thought rather elegant - so I thought I'd approach it myself. It also solved the Safari problem, because you can write a document to an iframe and have it fully rendered before the parent page is rendered. Subtle, but true.

There didn't seem to be a nice way to bind the resize event to the iframe and pass back to the parent script - I was hoping to go in via the DOM, but for some reason IE didn't treat that correctly and bound the event to the parent document (perhaps I was just missing something there). So I had to write in the JS via the main document.write(). Also, some types of positioning / display settings seemed to prevent any event being fired at all.

The result?

What you see below actually works - at least, where I've tested it (IE6, 7, FF 3 PC/Mac, Safari 3). It's not particularly tidy or elegant code, but that wasn't the point - I was just trying to see how reliably it could be done.

I may well be slipping it into a project in the near future, to see how it fares.




new (function() {
var me = this,
iframe = null,
el = null,
renderedTextSize = null,
settings = {
BASE_TEXT_SIZE: '75%'
},
frameContent = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'
+ '<html><head><style type="text/css">body {font-size: ' + settings.BASE_TEXT_SIZE + '}</style></head>'
+ '<scr'+'ipt type="text/javascript">'
+ 'function resize() {if (document.caller) document.caller();}'
+ '</scr'+'ipt>'
+ '<body onresize="resize()">'
+ '<body></html>';

var getUQID = function() {
return 'UQID' + (new Date().getTime());
};

var renderiFrame = function() {
var id = getUQID();

iframe = document.createElement('iframe');

iframe.style.width = '10em';
iframe.style.height = '10em';

iframe.name = id;
iframe.id = id;



var div = document.createElement('div');
div.appendChild(iframe);

document.body.appendChild(div);

div.style.position = 'relative';
div.style.left = '-1000em';
var wfd = window.frames[id].document;
wfd.open();
wfd.write(frameContent);
wfd.close();

wfd.caller = function() {onResize.call(me);};


el = wfd.createElement('div');
el.style.width = '1em';
el.style.height = '1em';
el.style.backgroundColor = '#ff0000';
wfd.body.appendChild(el);

};

// measures text size by adding element and measuring it;
var measureTextSize = function() {
if (!iframe) renderiFrame();

return el.offsetWidth;
};

var onResize = function() {
checkTextSize();
};

// checks text size and deals appropriately;
var checkTextSize = function() {
var measured = measureTextSize();
if (measured != renderedTextSize) {
// deal with adjustment;
renderedTextSize = measured;
if (window.ontextresize) window.ontextresize(renderedTextSize);
else if (window.onTextResize) window.onTextResize(renderedTextSize);
};
};


this.prod = function() {checkTextSize();};

var onReady = function() {checkTextSize.call(me);};
$(document).ready(onReady);
});


window.onTextResize = function(textsize) {
alert('text size = ' + textsize + 'px');
}



Thursday, March 12, 2009

Making it large

I've managed to amass a bunch of random thoughts about text sizing in browsers. We 'bust our asses' with EMs and other similar things, but these days it's not clear what the point is.

I have often wondered how many people actually use browser text sizing / zoom features. I had a chat with a colleague about this. She does user testing for AbilityNet, and her observation is that nobody changes text size in the browser. Anyone who needs larger text will have a big screen resolution, or different OS settings, or a screen magnifier. These days, she feels that scalable font coding is a waste of time - and this is based on working with users who have disabilities. Makes you think.

Another observation. I have heard rumours that IE8 respects pixel font sizes. For years people have grumbled about IE 'not scaling pixel font sizes'. This winds me up no end. Pixel font sizes shouldn't be scalable! They are PIXEL based sizes! IE is the only browser which has consistently respected the specification in this regard.

Do people really use browser zoom features? I use them to check my pages (making them pixel perfect, blah blah). But are they useful for users? I don't have the answer to that one. There aren't any metrics.

Regardless, yesterday I knocked up some code to detect user text size setting changes. It goes around a few hundred houses to do this reliably and usefully. May have been a waste of time.

Except that it could be used to capture usage metrics - on what size user text really is. That would be useful. If, of course, I can find a site where I can run it quietly in the background. I don't think my clients would be that keen.

While rambling, it's worth mentioning that Mr Clancey has a few things to say these days.

Welcome to the blogosphere, Patrick!

Wednesday, February 18, 2009

Yadda yadda yadda

I was having that old conversation with Mr Norton the other day about non-javascript styling and how to approach it. Yes, even now it still manages to cause debate. For some time now, I have used the "noscript hack" - wrapping an additional stylesheet declaration in a noscript tag, like so:

<noscript>
<link rel="stylesheet".../>
</noscript>


To me it's the most pragmatic approach, and the easiest to work with. One alternative is the anti-noscript (or "script hack"), where you write out an additional stylesheet declaration using document.write().

Which I don't like, because I like to build for the baseline and accommodate the edge-case, not the other way round.

Problem is, the "noscript hack" doesn't validate, and some people like validation. Some people are obsessed with it. Personally I'm not fussed with validation, or validators, or validationistas. Yadda yadda yadda. It can be a useful step, but sometimes I just want to breach the blancmange.

So, for the validationistas, I wanted a way to resolve the noscript issue without, for instance, reversing lots of CSS declarations and stomaching the attendant hassles. Hence the "noscript-sript hack", which, because it's only there to satisfy the validator, is called the "yadda yadda yadda hack".

<link id="noscriptCSS" rel="stylesheet".../>
<script type="text/javascript">
var el = document.getElementById('noscriptCSS');
el.parentNode.removeChild(el);
</script>

Do I think it's good?
No, not really. It's just a solution. A solution to a political problem, rather than a technical one.

I wouldn't engineer it into anything, but I would if desperate throw it in as a fix. Does it work? In my tests, yes. Norton warns that there may be a flicker. I haven't seen one. There shouldn't be, but I haven't hammered it very hard.

So, the "yadda yadda yadda hack". It works, and it's a dirty way to make a clean solution clean.

Thursday, January 8, 2009

A new dawn

Greetings, and welcome to 2009.

New years, it seems, are all about resolutions and blogging 'apologies for absence'. So, yes, I have been quiet. Things have been busy. Hopefully, they'll stay busy for quite a while.

In the meantime, I was rummaging through my photos and found this, which for me really sums up my 2008 - dawn breaking in Dunwich, after the Dynamo, and an unnamed cyclist.


Oh, and one more thing. the Rothko exhibition closes soon, and I command you all to pay a visit. It may not be the most comprehensive Rothko exhibition ever ('99 retrospective in NY, was larger I think). It may have taken the Tate's unfortunate obsession with thematic display to its logical, fatuous conclusion (Curator to Serota: "Hey, Nick, why don't we have a room full of grey paintings" - "Yes! Absolute genius!" - Serota punches air with fist - "High five!"). It may, even on a Friday evening, be more crowded than you'd want. But still. You won't see anything like this again. Not for a very long time. Maybe not ever. So go, while you still can!

Saturday, November 8, 2008

Boxing and the art of CSS design

Recently, I have spent way too much time thinking about CSS -

- and the vexing question of how to distill some design principles which are actually realistic and useful. Partly this comes from a project which has run to some hundreds of thousands of lines of code, many of which are redundant, duplicated or just plain bizarre. Partly it comes from a conversation some time ago with the esteemed Mr Norton about how to work collaboratively with CSS. A conversation which led to no satisfactory conclusion.

Even if you look on the web, there is little of use - even now, CSS guides haven't reached beyond endless revelations about faux columns, or masturbatory explorations of CSS3. Fun, perhaps, but not useful - particularly not in a real world business context.

Seeing outside the bockuss
So I started writing down some thoughts. And I haven't finished doing that yet. When I have finished, I may well try to write some articles on the matter. Where I'll talk about loose boxes, bounded and unbounded states, event horizons, and all manner of strange things.

Until then, I'll ramble on about a few thoughts which struck me:

Firstly, much of what I wrote didn't even reach the code itself - instead it talked about other things. Such as design analysis. CSS often fails simply because developers don't see the scope of a design until they are half way through a project.

And communication. Knowing what's been built already can save a lot of problems.

And testing processes. No matter how arrogant you feel about browsers, in a real-world project, *it is insane to ignore any target browsers during development, and attempt to patch the code for them later - for example, building in Firefox 3 and only fixing for IE6 later will cause you a world of pain*.

Secondly, I began to realise something interesting - much of what is preached as sound engineering practices - the sort of thing software engineers care about - simply don't make sense in a CSS world.

Take encapsulation, for instance. This is perfect for an OO language, but much of CSS is about defining globally applicable rules. If I gave two page components to two developers and found that they'd coded every rule from the browser-base level, and were not absorbing more generic styles, I would think it barmy.

Unit testing is another thing. I've been racking my brains as to how one could apply a unit-testing approach to CSS. It would be heaven - but I can't see a way of doing it in a practical sense. Even if all browsers did provide you with accurate ways to probe the rendered DOM ('what colour is this, how big is that text and what's it liine-height'), we're talking about a declarative world. So the test for a CSS rule ("all level 3 headings are green") would effectively be the same as the rule itself (h3 {color: green;}).

I'm not saying engineering practices are wrong, of course, I'm simply saying that we haven't yet reached a stage where there are sound engineering practices for CSS. We have some frameworks, which are useful in some contexts and not others. And countless attempts to work through apparent, and real, deficiencies (rounded corners, etc). But no defined practices, or approaches, which actually work well.

Despite the language having been around for years, meaningful CSS design is still, to all intents and purposes, in its infancy.

* nb. this sentence has been edited since original publication.