Posts tagged css
Book Review: Refactoring HTML
May 23rd
Despite years of progress by web standards advocates, and a significant improvement in the quality of the HTML on the web, many of us still end up grappling with outmoded, broken HTML on a regular basis. When confronted with a large site filled with broken pages it can be hard to know where to start. Elliotte Rusty Harold’s Refactoring HTML offers a step by step recipe book for migrating such sites to clean, semantic code.
Harold’s is a well known name in the XML world, and that background shows through in how he approaches the book. While a general audience will probably find useful content, the reader needs to be prepared for a series of command-line and Java-based examples. Tools like tidy are featured prominently, as is the use of regular expressions to seek out broken code to fix and, in the music-to-my-ears category, automated testing.
If you’re equipped to do so, following these steps will lead to much cleaner, more manageable sites, but I found myself wondering how many of those comfortable with command line tools and regular expressions are in the market for a book like this.
In general I suspect the key audience for this will be IT departments inside large organisations tasked with refreshing or extending an intranet. For those developers, who maybe don’t spend much of their time working with HTML and like the idea of using scripting tools similar to those in their regular workflow, this book’s worth a look. If you’re already familiar with current trends in web development, then there are probably other ways of picking up on the scattering of techniques that might be new to you.
Disclaimer: I was sent a copy of this book for review by the publisher. You can find it at amazon US, amazon UK and all sorts of other places.
Project Launch: New Greenbelt website
Apr 13th
One of the numerous projects I’ve been juggling over the past few months has been a redesign of the Greenbelt Festival website. That redesign went live late last night.
Working from Wilf‘s designs I initially built new HTML and CSS templates and began to establish some rules for how we’d handle the new image management requirements for a site that is now very photo-heavy. When it came time to apply the new designs to the CMS, however, it became apparent that there was a much bigger job ahead.
That CMS (a bundle of custom PHP that I had inherited) has grown over time and within some quite onerous server configuration constraints to a point where it was due a significant overhaul. Sticking with PHP was a fixed requirement as we’re relying on various APIs and a server architecture that wouldn’t be happy with me shifting to, say, rails, but already having the problem domain mapped out and the opportunity to radically simplify a few things meant I got to enjoy the feeling of stripping out a lot of code without impairing functionality.
One note that Derek Sivers made in his controversial blog entry last year about switching from Rails to PHP was that working with Rails had made him a better PHP developer. I’ve found a similar effect. I have no intention of leaving the world of Rails (I still prefer it by orders of magnitude), but tackling projects like this in PHP are a reminder that working for a while with really good tools is likely to encourage you to seek out best practice in whatever environment you end up in.
Ruby developers who occasionally work on PHP projects as I do may be interested to note that we are using capistrano for deployment, and I intend to use rspec for some testing. I’ll try to write that up once it’s in place.
With a refreshed CMS, new templates, and some standardisation of our many javascript files on top of a jquery foundation, Paul, Greenbelt’s was able to manage the photos and copy to turn that new look into a vibrant and content-rich new site. You can see a few notes he wrote about the redesign on the site.
There’s still a fair way to go. I’ve got a lot of tests to write in order to make it easier for us to make further changes, and various aspects of the site are more than ready for a more fundamental rethink that will let the festival open up its archives better, but all concerned are very pleased to present the fruit of our labours.
The fury that Microsoft have unleashed
Jan 24th
Such has been the flood of information since Aaron Gustafson broke the news of Microsoft’s radical new plans for Internet Explorer that I’ve mostly sat back and tried to absorb it all, waiting before contributing anything.
For those who haven’t been following the developments, Microsoft have said that future versions of Internet Explorer will support a new HTTP header and/or meta-tag which will indicate to the browser which version of IE the page is designed for. Unless the page specifies otherwise, all future versions of Internet Explorer will render it just like IE7 would. If you want IE8 to actually use the new features it brings with it, such as (we hope) improved standards support, you will need to explicitly ask it to do so.
There’s been a lot of response and people have fairly quickly become quite polarised. David Emery has a good list but a few I particularly noted were:
Eric Meyer and Jeffrey Zeldman explaining their support, Jeremy Keith suggesting that at the very least this is the wrong way round (the default should be the latest and greatest rendering engine), Drew McLellan (Web Standards Group Lead) pointing out that while members of the WaSP Microsoft Task Force had been involved in the initiative, this is not (currently) a WaSP-endorsed idea, comments from Ian Hickson,
and Sam Ruby and his commenting crowd considering the technical implications.
Reading all the debate it can be hard to separate feelings about this specific idea from a basic resentment against Microsoft that is harboured by most web developers I know. The failure of Internet Explorer to keep up with web standards has cost many of us, in aggregate, months of work, and our clients lots of money. The time we’ve spent supporting broken browsers could have been time spent improving the user experience or developing exciting new uses for the web. It feels very much as if the only way Microsoft can see to fix the mess they’ve created with their lacklustre browsers (and some very poor authoring tools) is to throw us a new type of confusion.
Regardless of it being Microsoft, though, even after reading all the debate I can’t help but feel that this is a very bad idea. Even if we get to the day that Internet Explorer 11 dominates and IE10 is the only other version used by a significant number of users, this would mean there would still be sites out there that are coded not to older standards than we may be used to, but to one of three or four older rendering engine and their unique set of bugs. That’s too much information for anyone to handle.
And then, of course, there’s the question of other web browsers. Sure, we can add a note that a site is designed for “safari 3, firefox 2.0, IE7 and Opera 9″, but that’s not a complete list even now. And we’re already seeing an explosion in the number of mobile devices, app-specific browsers, screen scrapers and other means of accessing the web. I find it hard to see this as anything other than a short-sighted form of browser lock-in.
So what should we do? Clearly the standards process is moving slowly and it’s taking browser developers several generations of their software to fully support the standards we do have. There’s already a lot of discussion of what should happen to the standards process to change that, but in the meantime I quite like the line of thought in David’s blog entry mentioned above suggesting we should have a way to test for support of various CSS properties. I’m not sure about the precise implementation details, but object detection got us a long way when we wanted to escape browser sniffing before, and maybe that’s still a fruitful line of enquiry?
Exploring Ruby CSS parsers: TamTam and CSSPool
Dec 5th
In response to yesterday’s post about inlining CSS for HTML emails, I got a couple of comments suggesting alternatives to my CSS parser class. Not wanting to have to maintain code unless I have to, I decided to give them both a try and see how they worked out.
TamTam
First up is TamTam, suggested by batnight. I’d actually spotted TamTam and link blogged it a few weeks ago, which shows how transient attention can be. TamTam is a complete solution for inlining CSS, so I should be able to replace all my code with:
require 'rubygems' require 'hpricot' require 'tamtam' inlined = TamTam.inline( :css => File.read('/path/to/my.css'), :body => File.read('/path/to/my.html') ) puts inlined
That looks ideal, but unfortunately as soon as I tried passing my code into it an error emerged.
/Library/Ruby/Gems/gems/tamtam-0.0.2/lib/tamtam.rb:77:in `apply_to': Trouble on style td#email-header-message on element <td id="email-header-message"> (Exception): can't convert nil into String from /Library/Ruby/Gems/gems/tamtam-0.0.2/lib/tamtam.rb:24:in `inline' </td>
Digging into the library it seems that its parsing fails if there’s a CSS rule that doesn’t match any elements in the document. That’s not a problem if your CSS file is targetted to a specific block of HTML, but if the idea is to build a set of rules that can be applied across a selection of page/emails that may be a problem.
CSSPool
CSSPool, suggested by Dan Kubb, is a more generic CSS parser which is designed to work with hpricot to map between CSS and HTML. Initially I just used something very much like the examples they offer to get a sense of the format of the objects they give access to:
require 'rubygems' require 'hpricot' require 'csspool' sac = CSS::SAC::Parser.new css_doc = sac.parse(File.read('/path/to/my.css')) html_doc = Hpricot.parse(File.read('/path/to/my.css')) css_doc.find_all_rules_matching(html_doc).each do |rule| puts rule end
Unfortunately this too failed on me with:
NoMethodError: undefined method `accept' for nil:NilClass
From a quick look at the source code it seemed that this error was occurring when a CSS selector didn’t match the supplied document, just as in TamTam. It turned out to be pretty easy to patch, though, and I’ve submitted a report in their tracker.
That done I was able to iterate over it and access the selectors easily enough, but what I’ve not yet been able to find is a way to get the parser to give me the actual CSS declarations appropriately formatted for including in the HTML. When I have a rule I can get the selector with:
rule.selector.to_css
But to find out what styles the selector applies isn’t so straightforward. If anyone has an easy way to do that, I’d love to hear about it in the comments!
Update (later that day): Version 0.2.3 of CSSPool is now out and includes my fix.
A little scripting to help with HTML email – bringing styles inline
Dec 4th
As anyone keeping an eye on my deli.cio.us feed may have noticed, quite a few links have appeared to information about the preparation of HTML email. It’s a nasty business, as a quick glance at the website of the email standards project will tell you. But sadly, nasty as it may be, sometimes it has to be done.
Even if the email I send out is going to have CSS scattered inline, for building the templates I’d much rather be able to focus on writing the structure of the document and leave worrying about my CSS for another time, and another file. That wouldn’t get me around the nastiness of having to use tables for anything but the simplest of layouts, but it still feels right to keep the separation for as long as possible.
I had a quick look for a tool that would take a stylesheet and an HTML document, and embed the rules online, but didn’t find one. So I turned to ruby. In theory it should be very easy to build something like this, because of hpricot‘s support for CSS selectors. If we had the CSS stored in a hash all it would take would be something like:
require 'hpricot' doc = Hpricot(open('my_page.html') css_as_hash.each do |selector, rule| (doc/selector).set('style', rule) end puts doc
Obviously that wouldn’t play nicely if there were already any styles inline, but for the purposes of this project I assumed there wouldn’t be.
I had a quick look at the cssparser rubygem but found that the sample code threw ‘method not found’ errors so I decided to quickly roll my own class that would take a path to a CSS file, and convert it to a hash. All it took was a few minutes’ work and the result was:
# This class takes a CSS file and provides a method to # parse it into a hash. Usage is: # # parser = SimpleCSSParser.new('/path/to/myfile.css') # hash_of_rules = parser.to_hash # # For more advanced CSS handling check out the cssparser gem # http://code.dunae.ca/css_parser/ class SimpleCSSParser # Receive and open the CSS file, storing its contents def initialize(path_to_file) @css = open(path_to_file).read end # Convert the CSS into a hash, where the keys are the selectors # and the values are the rules def to_hash @to_hash ||= separate_rules.inject({}) do |collection, rule| identifiers, rule = prepare_selectors_and_rule(rule) identifiers.each do |identifier| collection[identifier] ||= '' collection[identifier] += rule end collection end end private def separate_rules @css.split('}') end # Strip comments and extraneous white space from our CSS rules def clean_up_rule(css_rule) css_rule = css_rule.gsub(/\/\*.+?\*\//, '') css_rule.gsub(/\n|\s{2,}/, '') end # Break apart our selector(s) and rule. We return an array # of selectors to allow for situations where multiple selectors # are specified (comma separated) for a single rule def prepare_selectors_and_rule(rule) parts = rule.split('{') selectors = parts[0].split(',').map(&:strip) return selectors, clean_up_rule(parts[1]) end end
With that in place, I can now call:
require 'hpricot' doc = Hpricot(open('my_file.html')) parser = SimpleCSSParser.new('my_file.css') parser.to_hash.each do |selector, rule| (doc/selector).set('style', rule) end puts doc
and have the result I wanted all along. It’s rather brittle because of the way it splits the rules up, and it won’t pull in @include’d files, handle multiple CSS files, or do anything to honour the proper inheritance rules, but for my purposes that’s okay. I bundled it all up in a file that can be called from the command line. You can find that in this pastie.
A nice (and really quite simple) addition would be to take Campaign Monitor’s Guide to CSS Support in Email, parse it and spit out warnings about which email clients will have issues with which CSS rules. If I get round to implementing that I’ll blog about it here. If you get there before me, do post a comment and let me know.
UPDATE (5th Dec ’07: I’ve posted a follow-up looking at some other Ruby CSS parsers.