Skip to content

Instantly share code, notes, and snippets.

@HeNy007
Created February 20, 2022 09:41
Show Gist options
  • Save HeNy007/4ffbbd585044eec295ff58b875ee53c6 to your computer and use it in GitHub Desktop.
Save HeNy007/4ffbbd585044eec295ff58b875ee53c6 to your computer and use it in GitHub Desktop.
Light & dark mode, with user-switch button
<body>
<h1>Light &amp; dark mode, with user-switch button</h1>
<p>Inherits dark mode from the OS when enabled, and allows switching in-browser.</p>
<p>Reads the current OS preference and adds an attribute <code>data-lightMode</code> to the <code>&lt;body&gt;</code> tag reflecting its dark or light value. If unsupported in the OS the default is set to light, and switching is still made available. Uses local storage to persist user selection across pages and visits.</p>
<figure>
<figcaption>JavaScript added data attribute</figcaption>
<pre><code class=language-markup spellcheck=false contenteditable>&lt;body data-lightMode="[light | dark]"&gt;</code></pre>
</figure>
<figure>
<figcaption>Set CSS variables for OS light, or no-preference, mode</figcaption>
<pre><code class=language-css spellcheck=false contenteditable>body {
--color: hsl(269,19%,30%);
--bgColor: hsla(32,100%,85%,.35);
--imgFilter: none;
--linkColor: hsl(214, 50%, 50%);
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg width='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}</code></pre>
</figure>
<figure>
<figcaption>Media query and variables for OS dark mode</figcaption>
<pre><code class=language-css spellcheck=false contenteditable>@media (prefers-color-scheme: dark) {
body:not([data-lightMode="light"]) {
--color: #fafafa; /* Not quite white */
--bgColor: hsl(269, 19%, 5%);
--imgFilter: grayscale(10%) brightness(90%);
--linkColor: hsl(214, 100%, 85%);
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg width='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}
}</code></pre>
</figure>
<p><strong>Note:</strong> <code>body:not([data-lightMode="light"])</code> prevents the media query CSS activating while the mode-button is set to light.</p>
<p>We need a second copy of the variables, so the mode-button can also offer dark mode.</p>
<figure>
<figcaption>Overwrite OS light mode with dark</figcaption>
<pre><code class=language-css spellcheck=false contenteditable>body[data-lightMode="dark"] {
--color: #fafafa; /* Not quite white */
--bgColor: hsl(269, 19%, 5%);
--imgFilter: grayscale(10%) brightness(90%);
--linkColor: hsl(214, 100%, 85%);
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg width='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}</code></pre>
</figure>
<figure>
<figcaption>Use the CSS variables</figcaption>
<pre><code class=language-css spellcheck=false contenteditable>body {
color: var(--color);
background-color: var(--bgColor);
background-image: var(--bgPage);
transition:
background-image .3s ease-out,
background-color .3s ease-out,
color .3s ease-out;
}
img:not([src*=".svg"]) {
filter: var(--imgFilter);
}
a:link,
a:visited {
color: var(--linkColor);
}</code></pre>
</figure>
<h2>Javascript anyone?</h2>
<p>Local Storage is used to persist the mode selected, light or dark, across pages and visits.</p>
<figure>
<figcaption>Supports ES6 &amp; local storage?</figcaption>
<pre><code class=language-javascript spellcheck=false contenteditable>var supportsES6=(function(){try{new Function('(a=0)=>a');return true}catch(err){console.log('No ES6');return false}}());
var supportsLocalStorage=(function(){try{var m=new Date().valueOf()+"";localStorage.setItem(m,m);localStorage.removeItem(m);return true}catch(e){console.log("localStorage unavailable");return false}}());</code></pre>
</figure>
<p>JavaScript adds a mode-toggle button, containing an SVG, to the HTML, which allows the switching of light &amp; dark modes.</p>
<figure>
<figcaption>Dark &amp; Light mode toggle button</figcaption>
<pre><code class=language-javascript spellcheck=false contenteditable>var Dark_Light_Mode_Toggle_Button = (function (window, document, supportsES6, supportsLocalStorage) {
if (!supportsES6) return;
const name = 'mode';
const btnClass = 'actions_btn-' + name;
const svgClass = 'actions_svg-' + name;
const clickedClass = '-js-clicked';
const [light, dark] = ['light', 'dark'];
const body = document.body;
const btn = document.createElement('button');
let mode;
const _setAttr = (obj, attr, value) =&gt; obj.setAttribute(attr, value);
const _modeText = bool =&gt; bool ? light : dark;
const _animEnd = e =&gt; btn.classList.remove(clickedClass);
const _clicked = _ =&gt; {
// Note: aria-clicked state is purposefully not linked to the mode setting.
// Initially: The mode may be light or dark, but aria-clicked state is always false.
_setAttr(btn, 'aria-clicked', btn.getAttribute('aria-clicked') === 'false');
mode = mode === false;
// Note: color-scheme cannot be set with CSS variables
// This setting is ignored where unsupported
body.style.colorScheme = _modeText(mode);
_setAttr(body, 'data-lightMode', _modeText(mode));
_setAttr(btn, 'aria-label', `Change to ${_modeText(!mode)} mode`);
supportsLocalStorage && localStorage.setItem('mode', _modeText(mode));
btn.classList.add(clickedClass);
btn.addEventListener('animationend', _animEnd, {once: true});
};
// Utilising symbol defs in the HTML
// [Optionally embed the full SVG here]
const _getSvg = _ =&gt; `&lt;svg class="${svgClass}" aria-hidden=true focusable=false&gt;
&lt;use class="${name}-${dark}" xlink:href="#icon-${name}-${dark}"&gt;&lt;/use&gt;
&lt;use class="${name}-${light}" xlink:href="#icon-${name}-${light}"&gt;&lt;/use&gt;
&lt;/svg&gt;`;
const _getMode = _ =&gt; {
// Get the OS mode setting
mode = (window.matchMedia &amp;&amp; window.matchMedia('(prefers-color-scheme: dark)').matches) ? false : true;
// Override OS mode with the locally stored value.
// Caters to state persistence across pages and visits.
if (supportsLocalStorage &amp;&amp; 'mode' in localStorage) {
mode = localStorage.getItem('mode') === 'light';
}
};
const _init = _ =&gt; {
_getMode();
// Note: color-scheme cannot be set with CSS variables
// This setting is ignored where unsupported
body.style.colorScheme = _modeText(mode);
_setAttr(body, 'data-lightMode', _modeText(mode));
_setAttr(btn, 'class', btnClass);
_setAttr(btn, 'aria-clicked', false);
_setAttr(btn, 'aria-label', `Change to ${_modeText(!mode)} mode`);
btn.innerHTML = _getSvg();
btn.addEventListener('click', _clicked);
// Note: Button is added at the end of the HTML to avoid preceding an accessibility skip-to-content link.
// Skip-to-content links should always be the first actionable asset on a web page.
body.appendChild(btn);
};
_init();
}(window, document, supportsES6, supportsLocalStorage));</code></pre>
</figure>
<p>The property <code class=language-css>color-scheme: [light | dark];</code> informs the browser what modes the page supports, and <strong>may</strong>, where supported (Safari), adjust form controls and scrollbars to suit. Unfortunately, it cannot be set with CSS variables so JavaScript is used.</p>
<p>
<label>Select visual for testing:
<select aria-label="Visual demonstration" role=presentation>
<option>Unopinionated example</option>
<option>Unopinionated example</option>
<option>Unopinionated example</option>
<option>Unopinionated example</option>
</select>
</label>
<label>Text input visual for testing:
<input type=text placeholder="Unopinionated example" role=presentation>
</label>
</p>
<h2>Button styling</h2>
<p>The button styling presented here is not exactly the button used, it omits <a target=_blank title="[new window]" href="https://codepen.io/2kool2/pen/aboydMX">button click animation</a>, but a fully working version none-the-less.</p>
<figure>
<figcaption>Basic button styling</figcaption>
<pre><code class=language-css spellcheck=false contenteditable>button::-moz-focus-inner {
border: 0;
}
.actions_btn-mode {
position: fixed;
z-index: 5;
top: .5rem;
right: .5rem;
width: 3rem;
height: 3rem;
border: 0;
background-color: transparent;
color: inherit;
}
/* Switch icon between dark &amp; light */
.actions_svg-mode > * {
transition: opacity .3s ease-out;
}
[data-lightMode="light"] .mode-dark,
[data-lightMode="dark"] .mode-light {
opacity: 1;
}
[data-lightMode="light"] .mode-light,
[data-lightMode="dark"] .mode-dark {
opacity: 0;
}</code></pre>
</figure>
<figure>
<figcaption>Light &amp; Dark icons as SVG symbol definitions</figcaption>
<pre><code class=language-markup spellcheck=false contenteditable>&lt;svg style=display:none id=svg_definitions&gt;
&lt;defs&gt;
&lt;symbol viewBox="0 0 960 960" id="icon-mode-dark"&gt;
&lt;circle cx="476" cy="480" r="458" fill-opacity=".25"/&gt;
&lt;path d="M382 33C82 91-118 488 115 767c186 223 492 255 716 9a515 515 0 01-421-243c-94-157-56-368-28-500z"/&gt;
&lt;/symbol&gt;
&lt;symbol viewBox="0 0 960 960" id="icon-mode-light"&gt;
&lt;circle cx="479.5" cy="480.5" r="242"/&gt;
&lt;path d="M480 800c22 0 40 18 40 40v80a40 40 0 01-80 0v-80c0-22 18-40 40-40zm480-320c0 22-18 40-40 40h-80a40 40 0 010-80h80c22 0 40 18 40 40zM706 763l57 56a40 40 0 1056-56l-56-57a40 40 0 10-57 57zm-509 56l57-56a40 40 0 10-57-57l-56 57a40 40 0 1056 56zm-77-379a40 40 0 010 80H40a40 40 0 010-80h80zm21-243l56 57a40 40 0 1057-57l-57-56a40 40 0 10-56 56zm622 57l56-57a40 40 0 10-56-56l-57 56a40 40 0 1057 57zM440 40v80a40 40 0 0080 0V40a40 40 0 00-80 0z"/&gt;
&lt;/symbol&gt;
&lt;/defs&gt;
&lt;/svg&gt;</code></pre>
</figure>
<section>
<h2>Image example</h2>
<p>A CSS filter is used to desaturate colour (-15%) and reduce image brightness (-15%) when in dark-mode.</p>
<img src="https://websemantics.uk/unsplash/red-door.jpg" style="display:block;width:100%;max-width:40rem;margin:2rem auto" alt="Worn and flaky, red painted door - image example for the applied filters"
</section>
<h2>References</h2>
<ul>
<li><a target=_blank title="[new window]" href="https://hankchizljaw.com/wrote/create-a-user-controlled-dark-or-light-mode/">Create a user controlled dark or light mode</a></li>
<li><a target=_blank title="[new window]" href="https://web.dev/prefers-color-scheme/">prefers-color-scheme</a></li>
<li><a target=_blank title="[new window]" href="https://codepen.io/2kool2/pen/MEbeEg">Prism code highlighting (light & dark mode)</a></li>
<li><a target=_blank title="[new window]" href="https://codepen.io/2kool2/pen/aboydMX">Fixed position animated SVG buttons</a></li>
<li><a target=_blank title="[new window]" href="https://websemantics.uk/tools/svg-to-background-image-conversion/">SVG to CSS background-image converter</a></li>
<!--
<li><a target=_blank title="[new window]" href=""></a></li>
-->
</ul>
<!-- Icon Definitions -->
<svg style=display:none id=svg_definitions>
<defs>
<symbol viewBox="0 0 960 960" id="icon-mode-dark">
<circle cx="476" cy="480" r="458" fill-opacity=".5"/>
<path d="M382 33C82 91-118 488 115 767c186 223 492 255 716 9a515 515 0 01-421-243c-94-157-56-368-28-500z"/>
</symbol>
<symbol viewBox="0 0 960 960" id="icon-mode-light">
<circle cx="479.5" cy="480.5" r="242"/>
<path d="M480 800c22 0 40 18 40 40v80a40 40 0 01-80 0v-80c0-22 18-40 40-40zm480-320c0 22-18 40-40 40h-80a40 40 0 010-80h80c22 0 40 18 40 40zM706 763l57 56a40 40 0 1056-56l-56-57a40 40 0 10-57 57zm-509 56l57-56a40 40 0 10-57-57l-56 57a40 40 0 1056 56zm-77-379a40 40 0 010 80H40a40 40 0 010-80h80zm21-243l56 57a40 40 0 1057-57l-57-56a40 40 0 10-56 56zm622 57l56-57a40 40 0 10-56-56l-57 56a40 40 0 1057 57zM440 40v80a40 40 0 0080 0V40a40 40 0 00-80 0z"/>
</symbol>
</defs>
</svg>
</body>
<style id=basic_page_styles>
*, *::after, *::before {
box-sizing: inherit;
}
body {
font-family: sans-serif;
text-rendering: optimizeLegibility;
line-height: 1.5;
margin: 1rem;
padding-bottom: 2rem;
background-attachment: fixed;
}
h1,h2 {
font-weight: 100;
margin-top: 2rem;
margin-bottom: 1rem;
text-align: center;
}
h1 + p {
font-size: 1.4rem;
text-align: center;
}
p {
font-size: 1.125rem;
}
ul, p {
max-width: 40rem;
margin: 1rem auto;
}
li {
margin:.25rem 0;
}
figure {
max-width: 40rem;
margin: 3rem auto;
}
figcaption {
font-size: 1.25rem;
}
pre {
overflow: scroll;
background-color: hsla(0,0%,100%, 0.3);
}
code {
font-family: monospace, monospace;
font-size: inherit;
}
label {
display: block;
margin: 1rem auto;
max-width: 24rem;
}
</style>
<style id=action_button_animations>
/* Buttons (or links) */
[class^="actions_btn"],
[class^="actions_btn"]:visited {
/* button colors light */
--btn-fg: #503660;
--btn-bg: #fafafd;
--btn-fg-hover: #418cec;
--btn-bg-hover: #fff;
box-sizing: content-box;
display: block;
width: 2.25rem;
height: 2.25rem;
padding: 0.25rem;
color: var(--btn-fg);
background-color: var(--btn-bg);
border: 0.125rem solid transparent;
border-radius: 50%;
box-shadow: 0 0.25em 0.25em rgba(0, 0, 0, 0.3);
text-decoration: none;
outline: 0 solid;
transition: all 0.3s ease-out;
}
[class^="actions_btn"]:hover,
[class^="actions_btn"]:focus {
color: var(--btn-fg-hover);
background-color: var(--btn-bg-hover);
border-color: var(--btn-fg-hover);
transform: scale(1.2);
box-shadow: 0 0.5em 0.5em rgba(0, 0, 0, 0.4);
}
[class^="actions_svg"] {
width: 2.25rem;
height: 2.25rem;
fill: currentColor;
stroke: currentColor;
border-radius: 100%;
overflow: hidden;
pointer-events: none;
transition: transform 0.5s ease-out;
}
/* Button click animation */
[class^="actions_btn"].-js-clicked {
animation: actions_btn-clicked 0.3s ease-out forwards;
}
@keyframes actions_btn-clicked {
0% {transform: scale(1.2);}
50% {transform: scale(0.8);}
100% {transform: scale(1.2);}
}
/* Remove all buttons from printouts */
@media print {
[class^="actions_container"] {
display: none !important;
}
}
</style>
<!-- Codepen footer include -->
[[[https://codepen.io/2kool2/pen/mKeeGM]]]

Light & dark mode, with user-switch button

Reads the current OS preference and adds an attribute data-lightMode to the body tag reflecting its dark or light value. If unsupported in the OS the default is set to light, and switching is still made available. Uses local storage to persist user selection across pages and visits.

A Pen by mike foskett on CodePen.

License.

var supportsES6=(function(){try{new Function('(a=0)=>a');return true}catch(e){console.log('No ES6');return false}}());
var supportsLocalStorage=(function(){try{var m=new Date().valueOf()+"";localStorage.setItem(m,m);localStorage.removeItem(m);return true}catch(e){console.log("localStorage unavailable");return false}}());
// Adds a mode toggle button, containing an SVG, to the HTML
var Dark_Light_Mode_Toggle_Button = (function (window, document, supportsES6, supportsLocalStorage) {
if (!supportsES6) return;
const name = 'mode';
const btnClass = 'actions_btn-' + name;
const svgClass = 'actions_svg-' + name;
const clickedClass = '-js-clicked';
const [light, dark] = ['light', 'dark'];
const body = document.body;
const btn = document.createElement('button');
let mode;
const _setAttr = (obj, attr, value) => obj.setAttribute(attr, value);
const _modeText = bool => bool ? light : dark;
const _animEnd = e => btn.classList.remove(clickedClass);
const _clicked = _ => {
// Note: Pressed state is purposefully not linked to the mode setting.
// Initially the mode may be light or dark, but pressed state is always false.
// _setAttr(btn, 'aria-pressed', btn.getAttribute('aria-pressed') === 'false');
_setAttr(btn, 'aria-clicked', btn.getAttribute('aria-clicked') === 'false');
mode = mode === false;
body.style.colorScheme = _modeText(mode); // Ignored where unsupported
_setAttr(body, 'data-lightMode', _modeText(mode));
_setAttr(btn, 'aria-label', `Change to ${_modeText(!mode)} mode`);
supportsLocalStorage && localStorage.setItem('mode', _modeText(mode));
btn.classList.add(clickedClass);
btn.addEventListener('animationend', _animEnd, {once: true});
};
// Using symbol defs in the HTML
// const _getSvg = _ => `<svg class=${svgClass} aria-hidden=true focusable=false>
// <use class="${name}-${dark}" xlink:href="#icon-${name}-${dark}"></use>
// <use class="${name}-${light}" xlink:href="#icon-${name}-${light}"></use>
// </svg>`;
// Using an embedded SVG - So I can include this JS into other CodePen projects
const _getSvg = _ => `<svg class="${svgClass}" aria-hidden=true focusable=false viewbox="0 0 960 960">
<g class="${name}-${dark}">
<circle cx="476" cy="480" r="458" fill-opacity=".25"/>
<path d="M382 33C82 91-118 488 115 767c186 223 492 255 716 9a515 515 0 01-421-243c-94-157-56-368-28-500z"/>
</g>
<g class="${name}-${light}">
<circle cx="479.5" cy="480.5" r="242"/>
<path d="M480 800c22 0 40 18 40 40v80a40 40 0 01-80 0v-80c0-22 18-40 40-40zm480-320c0 22-18 40-40 40h-80a40 40 0 010-80h80c22 0 40 18 40 40zM706 763l57 56a40 40 0 1056-56l-56-57a40 40 0 10-57 57zm-509 56l57-56a40 40 0 10-57-57l-56 57a40 40 0 1056 56zm-77-379a40 40 0 010 80H40a40 40 0 010-80h80zm21-243l56 57a40 40 0 1057-57l-57-56a40 40 0 10-56 56zm622 57l56-57a40 40 0 10-56-56l-57 56a40 40 0 1057 57zM440 40v80a40 40 0 0080 0V40a40 40 0 00-80 0z"/>
</g>
</svg>`;
const _getMode = _ => {
// Get the OS mode setting
mode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ? false : true;
// Override OS mode with the locally stored value.
// Caters to state persistence across pages and visits.
if (supportsLocalStorage && 'mode' in localStorage) {
mode = localStorage.getItem('mode') === 'light';
}
};
const _init = _ => {
_getMode();
// color-scheme cannot be set with CSS variable
// Ignored where unsupported
body.style.colorScheme = _modeText(mode);
_setAttr(body, 'data-lightMode', _modeText(mode));
_setAttr(btn, 'class', btnClass);
// _setAttr(btn, 'aria-pressed', false);
_setAttr(btn, 'role', 'switch');
_setAttr(btn, 'aria-clicked', false);
_setAttr(btn, 'aria-label', `Change to ${_modeText(!mode)} mode`);
btn.innerHTML = _getSvg();
btn.addEventListener('click', _clicked);
// Note: Button is added at the end of the HTML to avoid preceding an accessibility skip-to-content link.
// Skip-to-content links should always be the first actionable asset on a web page.
body.appendChild(btn);
};
_init();
}(window, document, supportsES6, supportsLocalStorage));
// Includes used:
// Prism highlighting: https://codepen.io/2kool2/pen/MEbeEg
<script src="https://codepen.io/2kool2/pen/MEbeEg"></script>
/* Global styling is in the HTML so I can include this CSS into other CodePen projects */
body {
--color: hsl(269, 19%, 30%);
--bgColor: hsla(32,100%,85%,.35);
--linkColor: hsla(214, 71%, 47%, 1);
--linkColorHover: hsla(214, 100%, 35%, 1);
--linkBgHover: hsla(214, 100%, 85%, 1);
--linkFocus: hsla(214, 71%, 80%, 0.3);
--focusOutline: var(--linkFocus) solid 0.25rem;
--imgFilter: none;
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
body:not([data-lightMode="light"]) {
--color: #fafafa;
--bgColor: hsl(269, 19%, 5%);
--linkColor: hsla(214, 100%, 80%, 1);
--linkColorHover: hsla(214, 100%, 11%, 1);
--linkFocus: hsla(214, 100%, 80%, .5);
--focusOutline: hsla(214, 100%, 85%, .6) solid .25rem;
--imgFilter: grayscale(15%) brightness(85%);
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}
}
/* Duplicated dark mode for button action */
body[data-lightMode="dark"] {
--color: #fff;
--bgColor: hsl(269, 19%, 5%);
--linkColor: hsla(214, 100%, 80%, 1);
--linkColorHover: hsla(214, 100%, 11%, 1);
--linkFocus: hsla(214, 100%, 80%, .6);
--focusOutline: hsla(214, 100%, 85%, .6) solid .25rem;
--imgFilter: grayscale(15%) brightness(85%);
--bgPage: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7'/%3E%3C/filter%3E%3C/defs%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}
body {
color: var(--color);
background-color: var(--bgColor);
background-image: var(--bgPage);
transition:
background-image .3s ease-out,
background-color .3s ease-out,
color .3s ease-out;
}
img:not([src*=".svg"]) {
filter: var(--imgFilter);
transition: filter 0.3s ease-out;
}
a:link,
a:visited {
color: var(--linkColor);
text-decoration-color: var(--linkColorUnderline);
outline: hsla(214, 71%, 80%, 0); solid .25rem;
transition:
color .3s ease-out,
background-color .3s ease-out,
outline-color .3s ease-out;
}
a:hover,
a:focus {
color: var(--linkColorHover);
outline: var(--linkBgHover) solid .25rem;
background-color: var(--linkBgHover);
}
button::-moz-focus-inner {
border: 0;
}
.actions_btn-mode {
--fromEdge: .5rem;
position: fixed;
z-index: 5;
top: var(--fromEdge);
right: var(--fromEdge);
width: 3rem;
height: 3rem;
border: 0;
background-color: transparent;
color: inherit;
}
@media (min-width: 768px) {
.actions_btn-mode {
--fromEdge: 1.5rem;
}
}
/* Switch icon between dark &amp; light */
.actions_svg-mode > * {
transition: opacity .3s ease-out;
}
[data-lightMode="light"] .mode-dark,
[data-lightMode="dark"] .mode-light {
opacity: 1;
}
[data-lightMode="light"] .mode-light,
[data-lightMode="dark"] .mode-dark {
opacity: 0;
}
/*
Includes used:
Prism highlighting: https://codepen.io/2kool2/pen/MEbeEg
*/
<link href="https://codepen.io/2kool2/pen/MEbeEg" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment