The Critial Rendering Path is the sequence of steps the browser goes through to convert the HTML, CSS, and JavaScript into pixels on the screen. Optimizing the critical rendering path improves render performance. The Critical Rendering Path includes the Document Object Model (DOM), CSS Object Model(CSSOM), render tree and layout.
Before the browser can render the page, it needs to construct the DOM and CSSOM trees. As a result, we need to ensure that we deliver both the HTML and CSS to the browser as quickly as possible.
Bytes -> Characters -> tokens -> nodes -> object model.
HTML markup is transformed into a Document Object Model (DOM); CSS markup is transformed into a CSS Object Model (CSSOM).
DOM and CSSOM are independent data structures.
- The DOM and CSSOM trees are combined to form the render tree.
- Render tree contains only the nodes required to render the page.
- Layout computes the exact position and size of each object.
- The last step is paint, which takes in the final render tree and renders the pixels to the screen.
- By default, CSS is treated as a render blocking resourc.
- Media types and media queries allow us to mark some CSS resources as non-render blocking.
- The browser downloads all CSS resources, regardless of blocking or non-bloc behavior.
import {LitElement, html, svg, css} from 'lit';
const themeCSS = css`
.background {
fill: var(--background-color, #000000);
}
text {
fill: var(--font-color, #ffffff);
font-size: var(--font-size, 26px);
stroke-width: var(--stroke-width, 1.2px);
stroke: var(--stroke-color, #eeeeee);
}
`;
const svgCSS = css`
:host {
display: block;
}
svg {
height: 100%;
width: 100%;
}
text {
fill: #ffffff;
dominant-baseline: hanging;
font-family: monospace;
font-size: 24px;
}
`;
const createElement = (chars) => svg`
<text id="chars">${chars}</text>
`;
const createMotif = (numPrints, offset = 0) => {
const rotation = 360 / numPrints;
const prints = [];
let currRotation = offset;
for (let index = 0; index < numPrints; index++) {
currRotation += rotation;
prints.push(svg`
<use
href="#chars"
transform="rotate(${currRotation}, 0, 0)">
</use>
`);
}
return svg`
<g
id="motif"
transform="translate(50, 50)">
${prints}
</g>
`;
};
const createTileBoundary = () => svg`
<clipPath id="rect-clip">
<rect width="200" height="200"></rect>
</clipPath>
`;
const createTile = () => svg`
<g clip-path="url(#rect-clip)">
<use transform="translate(0, 0)" href="#motif"></use>
<use transform="translate(0, 100)" href="#motif"></use>
<use transform="translate(100, -50)" href="#motif"></use>
<use transform="translate(100, 50)" href="#motif"></use>
<use transform="translate(100, 150)" href="#motif"></use>
</g>
`;
const createRepeatPattern = () => svg`
<pattern
id="repeat-pattern"
x="-10"
y="-10"
width="200"
height="200"
patternUnits="userSpaceOnUse">
${createTile()}
</pattern>
`;
export class RepeatPattern extends LitElement {
static properties = {
chars: {type: String},
numPrints: {type: Number, attribute: 'num-prints'},
rotationOffset: {
type: Number,
attribute: 'rotation-offset',
},
};
static styles = [svgCSS, themeCSS];
constructor() {
super();
this.chars = 'lit';
this.numPrints = 7;
this.rotationOffset = 0;
}
render() {
return html`
<svg>
<defs>
${createTileBoundary()}
${createElement(this.chars)}
${createMotif(this.numPrints, this.rotationOffset)}
${createRepeatPattern()}
</defs>
<rect class="background" height="100%" width="100%"></rect>
<rect fill="url(#repeat-pattern)" height="100%" width="100%"></rect>
</svg>
`;
}
}
customElements.define('repeat-pattern', RepeatPattern);