From dc4bc217161bf9f839dd637b1caa54c6e9955d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Z=C3=B6chling?= Date: Sun, 3 Mar 2024 00:20:04 +0100 Subject: [PATCH] v3.0.beta --- docs/main.css | 9 +- docs/slides-cssingraz2024/index.html | 62 ++++---- docs/slides-cssingraz2024/slide.js | 25 +-- docs/slides-cssingraz2024/style.css | 218 ++++++++++++++++----------- 4 files changed, 183 insertions(+), 131 deletions(-) diff --git a/docs/main.css b/docs/main.css index a598de8..8d812e6 100644 --- a/docs/main.css +++ b/docs/main.css @@ -20,8 +20,7 @@ body { margin: 0; padding-block: 1em 3em; padding-inline: .75em; - overflow-x: auto; - overflow-y: scroll; + overflow: hidden scroll; scroll-behavior: auto; } @media (prefers-reduce-motion: no-preference) { @@ -133,11 +132,11 @@ tbody tr { align-self: end; grid-area: year; } -[aria-labelledby="presentations"] td:nth-child(4)::before { +[aria-labelledby="presentations"] :is(th, td):nth-child(4)::before { content: ''; display: inline-block; - inline-size: 2ch; - block-size: 1.125ch; + inline-size: 1rem; + block-size: .75rem; mask: no-repeat url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"%3E%3Cpath fill="%23000" d="M15.938 32c0 0-9.938-14.062-9.938-20.062 0-11.813 9.938-11.938 9.938-11.938s10.062 0.125 10.062 11.875c0 6.187-10.062 20.125-10.062 20.125zM16 6c-2.209 0-4 1.791-4 4s1.791 4 4 4 4-1.791 4-4-1.791-4-4-4z"%3E%3C/path%3E%3C/svg%3E') -0.0625ch center / 1.125ch 1.125ch; background-color: currentColor; forced-color-adjust: preserve-parent-color; diff --git a/docs/slides-cssingraz2024/index.html b/docs/slides-cssingraz2024/index.html index 682a29d..b57e096 100644 --- a/docs/slides-cssingraz2024/index.html +++ b/docs/slides-cssingraz2024/index.html @@ -1,5 +1,5 @@ - + High Contrast Mode, for real | @CSSence | #CSS-in-Graz @@ -10,10 +10,10 @@ - +
-
+

High Contrast Mode, for real

@CSSence
🗣 Matthias Zöchling

@@ -21,14 +21,14 @@

High Contrast Mode, for real

-
+

What?

(High) Contrast Mode?

-
+

The main feature is that it limits and controls the range of colors, making it easier for users to emphasize content and UI in a way that works for them.

@@ -38,7 +38,7 @@

What?

-
+

Unlike other operating system display modes that invert colors or set a dark mode flag, Windows High Contrast Mode completely overrides authored colors with user-set colors.

@@ -47,13 +47,13 @@

What?

-
+

The Settings Page in Windows 10, navigated to Ease of Access, Vision, High Contrast.

The same Settings page, but now High Contrast Mode is turned on: A theme with light text on dark background chosen.

The list of four available default themes in Windows 10, including a fifth, created by the user, named ‘Custom’.

-
+

⚠️ Low Contrast

@@ -63,7 +63,7 @@

⚠️ Low Contrast

-
+

Why?

@@ -73,7 +73,7 @@

Why?

-
+

How?

    @@ -84,7 +84,7 @@

    How?

-
+

OS

    @@ -96,7 +96,7 @@

    OS

-
+

Browsers

Support is good.*

@@ -104,7 +104,7 @@

Browsers

-
+

There is a ton of prior content discussing Windows High Contrast Mode (WHCM) and web content. The catch is that content covers four (five?) different implementations across more than a decade of support: Internet Explorer, Edge, the other Edge, Edge plus IE aliasing, and hardly anything on Firefox. Which means much of it no longer applies.

@@ -113,14 +113,14 @@

Browsers

-
+

For real!

🥁

-
+

What happens… (1/2)

    @@ -136,7 +136,7 @@

    What happens… (1/2)

-
+

What happens… (2/2)

    @@ -152,7 +152,7 @@

    What happens… (2/2)

-
+

The media query

@media (forced-colors: active*) {
@@ -162,17 +162,17 @@ 

The media query

-
+

The other media query

@media (prefers-contrast: more*) {
 	…
 }
-

*) no-preference | more | less | custom

+

*) no-preference | more | less | custom

-
+

The future media query?

@media (prefers-contrast: forcedcustom) {
@@ -182,7 +182,7 @@ 

The future media query?

-
+

The retired media query

@media (-ms-high-contrast: active) {
@@ -191,7 +191,7 @@ 

The retired media query

-
+

Combining media queries

@media (forced-colors: active) and
@@ -201,7 +201,7 @@ 

Combining media queries

-
+

The ToDo List (1/2)

    @@ -214,7 +214,7 @@

    The ToDo List (1/2)

-
+

Transparent is a color

:focus {
@@ -225,7 +225,7 @@ 

Transparent is a color

-
+

The ToDo List (2/2)

    @@ -238,14 +238,14 @@

    The ToDo List (2/2)

-
+

The Backplate

-

The same picture of a cat two times, left and right. The text ‘Hello Kitty!’ has been placed on top of each. However, the right one also shows a black background behind the text, hiding parts of the cat for better legibility. This background is called a backplate in High Contrast Mode.
Image on the right has backplate applied.

+

The same picture of a cat two times, left and right. The text ‘Hello Kitty!’ has been placed on top of each. However, the right one also shows a black background behind the text, hiding parts of the cat for better legibility. This background is called a backplate in High Contrast Mode.
Image on the right has backplate applied.

-
+

The Override

.element {
@@ -255,7 +255,7 @@ 

The Override

-
+

Outro

⚠️ Testing

@@ -267,7 +267,7 @@

⚠️ Testing

-
+

⚠️ color(s)

@media (forced-colors: active) {
@@ -279,7 +279,7 @@ 

⚠️ color(s)

-
+

You’ve made it this far!

diff --git a/docs/slides-cssingraz2024/slide.js b/docs/slides-cssingraz2024/slide.js index 4412a80..e54390c 100644 --- a/docs/slides-cssingraz2024/slide.js +++ b/docs/slides-cssingraz2024/slide.js @@ -6,7 +6,7 @@ const init = () => { }); let current = 0; const slide = (dir) => { - if (slideMap[current]) { + if (slideMap[current] && dir === 1) { const currentStep = parseInt(slides[current].getAttribute('data-current'), 10); if (currentStep + dir >= 0 && currentStep + dir <= slideMap[current]) { slides[current].setAttribute('data-current', '' + (currentStep + dir)); @@ -17,24 +17,31 @@ const init = () => { slides[current].removeAttribute('data-current'); current += dir; slides[current].setAttribute('data-current', dir === -1 ? '' + slideMap[current] : '0'); + const animate = window.matchMedia('(prefers-reduced-motion: no-preference)').matches; + slides[current].scrollIntoView({ behavior: animate ? 'smooth' : 'instant' }); + // history.pushState({}, window.title, `#${slides[current].id}`); }; const navigate = (event) => { + event.preventDefault(); const dir = {'ArrowUp': -1, 'ArrowLeft': -1, 'ArrowRight': 1, 'ArrowDown': 1}[event.key]; if (dir) slide(dir); }; - const act = (event) => { - const target = '#interactive'; - if (location.hash === target) { + document.querySelector('nav').innerHTML += ' '; + document.querySelector('nav button').addEventListener('click', (event) => { + const newState = event.target.getAttribute('aria-pressed') === 'false'; + event.target.setAttribute('aria-pressed', newState); + if (newState === true) { + const id = location.hash ? location.hash.slice(1) : ''; + const target = parseInt(id, 10); + if (target == id) current = target; slides[current].setAttribute('data-current', '0'); window.addEventListener('keydown', navigate); - } else if (event && new URL(event.oldURL).hash === target) { + slides[current].scrollIntoView({ behavior: 'instant' }); + } else { slides[current].removeAttribute('data-current'); - current = 0; window.removeEventListener('keydown', navigate); } - }; - act(); - window.addEventListener("hashchange", act); + }); }; if (document.readyState !== 'loading') { init(); diff --git a/docs/slides-cssingraz2024/style.css b/docs/slides-cssingraz2024/style.css index 766ae42..b22f399 100644 --- a/docs/slides-cssingraz2024/style.css +++ b/docs/slides-cssingraz2024/style.css @@ -10,14 +10,15 @@ html { color-scheme: dark light; font: 100%/1.5 sans-serif; } -html:not(:target) :is(nav, main) { +html:not(:has(button[aria-pressed="true"])) :is(nav, main) { max-inline-size: 68ch; margin-inline: auto; } body { margin: 0; - padding-block: 1em 3em; - padding-inline: .75em; + padding-block: 1rem 3rem; + padding-inline: .75rem; + overflow: hidden scroll; scroll-behavior: auto; } @media (prefers-reduce-motion: no-preference) { @@ -27,33 +28,84 @@ body { } nav { display: flex; - gap: .5em; - justify-content: start; - margin-block-end: 3em; + gap: .5rem; + justify-content: center; + position: relative; + z-index: 1; + margin-block-end: 3rem; + transition: opacity .3s ease-in-out; } -nav a { +nav :is(a, button) { + appearance: none; display: inline-block; - padding-block: .375em; - padding-inline: .5em; + position: relative; + padding-block: .375rem; + padding-inline: .5rem 3.875rem; background-color: CanvasText; color: Canvas; border: 2px solid; - border-radius: .375em; + border-radius: .375rem; + font: inherit; text-decoration: none; + text-overflow: ellipsis; + overflow: hidden; + white-space: pre; forced-color-adjust: none; } -[data-alternate]::after { - content: attr(data-alternate); - position: relative; - inset-block-start: -1px; - margin-inline-start: 1ex; - padding: 0 .25em; - background: Canvas; - border: 1px solid Canvas; +nav :is(a, button)::after { + position: absolute; + block-size: 1.5em; + inline-size: 4em; + inset-block-end: 50%; + inset-inline-end: .5rem; + margin-block-end: -.75em; + padding-inline: 1.25em 0; + background-color: Canvas; border-radius: .25em; color: CanvasText; font-size: 75%; + text-align: center; + white-space: normal; +} +nav a::after { + content: ' PDF'; +} +nav button::after { + content: ' OFF'; + border-radius: 1em; } +nav button[aria-pressed="true"]::after { + content: ' ON'; + padding-inline: 0 1.25em; +} +nav :is(a, button)::before { + content: ''; + position: absolute; + z-index: 1; + inset-block-end: 50%; + inset-inline-end: 2.5em; + margin-block-end: -.375em; + block-size: .75em; + aspect-ratio: 1; + background-color: CanvasText; +} +nav a::before { + mask: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjEyMCAtODQwIDcyMCA3MjAiPjxwYXRoIGQ9Ik00ODAtMzIwIDI4MC01MjBsNTYtNTggMTA0IDEwNHYtMzI2aDgwdjMyNmwxMDQtMTA0IDU2IDU4LTIwMCAyMDBaTTI0MC0xNjBxLTMzIDAtNTYuNS0yMy41VDE2MC0yNDB2LTEyMGg4MHYxMjBoNDgwdi0xMjBoODB2MTIwcTAgMzMtMjMuNSA1Ni41VDcyMC0xNjBIMjQwWiIvPjwvc3ZnPg==') center/contain no-repeat; +} +nav button::before { + border-radius: 50%; + transition: inset-inline .1s ease; +} +nav button[aria-pressed="true"]::before { + inset-inline-end: .75em; +} +@media (max-width: 22.49em) { + nav :is(a, button) { + font-size: 87.5%; + line-height: calc(23 / 14); + } +} + h1, h2, h3 { @@ -88,105 +140,105 @@ hr { border-block-end: 1px dotted; } -#interactive:target :not(a) { +html:has(button[aria-pressed="true"]) nav { + opacity: 0; +} +html:has(button[aria-pressed="true"]) :is(nav:focus-within, nav:hover) { + opacity: 1; +} +html:has(button[aria-pressed="true"]) main :not(a) { cursor: default; } -#interactive:target { +html:has(button[aria-pressed="true"]) { background-color: #000; color: #fff; } -#interactive:target body { - margin: 0; -} -#interactive:target, -#interactive:target body { +html:has(button[aria-pressed="true"]) body { block-size: 100dvh; - inline-size: 100vw; overflow: hidden; } -#interactive:target small, -#interactive:target blockquote footer { +html:has(button[aria-pressed="true"]) small, +html:has(button[aria-pressed="true"]) blockquote footer { font-size: 66.667%; } -#interactive:target nav, -#interactive:target .x { +html:has(button[aria-pressed="true"]) .x { display: none; } -#interactive:target a { +html:has(button[aria-pressed="true"]) main a { color: #d34b6c; } -#interactive:target mark { +html:has(button[aria-pressed="true"]) mark { display: inline-block; background-color: #d34b6c; color: #fff; outline: .125rem solid #d34b6c; } -#interactive:target main > div { +html:has(button[aria-pressed="true"]) main { position: absolute; - inset-block-start: -100dvh; - inset-inline-start: 0; + inset: 0; + overflow: hidden scroll; + scroll-snap-type: block mandatory; +} +html:has(button[aria-pressed="true"]) main > div { + position: relative; block-size: 100dvh; - inline-size: 100vw; overflow: hidden; + scroll-snap-align: start; transition: inset .5s ease-in; } -#interactive:target main > div:first-of-type { - inset-block-start: 0; - inset-inline-start: 100vw; -} -#interactive:target main > div:has(h1) { +html:has(button[aria-pressed="true"]) main > div:has(h1) { background: linear-gradient(to right, #000 calc(100vw - 70dvh), #0000 100vw) right no-repeat, url(uhrturm.webp) right/auto 100dvh no-repeat #000; } -#interactive:target main > div:has(h1) div { +html:has(button[aria-pressed="true"]) main > div:has(h1) div { inline-size: auto; } -#interactive:target div div { +html:has(button[aria-pressed="true"]) div div { margin-inline: 0; padding-block-start: 20dvh; padding-inline: 16px; } -#interactive:target div div, -#interactive:target blockquote { +html:has(button[aria-pressed="true"]) div div, +html:has(button[aria-pressed="true"]) blockquote { inline-size: max-content; max-inline-size: var(--size, 60vw); margin-inline: auto; } -#interactive:target :is(h1, h2, h3) { +html:has(button[aria-pressed="true"]) :is(h1, h2, h3) { font-size: 150%; } -#interactive:target :is(h1, h2, h3, ul, li, p, pre) { +html:has(button[aria-pressed="true"]) :is(h1, h2, h3, ul, li, p, pre) { margin-block: 0 .75em; } -#interactive:target pre { - padding-block: .5rem; - padding-inline: 1.5rem; +html:has(button[aria-pressed="true"]) pre { + padding-block: .5em; + padding-inline: 1.5em; background-color: #8884; tab-size: 4; } -#interactive:target :not(pre) > code { +html:has(button[aria-pressed="true"]) :not(pre) > code { background-color: #8884; - outline: .125rem solid #8884; + outline: .125em solid #8884; } -#interactive:target :is(h2, h3) { +html:has(button[aria-pressed="true"]) :is(h2, h3) { text-align: center; } -#interactive:target div > ul { +html:has(button[aria-pressed="true"]) div > ul { padding-inline-start: 0; } -#interactive:target ul ul li { +html:has(button[aria-pressed="true"]) ul ul li { margin-block-end: 0; } -#interactive:target p { +html:has(button[aria-pressed="true"]) p { text-align: var(--align, start); } -#interactive:target main > div > p { +html:has(button[aria-pressed="true"]) main > div > p { margin: 0; } -#interactive:target p > img:only-child { +html:has(button[aria-pressed="true"]) p > img:only-child { position: absolute; block-size: var(--size, 100dvh); margin-inline: auto; @@ -194,47 +246,44 @@ hr { inset-inline-start: var(--x, 50vw); transform: translateX(-50%); } -#interactive:target img:not(:only-child) { - max-inline-size: none; +html:has(button[aria-pressed="true"]) img:not(:only-child) { + max-inline-size: 100%; } -#interactive:target p > i:only-child { +html:has(button[aria-pressed="true"]) p > i:only-child { font-size: 300%; } - -#interactive:target main > div[data-current] { - inset-block-start: 0; - inset-inline-start: 0; -} -#interactive:target main > div[data-current] ~ div { - inset-block-start: 100dvh; -} -#interactive:target b { - position: absolute; +html:has(button[aria-pressed="true"]) b { + position: relative; + inset-block-start: -.5em; font-size: 66.667%; } -#interactive:target [data-step] { - opacity: 0; +/* html:has(button[aria-pressed="true"]) [data-step] { transition: opacity .3s ease-in; +} */ +html:has(button[aria-pressed="true"]) [data-current] [data-step] { + opacity: 0; } -#interactive:target [data-current="1"] :where([data-step="1"]), -#interactive:target [data-current="2"] :where([data-step="1"], [data-step="2"]), -#interactive:target [data-current="3"] :where([data-step="1"], [data-step="2"], [data-step="3"]), -#interactive:target main > div:has(~ [data-current]) [data-step], -#interactive:target [data-step]:has(~ [data-step="active"]) { +html:has(button[aria-pressed="true"]) [data-current="1"] :is([data-step="1"]), +html:has(button[aria-pressed="true"]) [data-current="2"] :is([data-step="1"], [data-step="2"]), +html:has(button[aria-pressed="true"]) [data-current="3"] :is([data-step="1"], [data-step="2"], [data-step="3"]), +html:has(button[aria-pressed="true"]) main > div:has(~ [data-current]) [data-step], +html:has(button[aria-pressed="true"]) [data-step]:has(~ [data-step="active"]) { opacity: 1; + transition: opacity .3s ease-in; } @media (orientation: landscape) { - #interactive:target { + html:has(button[aria-pressed="true"]) main { font-size: 4.5dvh; } } @media (orientation: portrait) { - #interactive:target div div, - #interactive:target blockquote { + html:has(button[aria-pressed="true"]) div div, + html:has(button[aria-pressed="true"]) blockquote { max-inline-size: 100%; } - #interactive:target img { + html:has(button[aria-pressed="true"]) img { max-block-size: 100%; + max-inline-size: none; } } @@ -248,15 +297,12 @@ hr { } html, body, - main { - height: 100%; - } + main, main > div { block-size: 100%; } main > div { position: relative; - block-size: 100%; padding-block-start: 40mm; padding-inline: 30mm; }