The issue that plagued all my pages in the desktop version was a very high cumulative layout shift (CLS). That is, a lot of page elements were moving around while the page was loading, making it a poor experience for the user. Together with largest contentful paint and first input delay, cumulative layout shift make up the Core Web Vitals[b], a new set of user-centric metrics that Google rolled out to quantify the quality of websites and thus provide a signal to Google's ranking algorithm.
CLS doesn't apply when the movement of elements is caused by user input. But in order to combat elements jumping around on the page as it loads, loading the page is not considered to be "caused by user input", and this is what caused problems for my pages. The solution I ended up with had three components:
Inline CSS styles: I added
overflow-y: scrollto the body element in order to have a permanent scrollbar which makes the width of the page predictable.
Fixed-size elements first: The fixed-width right sidebar on the page loads before the horizontally growing main article, but is laid out to the right of it by using a
flexboxlayout with reverse order.
It was the last component - inline load-time layout - that took the longest to figure out. CLS is computed as amount of shift times area affected. What this means is that each shifted element affects itself and elements below it in the document flow. It also means that if an element is the last element in the flow, and it has size zero, it has no shift at all.
<script>var layout = new LoadingMasonryLayout();</script> <div id="new_div_0"> <script>layout.beginElement(document.getElementById("new_div_0"));</script> ... </div> <script>layout.endElement(document.getElementById("new_div_0"));</script>
This way, each element could be moved into its approximately final position in the page as the page was loading. The
beginElement() call would do the actual moving of the element, since it had to be done while the element didn't have any size. The
endElement() call would be able to read the size of the fully-constructed element and therefore update the
layout object so that the next masonry "brick" could be accurately positioned.
Update 2020-06-23: It seems like the God-machine has taken this blog back into its mercy.