Journal tags: painting

2

Speedier tunes

I wrote a little while back about improving performance on The Session by reducing runtime JavaScript in favour of caching on the server. This is on the pages for tunes, where the SVGs for the sheetmusic are now inlined instead of being generated on the fly.

It worked. But I also wrote:

A page like that with lots of sheetmusic and plenty of comments is going to have a hefty page weight and a large DOM size. I’ve still got a fair bit of main-thread work happening, but now the bulk of it is style and layout, whereas previously I had the JavaScript overhead on top of that.

Take a tune like Out On The Ocean. It has 27 settings. That’s a lot of SVG markup that needs to be parsed, styled and rendered, even if it’s inline.

Then I remembered a very handy CSS property called content-visibility:

It enables the user agent to skip an element’s rendering work (including layout and painting) until it is needed — which makes the initial page load much faster.

Sounds great! But there are two gotchas.

The first gotcha is that if a browser doesn’t paint the element, it doesn’t know how much space the element should take up. So you need to provide dimensions. At the very least you need to provide a height value. Otherwise when the element comes into view and gets rendered, it pushes down on the content below it. You’d see a sudden jump in the scrollbar position.

The solution is to provide a value for contain-intrinsic-size. If your content is dynamic—from, say, a CMS—then you’re out of luck. You don’t know how long the content is.

Luckily, in my case, I could take a stab at it. I know how many lines of sheetmusic there are for each tune setting. Each line takes up roughly the same amount of space. If I multiply that amount of space by the number of lines then I’ve got a pretty good approximation of the height of the sheetmusic. I apply this with the contain-intrinsic-block-size property.

So each piece of sheetmusic has an inline style attribute with declarations like this:

content-visibility: auto;
contain-intrinsic-block-size: 380px;

It works a treat. I did a before-and-after check with pagespeed insights on the page for Out On The Ocean. The “style and layout” part of the main thread work went down considerably. Total blocking time went from more than 600 milliseconds to less than 400 milliseconds.

Not a bad result for a little bit of CSS!

I said there was a second gotcha. That’s browser support.

Right now content-visibility is only supported in Chrome and Edge. But that’s okay. This is a progressive enhancement. Adding this CSS has no detrimental effect on the browsers that don’t understand it (and when they do ship support for it, it’ll just start working). I’ve said it before and I’ll say it again: the forgiving error-parsing in HTML and CSS is a killer feature of the web. Browsers just ignore what they don’t understand. That’s what makes progressive enhancement like this possible.

And actually, there’s something you can do for all browsers. Even browsers that don’t support content-visibility still understand containment. So they’ll understand contain-intrinsic-size. Pair that with a contain declaration like this to tell the browser that this chunk of content isn’t going to reflow or get repainted:

contain: layout paint;

Here’s what MDN says about contain:

The contain CSS property indicates that an element and its contents are, as much as possible, independent from the rest of the document tree. Containment enables isolating a subsection of the DOM, providing performance benefits by limiting calculations of layout, style, paint, size, or any combination to a DOM subtree rather than the entire page.

So if you’ve got a chunk of static content, you might as well apply contain to it.

Again, not bad for a little bit of CSS!

Paint

I was in London again today. A team from Clearleft have their sprint playbacks every second Tuesday at the client’s offices on The Strand. I tag along for the ride, and to marvel at the quality of the work being produced in each sprint. Then I duck out when it’s time for them to plan the next sprint—I don’t want to be the extra cook that spoils that particular broth.

Usually I would just head straight back to Brighton, nice and early, avoiding the after-work rush. But today was such a beautiful, crisp, clear winter’s day that I tarried a while. Instead of hopping on the tube back to Victoria, I perambulated.

At Trafalgar Square, I marvelled at the fact that the National Gallery is right there, free to the public. I could just walk right in and admire one of the world’s finest collections of art. So I did.

One minute I was on a typical London street, complete with obligatory Pret a Manger and Costa Coffee. The next I was standing in front of a Caravaggio, marvelling once again at his use of light—like Renaissance film noir.

Turner, Van Gogh, Seurat, Cézanne; all there for everybody to enjoy. As I stood in front of the Holbein—stepping between the school children to find just the right spot for the skull’s optical illusion—I remembered a conversation I had with Alla just last week.

We were discussing responsive design. I was making the case that there should be parity between small screens and large when it came to accessing content. “But”, said Alla, “what about the emotional impact?” Is it even possible to get the same “wow” factor on a handheld screen that you can get with a wider canvas? She asked me if I had ever had an emotional response to seeing something in an art gallery. I smiled, because her question made her point perfectly. Then I told her about the first time I ever went to the Louvre.

It was my first time ever being in Paris. I wasn’t even supposed to be there. It was the early nineties and I was hitch-hiking around Europe, trying my best to avoid big cities—they’re less than ideal when you have no place to sleep. But through a series of circumstances that probably involved too much wine, I found myself taking a ride into the capital and getting dropped in the middle of the city.

It all worked out okay though. Through an astronomical coincidence, I met someone I knew who put me up for a few nights.

I was standing in Châtelet metro station in the middle of rush hour. Whatever effect that wine had on me was wearing off, and I was beginning to realise what a terrible mistake I had made in coming to Paris. I was studying a city map on the wall, looking for areas of green where I might unroll a sleeping bag in peace, when I heard someone shout “Jeremy!” It was a girl from back home in Cork that I knew through a mutual friend in art college. She was working at Euro Disney for the summer and having finished her day’s work, she missed her metro stop and was switching trains. She just happened to be there at just the right time to take me in.

But that’s not the story I told Alla. I told Alla about what happened during that time in Paris when I busked up enough money to go the Louvre.

I walked in and saw Géricault’s The Raft Of The Medusa. I felt like somebody had punched me in the chest. I was genuinely winded. It was one thing to see a reproduction in a book, but the sheer scale of the thing …I had no idea.

I’ve never had quite the same physical reaction to a piece of art since, but I sometimes feel echoes of it. I think that’s probably one of the reasons why I stepped into the National Gallery today. I was trying to recapture a fragment of that feeling.

Well, that and the fact that it’s free …which really is quite amazing in a city as expensive as London.