From 515610278a618c78e49ddd5410cb6a8952841685 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Wed, 21 Oct 2026 11:49:30 +0200 Subject: [PATCH] Accessibility fixes --- src/chunks/models.py | 6 +- src/chunks/templates/chunks/menu.html | 4 +- src/wolnelektury/static/2022/more.scss | 47 +++----- .../static/2022/styles/base/_global.scss | 18 +-- .../static/2022/styles/components/_lang.scss | 42 ++++--- .../static/2022/styles/components/_media.scss | 1 - .../static/2022/styles/layout/_button.scss | 2 - .../2022/styles/layout/_navigation.scss | 109 ++++++++++++------ .../2022/styles/vendors/_normalize.scss | 8 +- src/wolnelektury/static/js/main.js | 85 ++++---------- src/wolnelektury/templates/header.html | 42 +++++-- src/wolnelektury/templates/lang-switcher.html | 16 +-- src/wolnelektury/templates/main_page.html | 8 +- src/wolnelektury/templates/user_actions.html | 42 ++++--- 14 files changed, 227 insertions(+), 203 deletions(-) diff --git a/src/chunks/models.py b/src/chunks/models.py index fc03c1be0..7bca1e2dd 100644 --- a/src/chunks/models.py +++ b/src/chunks/models.py @@ -69,9 +69,13 @@ class MenuItem(models.Model): class Meta: ordering = ('order',) + @property + def is_separator(self): + return self.name == '-' + @property def final_name(self): - if self.name == '-': + if self.is_separator: return mark_safe('
') if self.name: return self.name diff --git a/src/chunks/templates/chunks/menu.html b/src/chunks/templates/chunks/menu.html index ed6669a5f..822162a17 100644 --- a/src/chunks/templates/chunks/menu.html +++ b/src/chunks/templates/chunks/menu.html @@ -1,7 +1,7 @@ {% for item in menu.menuitem_set.all %} -
  • +
  • {% if item.has_link %} - + {% endif %} {% if item.highlight %} diff --git a/src/wolnelektury/static/2022/more.scss b/src/wolnelektury/static/2022/more.scss index 1e6b692c4..ff590a5fa 100644 --- a/src/wolnelektury/static/2022/more.scss +++ b/src/wolnelektury/static/2022/more.scss @@ -1,24 +1,5 @@ @import "styles/utils/mixins"; -body.is-open { - height: 100%; - overflow-y: hidden; -} - -.l-navigation__menu { - .scrollable { - height: 100%; - overflow-y: scroll; - padding-bottom: 30px; - } -} - -.l-navigation__menu__links ul li a em { - font-style: normal; - color: #FFA500; - font-weight: 600; -} - .l-collections .l-books { width: 100%; } @@ -148,30 +129,25 @@ body.is-open { #user-menu { - //display: none; - + --focus-ring: #083F4D; + position-area: bottom span-right; position:absolute; - top: 60px; - z-index: 50; - - position: absolute; width: 186px; - top: 48px; - right: 45px; + top: 8px; /* yellow 900 */ background: #F7BA00; + border: none; box-shadow: 0px 0px 20px rgba(1, 129, 137, 0.2); border-radius: 10px; overflow: hidden; opacity:0; - pointer-events: none; - transition: 200ms opacity; + transition: all 350ms cubic-bezier(.0, 0, .2, 1), // $ease-out + display 350ms allow-discrete, + overlay 350ms allow-discrete; - &.is-open { - //display: block; - pointer-events: all; + &:popover-open { opacity: 100%; } @@ -199,6 +175,13 @@ body.is-open { } } +@starting-style { + #user-menu:popover-open { + opacity: 0; + transform: translateY(-10px); + } +} + form { label.required:before { diff --git a/src/wolnelektury/static/2022/styles/base/_global.scss b/src/wolnelektury/static/2022/styles/base/_global.scss index d81a0af56..07b97808e 100644 --- a/src/wolnelektury/static/2022/styles/base/_global.scss +++ b/src/wolnelektury/static/2022/styles/base/_global.scss @@ -6,11 +6,19 @@ box-sizing: border-box; } -:focus { - outline: $color-black auto 2px; +:root { + --focus-ring: #083F4D; +} + +:focus-visible { + outline: 2px solid var(--focus-ring); outline-offset: 2px; } +html { + scrollbar-gutter: stable; +} + html, body { -webkit-overflow-scrolling: auto; @@ -25,12 +33,6 @@ body { overflow-y: hidden; height: 100vh; } - - &.using-mouse { - *:focus { - outline: 0 !important; - } - } } .visibility-hidden { diff --git a/src/wolnelektury/static/2022/styles/components/_lang.scss b/src/wolnelektury/static/2022/styles/components/_lang.scss index ef5d7bc7f..8cc632dd1 100644 --- a/src/wolnelektury/static/2022/styles/components/_lang.scss +++ b/src/wolnelektury/static/2022/styles/components/_lang.scss @@ -4,9 +4,6 @@ width: 150px; right: 50px + 16px; - opacity: 0; - pointer-events: none; - transition: opacity 350ms $ease-out; z-index: $master-layer + 1; display: none; @@ -14,21 +11,20 @@ display: block; } - &.is-open { + &:has(.c-lang__list:popover-open) { .c-lang__button { .icon-arrow-down { transform: rotate(-180deg); } } - .c-lang__list { - transform: none; - opacity: 1; - pointer-events: all; - } } } .c-lang__button { + border: 0; + background: none; + padding: 0; + font: inherit; display: flex; align-items: center; color: $color-white; @@ -46,18 +42,31 @@ } } + .c-lang__list { - margin-top: 10px; + --focus-ring: #083F4D; + position-area: bottom span-right; + position: absolute; + inset: auto; + width: 150px; + margin: 10px 0 0 0; + border: 0; border-radius: 10px; background-color: #F7BA00; overflow: hidden; transform: translateY(-10px); opacity: 0; - transition: all 350ms $ease-out; - pointer-events: none; - display: flex; flex-direction: column; + transition: all 350ms $ease-out, + display 350ms allow-discrete, + overlay 350ms allow-discrete; + &:popover-open { + display: flex; + opacity: 1; + transform: none; + } + button { display: block; padding: 9px 20px; @@ -80,3 +89,10 @@ } } } + +@starting-style { + .c-lang__list:popover-open { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/src/wolnelektury/static/2022/styles/components/_media.scss b/src/wolnelektury/static/2022/styles/components/_media.scss index 9c5f34f94..6b15f8044 100644 --- a/src/wolnelektury/static/2022/styles/components/_media.scss +++ b/src/wolnelektury/static/2022/styles/components/_media.scss @@ -269,7 +269,6 @@ position: absolute; padding: 0; border: 0; - outline: 0; cursor: pointer; font-size: 0; background-color: transparent; diff --git a/src/wolnelektury/static/2022/styles/layout/_button.scss b/src/wolnelektury/static/2022/styles/layout/_button.scss index b1844d896..44d33507b 100644 --- a/src/wolnelektury/static/2022/styles/layout/_button.scss +++ b/src/wolnelektury/static/2022/styles/layout/_button.scss @@ -7,8 +7,6 @@ cursor: pointer; transition: all $ease-dynamic 350ms; background-color: $color-white; - outline: 0; - font-weight: bold; line-height: 17.6px; display: flex; diff --git a/src/wolnelektury/static/2022/styles/layout/_navigation.scss b/src/wolnelektury/static/2022/styles/layout/_navigation.scss index a47875b1a..9e3aafc54 100644 --- a/src/wolnelektury/static/2022/styles/layout/_navigation.scss +++ b/src/wolnelektury/static/2022/styles/layout/_navigation.scss @@ -3,6 +3,8 @@ body { } .l-navigation { + --focus-ring: #fff; + max-width: 100%; margin: 0 auto; background-color: #083F4D; @@ -41,14 +43,8 @@ body { .l-navigation__menu { opacity: 1; - pointer-events: all; - } - - .c-lang { - opacity: 1; - .c-lang__button { - pointer-events: all; - } + visibility: visible; + pointer-events: auto; } } } @@ -87,20 +83,9 @@ body { background: 0; padding: 0; margin: 0; - outline: 0; position: relative; } -.is-open { - .l-navigation__logo { - z-index: $master-layer + 1; - } - .l-navigation__button { - z-index: $master-layer + 1; - } -} - - .l-naviagion__search { width: 60%; max-width: 580px; @@ -123,7 +108,6 @@ body { border-radius: 52px; width: 100%; max-width: 580px; - outline: 0; @include rwd($break-menu) { font-size: 18px; @@ -138,9 +122,10 @@ body { position: relative; height: 44px; - .icon-liked { + .user-liked { color: #85C7CC; font-size: 30px; + line-height: 30px; margin-right: 25px; } @@ -174,6 +159,9 @@ body { .user { margin-right: 25px; + background: none; + border: none; + padding: 0; } } @@ -226,24 +214,51 @@ body { } .l-navigation__menu { - position: fixed; - top: 0; left: 0; - width: 100%; height: 100%; - background-color: #083F4D; - z-index: $master-layer; - padding-top: 50px; - opacity: 0; - pointer-events: none; - transition: opacity 350ms $ease-out; - - @include rwd($break-menu) { - padding-top: 93px; - } - - .l-container { - display: flex; + margin: 0; + padding: 0; + border: 0; + max-width: none; + max-height: none; + width: 100%; + height: 100%; flex-direction: column; - } + background-color: #083F4D; + opacity: 0; + transition: opacity 350ms $ease-out; + // Gdy + // https://caniuse.com/wf-display-animation, https://caniuse.com/wf-overlay + // display 350ms allow-discrete, + // overlay 350ms allow-discrete; + + &[open] { + display: flex; + opacity: 1; + } + &:not([open]) { + pointer-events: none; + } + // https://caniuse.com/wf-display-animation, https://caniuse.com/wf-overlay + &.is-closing { + opacity: 0; + pointer-events: none; + } + + .l-navigation__menu__top { + padding: 3px 0; + @include rwd($break-menu) { + padding: 12px 0; + } + } + .scrollable { + height: 100%; + overflow-y: auto; + padding-bottom: 30px; + + .l-container { + display: flex; + flex-direction: column; + } + } .l-navigation__user-bar { width: 100%; @@ -284,6 +299,18 @@ body { } } +body:has(dialog[open]) { + overflow: hidden; +} + +@starting-style { + .l-navigation__menu[open] { + opacity: 0; + } +} +@media (prefers-reduced-motion: reduce) { + .l-navigation__menu { transition: none; } +} .l-navigation__menu__blocks { position: relative; @@ -352,6 +379,12 @@ body { &:hover { text-decoration: underline; } + + em { + font-style: normal; + color: #FFA500; + font-weight: 600; + } } hr { diff --git a/src/wolnelektury/static/2022/styles/vendors/_normalize.scss b/src/wolnelektury/static/2022/styles/vendors/_normalize.scss index 68c1ec67e..49aba02e6 100644 --- a/src/wolnelektury/static/2022/styles/vendors/_normalize.scss +++ b/src/wolnelektury/static/2022/styles/vendors/_normalize.scss @@ -303,13 +303,7 @@ button::-moz-focus-inner, /** * Restore the focus styles unset by the previous rule. */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} +/* WL: removed */ /** * Correct the padding in Firefox. diff --git a/src/wolnelektury/static/js/main.js b/src/wolnelektury/static/js/main.js index 68d35fa24..b646bf450 100644 --- a/src/wolnelektury/static/js/main.js +++ b/src/wolnelektury/static/js/main.js @@ -1,67 +1,37 @@ // JS Menu (function () { - let button = $('.js-menu'); - let menu = $('.l-navigation'); - let menuLinks = menu.find('a'); - - button.on('click', function() { - if(!$(this).hasClass('is-active')) { - $(this).addClass('is-active'); - menu.addClass('is-open'); - $('body').addClass('is-open'); - button.find('.bar').addClass('animate'); - menuLinks.attr('tabindex', 0); - } else { - $(this).removeClass('is-active'); - menu.removeClass('is-open'); - $('body').removeClass('is-open'); - button.find('.bar').removeClass('animate'); - menuLinks.attr('tabindex', -1); - } - }); - - $(document).keyup(function(e) { - if (e.keyCode === 27) { - button.removeClass('is-active'); - menu.removeClass('is-open'); - $('body').removeClass('is-open'); - button.find('.bar').removeClass('animate'); - menuLinks.attr('tabindex', -1); + const dialog = document.getElementById('main-menu'); + let buttonOn = $('.js-menu'); + let buttonOff = $('.js-menu-close'); + + async function closeMenu() { + // Może być od razu dialog.close bez is-closing, gdy przeglądarki nadrobią + // https://caniuse.com/wf-display-animation, https://caniuse.com/wf-overlay + if (!dialog.open || dialog.classList.contains('is-closing')) return; + dialog.classList.add('is-closing'); + buttonOn.find('.bar').removeClass('animate'); + buttonOff.find('.bar').removeClass('animate'); + await Promise.allSettled(dialog.getAnimations().map(a => a.finished)); + dialog.close(); } - }); -})(); - -// User menu. -(function() { - let button = $('.l-navigation__actions .user'); - let menu = $('#user-menu'); - let menuLinks = menu.find('a'); - - button.on('click', function() { - if (!menu.hasClass('is-open')) { - menu.addClass('is-open'); - menuLinks.attr('tabindex', 0); - } else { - menu.removeClass('is-open'); - menuLinks.attr('tabindex', -1) - } - return false; + dialog.addEventListener('close', () => { + dialog.classList.remove('is-closing'); }); - $(document).keyup(function(e) { - if (e.keyCode === 27) { - menu.removeClass('is-open'); - menuLinks.attr('tabindex', -1); - } + document.querySelector('.js-menu').addEventListener('click', () => { + dialog.showModal(); + buttonOn.find('.bar').addClass('animate'); + buttonOff.find('.bar').addClass('animate'); }); - $(document).click(function() { - menu.removeClass('is-open'); - menuLinks.attr('tabindex', -1); + dialog.querySelector('.js-menu-close').addEventListener('click', closeMenu); + dialog.addEventListener('cancel', e => { + e.preventDefault(); + closeMenu(); }); - })(); + // Ebook/Audiobook Btns (function() { let button = $('.c-media__btn button:not(.l-button--media--full)'); @@ -566,13 +536,6 @@ window.location.reload(true); }); - $('.c-lang').on('click', function() { - !$(this).toggleClass('is-open'); - }); - - - - $(".c-media__settings > i").on('click', function() { $(".c-media__settings").toggleClass('active'); diff --git a/src/wolnelektury/templates/header.html b/src/wolnelektury/templates/header.html index 3cc48515a..7b257b354 100644 --- a/src/wolnelektury/templates/header.html +++ b/src/wolnelektury/templates/header.html @@ -11,7 +11,7 @@ {% annoy_banner_blackout %} -