Then I realized we could do that easily with a JS library! We could give some divs a "sticky-id" attribute, so they stay as part of the DOM tree when the page reloads, only their contents get replaced with the contents of divs from the new page having the same "sticky-id". That way there's no flash to white, and CSS transitions on sticky elements get a chance to fire. The whole thing could be handled by a generic onclick handler on each link. And the links would support opening in new tab as well, the JS would only fire when they are clicked in the same tab. I think that would be the most conservative way to have an SPA-like experience with a minimum of JS. Unfortunately I was too lazy to implement it :-/
EDIT: It's interesting that most replies to this comment seem to talk about whole page transitions, like fading out the whole page. But as I envisioned it, the key part of the idea is that we can get element-by-element transitions without writing custom JS, just by adding "sticky-id" attribute to some elements and letting their CSS transitions do the work.