Skip to content

Instantly share code, notes, and snippets.

@Sidneys1
Created January 30, 2024 21:04
Show Gist options
  • Save Sidneys1/d655bf7bfaf85efcf9feac2c0f30f159 to your computer and use it in GitHub Desktop.
Save Sidneys1/d655bf7bfaf85efcf9feac2c0f30f159 to your computer and use it in GitHub Desktop.
noscript theming
<!DOCTYPE html>
<html>
<head>
<script>
/*
* This code is only used for loading/saving preferences
* to/from `localstorage`. If scripts are disabled all
* the theming still works, they just won't persist. :^)
*/
// Definition of preferences. Individual toggles should be
// `id`'d `${key}-${value}`.
const PREFERENCES = {
'color': ['red', 'green', 'blue'],
'theme': ['auto', 'light', 'black', 'monokai'],
'align': ['left', 'justify'],
'font': ['default', 'od'],
};
// Save preferences to `localstorage`.
function savePreferences() {
var p = {
};
Object.entries(PREFERENCES).forEach(([key, values]) => {
p[key] = values.find(value =>
document.getElementById(`${key}-${value}`).checked);
});
localStorage.setItem('preferences', JSON.stringify(p));
};
// Run at page load
document.addEventListener("DOMContentLoaded", function(_, __) {
// Load preferences once.
const p = JSON.parse(localStorage.getItem('preferences') || '{}');
Object.entries(PREFERENCES).forEach(([key, values]) =>
document.getElementById(`${key}-${p[key] || values[0]}`).checked = true);
// Register change handlers.
Object.entries(PREFERENCES).forEach(([key, values]) =>
values.forEach(value =>
document.getElementById(`${key}-${value}`).addEventListener('change', e =>
savePreferences())));
});
</script>
<style>
@font-face {
font-family:clfallback;
src:url(OpenDyslexic3-Regular.otf) format('opentype');
}
:root {
/* Defaults */
--accent: magenta;
--accent-subtle: magenta;
--background: white;
--foreground: black;
--text-align: left;
--font-face: system-ui;
}
/* ALIGNMENT */
body:has(input:checked[name="align"][value="justify"]) {
--text-align: justify;
}
/* FONT */
body:has(input:checked[name="font"][value="od"]) {
--font-face: clfallback, system-ui;
}
/* LIGHT MODE COLORS */
/* Red Light */
body:has(input:checked[name="color"][value="red"]) {
--accent: darkred;
--accent-subtle: #FF00007F;
}
/* Green Light */
body:has(input:checked[name="color"][value="green"]) {
--accent: darkgreen;
--accent-subtle: #00FF007F;
}
/* Blue Light */
body:has(input:checked[name="color"][value="blue"]) {
--accent: darkblue;
--accent-subtle: #0000FF7F;
}
/* DARK MODE COLORS */
/* Red Dark */
body:has(input:checked[name="theme"][value="dark"], input:checked[name="theme"][value="black"], input:checked[name="theme"][value="monokai"]):has(input:checked[name="color"][value="red"]) {
--accent: #BF3D7C;
--accent-subtle: #BF3D7C7F;
}
/* Green Dark */
body:has(input:checked[name="theme"][value="dark"], input:checked[name="theme"][value="black"], input:checked[name="theme"][value="monokai"]):has(input:checked[name="color"][value="green"]) {
--accent: #b4d273;
--accent-subtle: #b4d2737F;
}
/* Blue Dark */
body:has(input:checked[name="theme"][value="dark"], input:checked[name="theme"][value="black"], input:checked[name="theme"][value="monokai"]):has(input:checked[name="color"][value="blue"]) {
--accent: #6c99bb;
--accent-subtle: #6c99bb7F;
}
/* THEME */
@media (prefers-color-scheme: dark) {
body:has(input:checked[name="theme"][value="auto"]) {
--background: #333;
--foreground: #eee;
}
}
@media (prefers-color-scheme: light) {
body:has(input:checked[name="theme"][value="auto"]) {
--background: white;
--foreground: black;
}
}
body:has(input:checked[name="theme"][value="light"]) {
color-scheme: only light;
}
body:has(input:checked[name="theme"][value="dark"]) {
color-scheme: only dark;
--background: #333;
--foreground: #eee;
}
body:has(input:checked[name="theme"][value="black"]) {
color-scheme: only dark;
--background: black;
--foreground: white;
}
body:has(input:checked[name="theme"][value="monokai"]) {
color-scheme: only dark;
--background: #2e2e2e;
--foreground: #d6d6d6;
}
body {
color-scheme: light dark;
accent-color: var(--accent);
background-color: var(--background);
color: var(--foreground);
font: 400 16px/1.5 var(--font-face);
text-wrap: pretty;
margin: 0;
}
::selection {
background-color: var(--accent-subtle);
}
a {
color: var(--accent);
text-decoration: none;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 400;
}
#content {
margin: 0 auto;
width: calc(100% / 3 * 2);
}
article {
text-align: var(--text-align);
}
#appearance-controls {
float: right;
}
#appearance-controls div.controls {
display: flex;
}
#appearance-controls div.noscript-notice {
width: 100%;
text-align: right;
font-style: italic;
color: var(--accent);
font-size: 75%;
cursor: default;
text-decoration: underline dashed var(--accent);
opacity: 0.75;
transition: opacity 100ms linear;
}
#appearance-controls div.noscript-notice:hover {
opacity: 1;
transition: opacity 100ms linear;
}
#appearance-controls fieldset {
display: flex;
border: none;
padding: 0;
justify-content: center;
align-content: center;
text-align: center;
}
#appearance-controls fieldset > legend {
width: 100%;
text-align: center;
font-weight: bold;
font-size: xx-small;
text-transform: uppercase;
}
#appearance-controls fieldset input[type="radio"] {
display:none;
}
#appearance-controls fieldset input[type="radio"] + label {
border-top: 2px solid var(--accent);
border-bottom: 2px solid var(--accent);
margin-left: 0;
margin-right: 0;
padding: 0 0.25em;
height: 1.5em;
cursor:pointer;
}
#appearance-controls fieldset input[type="radio"] + label:hover {
background-color: var(--accent-subtle);
}
#appearance-controls fieldset input[type="radio"] + label:first-of-type {
border-left: 2px solid var(--accent);
border-top-left-radius: 0.5em;
border-bottom-left-radius: 0.5em;
}
#appearance-controls fieldset input[type="radio"] + label:last-of-type {
border-right: 2px solid var(--accent);
border-top-right-radius: 0.5em;
border-bottom-right-radius: 0.5em;
}
#appearance-controls fieldset input:checked[type="radio"] + label {
background-color: var(--accent);
border-color: transparent;
color: var(--background);
}
#theme-select {
grid-row: 2;
}
#toc {
}
#toc::before {
content: "Table of Contents";
font-weight: bold;
font-size: 1rem;
font-variant-caps: small-caps;
}
</style>
</head>
<body>
<div id="content">
<div id="appearance-controls">
<div class="controls">
<fieldset id="color-select">
<legend>Accent</legend>
<input id="color-red" type="radio" name="color" value="red" checked /><label for="color-red" title="Red">❤️</label>
<input id="color-green" type="radio" name="color" value="green" /><label for="color-green" title="Green">🌳</label>
<input id="color-blue" type="radio" name="color" value="blue" /><label for="color-blue" title="Blue">💧</label>
</fieldset>
<fieldset id="theme-select">
<legend>Theme</legend>
<input id="theme-auto" type="radio" name="theme" value="auto" checked /><label for="theme-auto" title="Auto">🪄</label>
<input id="theme-light" type="radio" name="theme" value="light" /><label for="theme-light" title="Light">☀️</label>
<input id="theme-dark" type="radio" name="theme" value="dark" /><label for="theme-dark" title="Dark">🌕</label>
<input id="theme-black" type="radio" name="theme" value="black" /><label for="theme-black" title="Black (AMOLED)">🌑</label>
<input id="theme-monokai" type="radio" name="theme" value="monokai" /><label for="theme-monokai" title="Monokai">🎨</label>
</fieldset>
<fieldset id="align-select">
<legend>Align</legend>
<input id="align-left" type="radio" name="align" value="left" checked /><label for="align-left" title="Left">⬅️</label>
<input id="align-justify" type="radio" name="align" value="justify" /><label for="align-justify" title="Justify">↔️</label>
</fieldset>
<fieldset id="font-select">
<legend>Font</legend>
<input id="font-default" type="radio" name="font" value="default" checked /><label for="font-default" style="font-family: system-ui;" title="System Font">Aa</label>
<input id="font-od" type="radio" name="font" value="od" /><label for="font-od" style="font-family: clfallback;" title="OpenDyslexic">Aa</label>
</fieldset>
</div>
<noscript>
<div class="noscript-notice" title="JavaScript is disabled, preferences cannot be saved.">
Will not be saved.
</div>
</noscript>
</div>
<article>
<h1>Title</h1>
<section id="toc">
<ul>
<li><a href="#section-1">Section 1</a>
<ul><li><a href="#section-1a">Section 1a</a></li></ul></li>
</ul>
</section>
<section>
<h2 id="section-1">Section 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Et magnis dis parturient montes nascetur ridiculus mus mauris. Leo duis ut diam quam nulla. Lacus sed viverra tellus in hac habitasse platea dictumst vestibulum. Est ultricies integer quis auctor elit sed vulputate mi. Urna molestie at elementum eu facilisis. Ante metus dictum at tempor commodo ullamcorper a. Id aliquet lectus proin nibh nisl. Nisi porta lorem mollis aliquam ut porttitor leo. At quis risus sed vulputate odio. Vitae ultricies leo integer malesuada. Amet commodo nulla facilisi nullam vehicula.</p>
<h3 id="section-1a">Section 1a</h3>
<p>Duis tristique sollicitudin nibh sit. Sagittis eu volutpat odio facilisis mauris sit amet. Faucibus vitae aliquet nec ullamcorper sit amet. Viverra mauris in aliquam sem fringilla. Etiam dignissim diam quis enim. Amet volutpat consequat mauris nunc congue nisi vitae suscipit. Luctus venenatis lectus magna fringilla urna porttitor. Massa tincidunt nunc pulvinar sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Cursus in hac habitasse platea dictumst. Amet justo donec enim diam vulputate ut pharetra sit amet. Massa ultricies mi quis hendrerit. Mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et. Faucibus purus in massa tempor nec feugiat nisl pretium. Amet justo donec enim diam vulputate ut.</p>
</section>
</article>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment