diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-06-17 12:23:43 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-17 15:23:43 -0400 |
| commit | dce7bb521e3947af59fe18895b609ec353e0450e (patch) | |
| tree | d873dfbd84bed355e8441405382e7a1a3bd34f19 /docs/_templates/layout.html | |
| parent | aa06af29d7580f8a0113449a3acfef831d02c7a8 (diff) | |
| download | vyos-documentation-dce7bb521e3947af59fe18895b609ec353e0450e.tar.gz vyos-documentation-dce7bb521e3947af59fe18895b609ec353e0450e.zip | |
Fix Cookiebot consent dialog rendering unstyled and breaking the page (#2108)
On a fresh (no-consent) load the consent banner could render completely
unstyled and expand to full page height. Cookiebot delivers its dialog CSS as
a constructed stylesheet on document.adoptedStyleSheets; ReadTheDocs'
readthedocs-addons.js reassigns that whole-array property with a destructive
replace, and when that lands after Cookiebot's network-gated adoption it drops
Cookiebot's sheet, leaving #CybotCookiebotDialog at position:static expanded to
~6700px. It is a race, so it is intermittent and clears once consent is given
(the dialog then never renders).
- layout.html: a small adoptedStyleSheets shim, installed before any page
script, that preserves Cookiebot's sheet so another library cannot drop it.
- custom.css: a leak-safe safety net that keeps the dialog contained even if
its adopted sheet is ever absent. It uses only properties Cookiebot itself
sets, so it has verifiably no effect on the normal, styled banner.
🤖 Generated by [robots](https://vyos.io)
Diffstat (limited to 'docs/_templates/layout.html')
| -rw-r--r-- | docs/_templates/layout.html | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index fce69b86..07748192 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -2,6 +2,46 @@ {%- set current_version = "1.5.x circinus" %} {% block extrahead %} {% if gtm_id and cookiebot_id %} + {# Keep Cookiebot's consent dialog from rendering unstyled and breaking the page. + Cookiebot delivers its dialog CSS as a constructed stylesheet via + document.adoptedStyleSheets. That property holds the *whole* sheet list, and + ReadTheDocs' readthedocs-addons.js reassigns it with a destructive replace; when + that lands after Cookiebot's (network-gated) adoption it drops Cookiebot's sheet, + leaving #CybotCookiebotDialog at position:static, expanded to full page height. + This shim makes assignment preserve Cookiebot's sheet specifically. It must run + before the first adoptedStyleSheets write, so it is the first thing in <head>. #} + <script> + (function () { + try { + var desc = Object.getOwnPropertyDescriptor(Document.prototype, "adoptedStyleSheets"); + if (!desc || !desc.get || !desc.set) return; + var guarded = null; + var isCookiebot = function (sheet) { + try { + var rules = sheet.cssRules; + for (var i = 0; i < rules.length; i++) { + if (rules[i].selectorText && rules[i].selectorText.indexOf("CybotCookiebotDialog") !== -1) return true; + } + } catch (e) {} + return false; + }; + Object.defineProperty(document, "adoptedStyleSheets", { + configurable: true, + get: function () { return desc.get.call(document); }, + set: function (sheets) { + for (var i = 0; i < sheets.length; i++) { + if (isCookiebot(sheets[i])) { guarded = sheets[i]; break; } + } + if (guarded && Array.prototype.indexOf.call(sheets, guarded) === -1) { + sheets = Array.prototype.slice.call(sheets).concat(guarded); + } + desc.set.call(document, sheets); + } + }); + } catch (e) {} + })(); + </script> + {# Cookiebot CMP — must load first so its auto-blocker can scan/block other tags #} <script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" |
