Live CSS Interaction with Skewer

This evening Skewer gained support for live CSS. When editing CSS code, you can send your rules and declarations from the editing buffer to be applied in the open page in the browser. It makes experimenting with CSS really, really easy. The functionality is exposed through the familiar interaction keybindings, so if you’re already familiar with other Emacs interaction modes (SLIME, nREPL, Skewer, Geiser, Emacs Lisp), this should feel right at home.

To provide the keybindings in css-mode there’s a new minor mode, skewer-css-mode. CSS “expressions” are sent to the browser through the communication channel already provided by Skewer. It’s essentially an extension to Skewer: it could have been created without making any changes to Skewer itself.

Unfortunately Emacs’ css-mode is nowhere near as sophisticated as js2-mode — which reads in and exposes a full JavaScript AST. I had to write my own very primitive CSS parsing routines to tease things apart. It should generally be able to parse declarations and rules reasonably no matter how it’s indented, but it’s not very good at navigating around comments, especially when they contain CSS syntax. If I find a way to parse CSS more easily sometime I’ll see about fixing it, but it’s plenty good enough for now.

To “evaluate” the CSS, the code is simply dropped into the page as a new <style> tag. I had considered other approaches, but this seemed to be by far the simplest way to support arbitrary selectors and shorthand properties. The more programmatic approaches would require re-writing something that browser already does.

The consequence of this is that every “evaluation” adds a new <style> tag to the page, which adds more and more load to style computation, most of which completely mask each other. Since there’s no way to tell when a particular <style> tag has been completely masked I can’t remove any of them from the page. That might revert a declaration that’s still in usde. I haven’t seen it happen yet but I wonder if it’s possible to run into browser problems during extended CSS interaction, when thousands of stylesheets have built up on a single page. Time will tell.

Just before doing all this, I added full support for Cross-resource Resource Sharing (CORS), which means any page from any server can be skewered, not just pages hosted by Emacs itself … as long as you can get skewer.js in the page as a script. To help with that, I wrote a Greasemonkey userscript that can automatically skewer any visited page. I can now manipulate from Emacs the JavaScript and CSS of any page I visit in my browser. It feels really powerful. I already have a good use for this at work right now.

Have a comment on this article? Start a discussion in my public inbox by sending an email to ~skeeto/ [mailing list etiquette] , or see existing discussions.

null program

Chris Wellons (PGP)
~skeeto/ (view)