fdnd-agency / buurtcampus-oost

In Buurtcampus Oost zoeken studenten samen met bewoners, professionals, ondernemers, docenten en onderzoekers gezamenlijk naar oplossingen voor kansrijke uitdagingen uit de buurt.
MIT License
1 stars 11 forks source link

Menu popup maken met daarin de accessibility tools (html/css) #139

Open Annevd opened 2 months ago

Annevd commented 2 months ago

User story: Als bezoeker wil ik toegankelijkheid features zien en kunnen aanpassen

Taak: Button popup maken met daarin de accessibility tools (html/css)

Annevd commented 1 month ago

3/10 Menu met accessibility tools V1

Na aanleiding van mijn ontwerp en de oude code van de web minor (#125 ), heb ik het menu van de toegankelijkheidsfuncties gebouwd. Dit is nu nog met voornamelijk dezelfde code als de web minor, met een paar semantische verbeteringen in de HTML.

Dit menu is een component in de folder lib/organisms/, namelijk accessibility-menu.svelte. Deze staat in de +layout.svelte geïmporteerd, omdat het op elke pagina moet staan.

+layout.svelte:

<script>
  export let data;
  import { Menu, AccessibilityMenu, Footer } from '$lib/index.js';
  import Viewtransition from '$lib/viewtransition.svelte';
</script>

<Viewtransition />

<Menu />
<AccessibilityMenu />
<slot/>
<Footer {data}/>

Zo ziet de HTML er nu uit:

<form aria-label="Accessibility Options">
    <label for="menu" class="accessibilityIcon">
        <input type="checkbox" id="menu"> <!-- Dit zorgt voor het openen en sluiten van het menu -->
         <Accessibility />
    </label>
    <div class="accessibilityContent">
        <ul>
            <li>
                <label for="toggle-darkmode">
                    <div class="label-container">
                        <Moon/> <!-- Dit is een component voor de SVG -->
                        <span>Dark mode</span>
                    </div>
                    <input type="checkbox" id="toggle-darkmode" role="switch"> <!-- Dit zorgt voor het aan/uit zetten van de feature -->
                    <span class="state"> <!-- Deze spans maken de switch -->
                        <span class="container">
                          <span class="position"> </span>
                        </span>
                    </span>
                </label>
            </li>
            <li>
                <label for="font-size">
                    <div class="label-container">
                        <FontIncrease />
                        <span>Grotere letters</span>
                    </div>
                    <input type="checkbox" id="font-size" role="switch">
                    <span class="state">
                        <span class="container">
                          <span class="position"> </span>
                        </span>
                    </span>
                </label>
            </li>
            <li id="google_translate_element">
                <div class="label-container">
                    <Translate />
                    <span>Vertaal deze website</span>  
                </div>  
            </li>
        </ul>
    </div>
</form>

In onderstaande CSS kan je zien hoe het menu opent en sluit door middel van het veranderen van de waarde van left: ... ;:

form {
    position: fixed;
    top: 20vh;
    left: -14rem; /* Hidden by default */
    z-index: 10000;
    display: flex;
    flex-direction: row-reverse;
    width: calc(13rem + 5rem);
    transition: left .3s;
}

/* Menu is shown when checkbox is checked */
form:has(.accessibilityIcon input:checked) {
    transition: left .3s;
    left: -1rem; /* Slide out to show the menu */
}

/* Hide the content when checkbox is unchecked */
form:not(:has(.accessibilityIcon input:checked)) > .accessibilityContent ul {
    display: none;
    transition: left .3s;
}

/* Extra's */

/* When the accessibility menu is closed (i.e., the input checkbox inside `.accessibilityIcon` is not checked), 
   this CSS rule sets a fixed height for `.accessibilityContent`. This ensures that when the menu is hidden, 
   it shrinks to a specific height instead of expanding to fit its full content. */
form:not(:has(.accessibilityIcon input:checked)) > .accessibilityContent {
    height: 117.781px;
}

/* This hides the checkbox with `id^="menu"`, which is the checkbox controlling the visibility of the menu. 
   It is positioned off-screen (`left: -50%`) so it remains functional (it can still be checked/unchecked) 
   but invisible to users. The visibility is handled entirely by the image or label, not the checkbox itself. */
input[type="checkbox"][id^="menu"] {
    position: absolute;
    left: -50%;
}

De switches heb ik gemaakt aan de hand van deze bron van W3, om goede toegankelijkheid te behouden.

Omdat :has() in een aantal oude browserversies niet ondersteund word, wil ik mij nog gaan verdiepen in hoe ik de functionaliteit van het menu zoals het openen, sluiten, en de features anders kan aanpakken volgens het principe PE.

Ook probeerde ik van de switch een component te maken, wat ook gelukt was. Echter leverde dat mij beperkingen op bij het stylen van specifieke elementen en labels hier binnen. Hierdoor heb ik het voor nu toch niet als component gebruikt. Ik ben benieuwd of hier nog een andere oplossing voor is.

Andere dingen waar ik nog tegen aan loop/wat ik nog moet doen:

Hoe het er uit ziet op dit moment:

Image

Annevd commented 1 month ago

8/10 (Her)Analyse

Na het sparren over de functionaliteit en de features van het toegankelijkheidsmenu ben ik nog over een aantal dingen na gaan denken.

Bronnen

Annevd commented 1 month ago

8/10 (Her)Bouwen

Na de her analyse ben ik begonnen met het herbouwen van het menu, dit keer zonder :has(). Ook heb ik de code netter en overzichtelijker gemaakt.

Switch component

Om te beginnen heb ik van de switch een component gemaakt. Dit scheelt namelijk veel regels code in het hoofdcomponent van het menu en maakt alles een stuk overzichtelijker.

Om dit te doen heb ik in de lib/atoms/buttons/ folder een file genaamd switch.svelte aangemaakt. Hierin staat de HTML en CSS voor de switch, en de dynamische variabele voor id, zodat je in je hoofdcomponent daar dynamisch een id naam aan kan geven. De "toggle" waarde is een default, en word overschreven wanneer je dit in je hoofdcomponent veranderd.

lib/atoms/buttons/switch.svelte:

<script>
    export let id = "toggle";
</script>

<input type="checkbox" id={id} role="switch">
<span class="state">
    <span class="container">
      <span class="position"> </span>
    </span>
</span>

Om dit component te kunnen gebruiken moet ik hem nog exporteren in de index.js:

export { default as Switch } from '$lib/atoms/buttons/switch.svelte'

Om hem vervolgens in het hoofdcomponent te gebruiken moet je je component hier ook importeren. Vervolgens kan je in de script tag je custom id's aanmaken en toevoegen aan de switch:


<script>
import {Accessibility, Moon, Translate, FontIncrease, Switch} from '$lib/index.js';

let darkModeId = "toggle-darkmode";
let fontSizeId = "toggle-font-size";

</script>

 <label for="toggle-darkmode">
         <Switch id={darkModeId}/>
</label>
<label for="toggle-font-size">
         <Switch id={fontSizeId}/>
</label>

Menu functionaliteit

Het menu kan nu geopend en gesloten worden met alleen CSS en zonder :has(). Ik werk nu met de :checked pseudo-class waarmee ik een open en closed state kan meegeven aan de hand van of de checkbox geklikt wordt of niet. Dit is dus eigenlijk hetzelfde als de vorige code maar nu zonder :has().

Doordat je zonder :has() niet het form kan aanspreken op basis van de checkbox, is het ontwerp wel iets veranderd. De button schuift niet meer mee uit maar heeft een vaste positie waaruit het menu komt.

HTML:

<form aria-label="Accessibility Options"> <!-- Het menu zit in een form, met daarin de features -->
<!-- Deze input controlleert het openen/sluiten van het menu en is gelinkt met het label-->
    <input type="checkbox" class="toggle-menu" id="menu" aria-expanded={isExpanded ? "true" : "false"} aria-controls="accessibility-options" on:change={toggleMenu}>
    <label title="Accessibility Options" for="menu" class="icon">
         <Accessibility /> <!-- Dit is een component van de SVG -->
    </label>
    <div class="content" id="accessibility-options" aria-hidden={!isExpanded}>
        <ul>
            <li>
                <label for="toggle-darkmode"> <!-- Dit label is gelinkt aan de switch via het id en for-->
                    <span class="label-container">
                        <Moon/>Dark mode <!-- Dit is een component van de SVG-->
                    </span>
                    <Switch id={darkModeId}/> <!-- Dit is het component voor de switch met het id-->
                </label>
            </li>
            <li>
                <label for="toggle-font-size">
                    <span class="label-container">
                        <FontIncrease/>Increase Text <!-- Dit is een component van de SVG  -->
                    </span>
                    <Switch id={fontSizeId}/> <!-- Dit is het component voor de switch met het id -->
                </label>
            </li>
            <li id="google_translate_element">
                <span class="label-container">
                    <Translate/>Translate this website <!-- Dit is een component van de SVG-->
                </span>  
            </li>
        </ul>
    </div>
</form>

CSS:

/* Het form staat vast gepositioneerd rechts onderaan de pagina*/
form { 
    position: fixed;
    bottom: 2rem;
    right: 0;
    z-index: 10000;
    display: flex;
    flex-direction: column-reverse;
    align-items: flex-end;
    transition: right 0.3s;
}

/* De content (de ul met daarin de features) staat absoluut gepositioneerd bovenaan het randje van de open menu knop.
Deze staat standaard -15rem naar rechts, zodat het menu by default niet zichtbaar is*/
.content {
    position: absolute;
    bottom: 4rem;
    right: -15rem;
    background: #fff;
    height: 9rem;
    width: 15rem;
    border-radius: 0.6rem 0 0 0.6rem;
    transition: right 0.5s ease-in-out;
}

/* Wanneer de checkbox van het menu aangeklikt wordt schuift de content  in beeld*/
.toggle-menu:checked ~ .content{
    right: 0;
    transition: right 0.5s ease-in-out;
}

/* By default is de ul niet te zien, zodat er geen interactie mee kan worden gedaan als het menu dicht is */
.toggle-menu:not(:checked) ~ .content ul {
    display: none;
}

/* Om hierbij wel de slide out animatie te houden heeft de content een vaste hoogte, dit is zodat wanneer de ul op display:none gaat, de content niet gelijk verdwijnt */
.toggle-menu:not(:checked) ~ .content {
    height: 9rem;
}

/* Dit zorgt ervoor dat het menu te openen/sluiten is, zonder dat de default input te zien is*/
input[type="checkbox"][id^="menu"] {
    position: absolute;
    right: -50%;
}

Accessibility

In de HTML gebruik ik verschillende ARIA attributen om ervoor te zorgen dat het menu toegankelijk is voor mensen met keyboard navigation en screenreaders.

  1. aria-label="Accessibility Options" op het element: <form>

    • Doel: Geeft een tekst label aan het form element die visueel niet te zien is maar wel wordt aangekondigd door screenreaders. Dit zorgt ervoor dat mensen die afhankelijk zijn van deze hulp technologieën weten waar dit form voor dient.
    • Impact: Helpt gebruikers die het form niet kunnen zien de functionaliteit te begrijpen.
  2. aria-expanded={isExpanded ? "true" : "false"} op het element <input type="checkbox" class="toggle-menu">

    • Doel: Indiceert wanneer de geassocieerde content (het menu) die gecontroleerd wordt via de checkbox, open of gesloten is.
    • Waardes:
      • true: De content (menu) is uitgeklapt (visible).
      • false: De content is ingeklapt (hidden).
    • Impact: Communiceert de visibility state van het menu naar assistive technologies zoals screenreaders, zodat gebruikers weten of het menu open of dicht is.
  3. aria-controls="accessibility-options" op het element <input type="checkbox" class="toggle-menu">

    • Doel: Identificeert het element dat deze checkbox bestuurt. In dit geval wijst het naar het id="accessibility-options" element, de div waarin het menu zit.
    • Impact: Zorgt voor een duidelijke link tussen het controlling element (de checkbox), en de bestuurde content (het menu), wat er voor zorgt dat screenreaders makkelijker de interactie kunnen uitleggen.
  4. aria-hidden={!isExpanded} op het element: <div class="content" id="accessibility-options">

    • Doel: Indiceert of de content zichtbaar of onzichtbaar is voor gebruikers.
    • Waardes:
      • true: De content is verborgen en is niet toegankelijk tot screenreaders.
      • false: De content is zichtbaar en toegankelijk.
    • Impact: Zorgt ervoor dat wanneer de content vebrorgen is, dat screenreaders het niet zullen lezen. Dit attribuut werkt werkt samen met aria-expanded op de checkbox om een ​​compleet beeld te geven van de status van de inhoud.
  5. aria-controls="toggle-darkmode" and aria-controls="toggle-font-size" op het element <label for="toggle-darkmode"> and <label for="toggle-font-size">

    • Doel: Legt de link tussen het label en de corresponderende switch/checkbox input. Het helpt de gebruiker te begrijpen dat het kliken van het label de switch bestuurt.
    • Impact: Hiermee kan de gebruiker op de labeltekst klikken om de status van de checkbox/switch in of uit te schakelen, wat een standaard toegankelijkheidsfunctie is om de bruikbaarheid voor alle gebruikers te verbeteren, vooral voor gebruikers met motorische beperkingen.
Nazneen05x commented 2 days ago

Wow je bent echt goed in documenteren Anne! echt nettjes!