Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Byte attribution of a served product snapshot: inlined CSS is 13%, attributes are 75%

Open
#147 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Active
Tech stack
javascript
Domain
performance

Research direction

Start by reading the postProcess path and the existing pruneUnmatchedCss and minifyInlineCss behavior, then reproduce the byte breakdown from /prerender_admin/page-content with the stated browser v1.21.0 options. Compare the SVG, class-token, and repeated style-URL levers against external stylesheets and paint or geometry parity; do not remove the review widget CSS. Done requires a selected, measured optimization with unchanged rendered content and a clear path toward the 1 MB cap.

Written by the indexing model from the issue text.

Description

Summary

A served product snapshot was reported as having a low text-to-HTML ratio, attributed to the CSS flattenShadowDom inlines for the review widget. Measured against a real served page, that attribution is wrong: inlined CSS is 13.4% of the document and attributes are 74.7%. Deleting every byte of injected styling moves the ratio 2.66% → 3.07%.

This issue records the byte attribution so the numbers aren't re-derived, and separates the levers that are provably safe from the one that isn't.

Method

One review-heavy product page (desktop), read from the serving cache via /prerender_admin/page-content, so these are the bytes a crawler receives. Rendered by browser v1.21.0 with flattenShadowDom, pruneUnmatchedCss and minifyInlineCss all on — i.e. the CSS below is already the residue after ~74% of style rules were pruned and the rest CSSOM-minified.

Class-token reference counts were computed against the inline <style> blocks and the four external stylesheets the snapshot still links. Measuring against inline CSS alone overstates the unreferenced total by ~6× (359 KB vs the true 61 KB) — the page keeps a 588 KB external utility stylesheet, so most tokens are referenced from a sheet that is not in the document.

Where 1,468,123 bytes go

bytes % of doc
class attributes 451,713 30.8%
inlined <style> CSS 197,160 13.4%
style= attributes 140,957 9.6%
href / src / srcset 214,751 14.6%
SVG d path data 81,344 5.5%
aria-label 52,604 3.6%
tag names + brackets 55,700 3.8%
ld+json 17,486 1.2%
visible text 39,078 2.66%

10,137 elements. 74.7% of the document is HTML attributes.

The review widget

The flattened review container is 385,482 B — 26.3% of the page — carrying 7,707 B of review text (2.0% of itself). Eight review cards; one card is 22,446 B / 235 elements for 956 B of text.

inside the review container bytes % of block
inlined <style> (host sheet + nested shadow hosts) 152,624 39.6%
SVG markup (d alone = 62,473) 108,954 28.3%
class 60,930 15.8%
review text 7,707 2.0%

Two candidates measured and rejected

  • Deduplicating identical shadow stylesheets across hosts. 9 distinct sheets across 10 hosts; total bytes sitting in duplicate copies: 196 B. Not a lever.
  • minifyInlineCss on the flattened blocks. Already CSSOM output, so re-emission is a no-op — consistent with the existing docstring.

Levers that remain, with sizes

  1. Repeated SVG path data — ~64,093 B (4.4% of the document), concentrated in the review block. 193 d occurrences, only 61 distinct; a single 1,033-byte path appears 45 times (46,485 B). Hoisting exact-duplicate path data into <defs><symbol> + <use> renders identically. No such pass exists in postProcess today.
  2. Class tokens no surviving rule references — 61,277 B page-wide, 34,467 B inside the review block. Same soundness argument that already licenses pruneUnmatchedCss: with stripScripts on, nothing can add a class after serialization, so a token no sheet mentions is inert. Must be evaluated against external sheets, not just inline ones.
  3. A repeated background-image URL in style= attributes — ~93,000 B. One sprite URL repeated 489 times across style= attributes. Origin-authored, not introduced by post-processing.

Cloaking: what actually carries risk here

Worth stating explicitly, because "fidelity" has been used to decline byte-cutting levers that do not actually implicate it.

Cloaking is presenting different content to users and crawlers in order to manipulate rankings. The unit is content — text, links, images, prices, availability, structured data — not markup. Removing an attribute no rule reads, deduplicating identical SVG path data, or pruning a rule that matches nothing changes zero content: a user and a crawler still perceive the same page. Levers 1–3 are outside the policy, and rendering-fidelity checks (paintParity, geometry) are the right bar for them for a different reason — Google indexes the rendered DOM and devalues content it determines is not visible, so a layout regression costs indexing quality on its own merits.

The risk is asymmetric, and it runs the other way: revealing content to a crawler that a user does not see is the cloaking-shaped move. That is exactly what dropping the review widget's CSS would do — the widget's own rules hold collapsed panels, modals and secondary UI at display:none, and stripping them injects text into the indexable page that no user is shown. It would also reintroduce the inbound-encapsulation defects fixed across v1.19–v1.21. Do not pursue "just drop the review CSS" for byte savings.

Note for answer/generative engines

Structured data carries aggregateRating (ratingValue, ratingCount) but no individual review objects. So the 385 KB review DOM is the only place individual review content exists in the snapshot — it is load-bearing for extraction, not redundant with the JSON-LD, and should not be treated as trimmable content. Emitting review items into the JSON-LD would serve extraction far better per byte than the DOM does, but that is an origin change, not a post-processing one.

Separately: text-to-HTML ratio is not a documented ranking signal — it is a third-party audit-tool metric. The documented hard constraint is the 1 MB soft cap a crawler applies to a document, and this page is at 1.47 MB. Sizing work against "get under 1 MB" is better defined than "raise a ratio", and levers 1–3 together are ~218 KB of the ~470 KB needed.

Dominant language
JavaScript
Stars
0
Forks
0
Avg merge
9h 10m
Merged PRs (30d)
56

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from HarperFast/prerender-plugin

All issues in HarperFast/prerender-plugin

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.