Kop 1

tagline

Modaal venster

Een modaal venster laat na een gebeurtenis extra inhoud zien kan weer worden gesloten. Je kunt hem gebruiken voor: log-in of registratievensters en natuurlijk als lightbox bij een foto-gallerij.
Een modaal venster is een venster dat opspringt en een aparte inhoud weergeeft. In onze uitwerking is deze inhoud in eerste instantie al in de DOM aanwezig. Maar het JS stopt deze inhoud in een variabele en haalt die inhoud dan uit de DOM. Wordt het modale venster geopend, dan haalt het de DOM-node weer uit die variabele en stopt het in het modale venster.

Leerdoelen

  • absoluut positioneren en postion: fixed
  • centreren met CSS Grid;
  • DOM bewerkingen:
    • elementen maken: document.createElement();
    • elementen een class geven: .className;
    • elementen toevoegen: .append en .prepend();
    • elementen verwijderen: .remove();
  • herhaling animatie in CSS

Modaal venster 0: het resultaat (00:00:38)

Hier is een hele tutorialreeks gemaakt om te laten zien hoe je een eigen modaal venster maakt.
Je ziet dat de inhoud die in de modale vensters getoond moet worden, uit de DOM gehaald wordt. Als er op een knop geklikt wordt, moet de passende inhoud tevoorschijn komen.
Je ziet dat proces gebeuren als je de pagina inspecteert.

In het modale venster is ook een sluitknop die het modaal sluit. Dat gebeurt ook als je op de achtergond van het modaal klikt.
Daarnaast ben je in de gelegenheid om zelf animaties toe te voegen.

Modaal venster 1: de opzet (00:02:58)

Hier zie je de een beetje het plan om met HTML, CSS en JS een modaal venster te maken. De inhoud die in het modaal venster tevoorschijn kan komen is feitelijk al in de mark-up aanwezig. Het script stopt dei eerst in en variabele en verwijdert hem dan uit de DOM. Op het moment dat er een klikje op een thumbnail is, wordt het modaal gemaakt en de juiste inhoud uit de variabele gehaald.

Modaal venster 2: de markup (00:05:50)

Hier kijken we naar de markup die is meegeleverd op: https://github.com/Theo-denBlanken/materiaal-lightbox. Om straks in het script de inhoud voor de modalen te selecteren, geven we dat soort inhoud een classnaam. We bedenken ook een classnaam voor de inhoud, die niet uit de DOM verwijderd hoeft te worden en waar de gebruiker op gaat klikken om een modaal te openen

Modaal venster 3: modale inhoud in array (00:07:33)

De inhoud voor de modalen wordt uit de DOM in een array gestopt. Eerst variabele maken en daar de inhoud met document.querySelectorAll() vullen.
De selector is de selector zoals je dat met CSS zou doen. Deze variabele is een NodeList geworden en via de inspector van je browser kun je dat zelf constateren. Het heeft iets weg van een array, maar is dat nog niet precies. Daarom maken we een lege array en met en for-loop vullen we die dan vanuit de node-list. De inhouden kunnen tegelijkertijd met die for-loop worden verwijderd uit de DOM. Ook met de inspector zijn ze dan niet meer terug te vinden.

Ook maken we een variabele van de items in de de DOM, waar op geklikt moet gaan worden.

Modaal venster 4: layout overige elementen (00:08:11)

Na het verwijderen van de modale inhoud, moeten de overige elementen overzichtelijk worden gepresenteerd. Met CSS Grid worden deze in zoveel kolommen geplaatst als de viewport toestaat. De kolommen zijn minimaal 300px breed.
De afbeeldingen blijken niet dezelfde verhoudingen te hebben. Als we de breedte vastleggen op de beschikbare kolombreedte en de hoogte vast op 200px, worden de afbeeldingen gestretched. Om dat tegen te gaan geven we de afbeeldingen een eigenschap object-fit met de waarde cover. Hierdoor wordt er en niet-passend deel van de afbeelding weggesneden. Met object-position kun dan aangeven welk deel je in ieder geval behouden wilt.

Modaal venster 5: paragraaf boven de afbeelding (00:06:28)

De overgebleven afbeeldingen hebben een paragraaf die onder de afbeelding staat. Deze tekst wensen we op de afbeelding.
Dat kan met CSS Grid. We maken een grid met 1 kolom en zowel de afbeelding als de paragraaf starten bij rij 1 en kolom 1. Dan forceert het grid ze boven elkaar.

Modaal venster 6: bij een klik de juiste inhoud oproepen: (00:0:47)

Bij een modaal is het van belang dat de bijpassende inhoud er komt. We maken daarom een functie die de modaal maakt en deze fucnctie wordt met een eventListener aangeroepen. Om dit voor alle aanwezige afbeeldingen te doen, gebruiken we een for-lus. En bij het aanroepen van de functie geven we de iterator i als parameter mee aan die functie. Een test met console.log() test of dit werkt.

Modaal venster 7: achtergrond modaal maken (00:05:56

Nu we de inhoud onder bereik hebben gaan we hier aan de slag om de achtergond van het modaal te maken. We maken een div met een transparante achtergrond, die over de huidige elementen gaat lopen.
Dit gaat nu met position: absolute, dat blijkt bij scrollen nog niet de beste oplossing. Later zetten dat om in position:fixed;. De breedte en hoogte zijn natuurlijk 100vw en 100vh.

Modaal venster 8: inhoud aan modaal toevoegen (00:04:50)

Nu de modaal er is kunnen we op dezelfde manier een element maken en daar de innerHTML aan toevoegen die uit de bijpassende deel van de inhoudsarray te halen is. Om het goed leesbaar te maken, beperken we de breedte van de inhouds-div en geven we die een witte achtergrond.

modaal venster 9: de inhoud centreren (00:02:05

Om de inhoud te centreren maken we weer gebruik van CSS Grid. De parent is de modale achtergrond en heeft maar 1 kolom. De inhoud van het modaal is het enige child. Daarom geven we de parent de eigenschappen justify-items en align-items beide de waarde center.

Modaal venster 10: het modaal sluiten (00:06:03

De gebruiker moet het modaal ook kunnen sluiten. We maken daar eenvoudig een functie voor zodat we later 2 manieren hebben om deze aan te roepen. Het modaal krijgt een id, zodat het script deze makkelijk kan selecteren en met de .remove() kan verwijderen.
Om de functie te kunnen aanroepen, geven we het modaal ook nog een eventListener.
Als dit blijkt te werken, dan blijkt ook een klik op de inhoud van de modaal het sluiten op te roepen. Dat is natuurlijk niet gewenst. De modaalinhoud blijkt de klik gewoon door te geven. Dit verhinderen we dan met event.stopPropagation().

Modaal venster 11: scrollmogelijkheden (00:03:00)

De pagina bevat meer inhoud dat in de viewport past. Als we scrollen gaat het modaal mee het venster uit.
Dit lossen we op door position: absolute te vervangen door position: fixed. De modaal staat dan niet vast op het document, maar op de viewport.
Als er teveel inhoud voor de modale inhoud is, moet er ook gescrolld kunnen worden. We beperken daarom naast de maximale breedte ook de maximale hoogte van de inhoud. Vervolgens geven we die inhoud een overflow: auto zodat indien nodig er een scrollbalk is.

Modaal venster 12: sluitknop maken (00:09:24)

Behalve een klik op de achtergrond helpen we de gebruiker met een sluitknop. We zoeken daarvoor een symbool. Dat kan met Unicode: https://unicode-table.com/en/#control-character maar ook met FontAwesome. Daar kun je een Kitcode aanvragen voor een scriptverwijzing van FontAwesome. Dan kun je je gewenste icon uitzoeken en dan levert de pagina https://fontawesome.com/icons/times-circle?style=solid jou de gewenste classname voor een i-element voor jouw icon.

Deze gaan we dan met JavaScript weer met .createElement() maken. We zijn dat al eerder in deze reeks tegengekomen en ook de class-naam weten we nu welweer te maken. Het element krijgt naast de 2 noodzakelijke class-namen van FontAwesome een extra class om het te kunnen stijlen.
Het toevoegen gaat nu niet NA de bestaande elementen in de inhoud van het modaal maar ERVOOR met .prepend().

Modaal venster 13: animatie met CSS (00:05:56)

Een eigen modaal venster heeft als voordeel dat we hem ook zelf kunnen stijlen en in dit geval animeren. We doen dat met de animation-eigenschap van CSS.
Met de @keyframes (en bijpassende pre-fixes) kunnen we eenvoudig de margin-top van 90vh animeren naar 0. De richting is forwards en de easing kan je zelf instellen met cubic-bezier: https://cubic-bezier.com/. Hier is voor een terugslag gekozen. ease-in-out had natuurlijk ook gekund.

Opgave

Voeg nu zelf een linkje boven aan je pagina toe, zodat een klik daarop een modaal opent met een inlog en/of registratievenster.

Bonusopdracht: elastische beweging met GSAP (00:06:48)

De animatie kan ook met een JS-library worden uitgevoerd. Zet daarvoor eerst met een comment je CSS-animatie uit.
Koppel de library van Greensock (GSAP). Dat kan via download, maar we gebruiken hier de CDN die je op https://greensock.com/ vindt. Doe dit voor de plaats van je eigen JS, omdat de library eerst geladen moet worden.
In de CSS plaatsen we dan de inhoud met margin-top: 90vh naar beneden.
In https://greensock.com/docs/v3/GSAP/Tween vindt je de documentatie voor de eenvoudige tween: gsap.to(). In deze functie moet je vervolgens de noodzakelijke argumenten meegeven zoals welk element je animeert (hier is dat de variabele van de inhoud van het modaal) welke eigenschap, je animeert: hier marginTop (let dus op het gebruik van camelcase), de tijdsduur in seconde en de easing. Om dat laatste is het hier ons te doen. Op https://greensock.com/docs/v3/Eases vind je vele mogelijkheden, waar je mee kunt spelen. We kiezen elastisch en zelfs daarmee kun je nog parameters instellen.
De browser eist zo wel veel van het systeem, wellicht ziet jouw animatie er op jouw systeem er wel vloeiender uit.


Inleveren

  • Na afloop plaats je deze training online in je bewijzenmap;
  • Valideer jouw pagina's op Markup Validation Service van W3C.
  • De validatie icoontjes staan al in de footer. Code vind je bij https://github.com/Theo-denBlanken/validatie-W3C;
  • Plaats jouw code op in een aparte reposetry op GitHub en plaats jouw uitwerking online;
  • Maak in jouw GitHub-repo een README.md met daarin temnminste een link naar jouw online uitwerking.
  • Plaats de GitHub-link in ELO Magister bij de FRO-opdracht modaal venster

Vervolgdracht:
Modaal venster 14: modaal object (00:12:25)

Link naar aparte presentatie

Het script werkt wel maar kan geoptimaliseerd worden.
Er zijn nu 3 variabelen en 2 functies en 2 losse for-lussen.
Deze kunnen in één object ondergebracht worden. Dit object heeft dan 3 eigenschappen (properties) en 3 methods.
De basisstructuur is dan

  const nObject = {
     eigenschap1 : waarde,
     eigenschap2 : waarde,
     eigenschap3 : [],
     method1: function() { 
         ...opdrachten ...
     },
     method2: function(parameter) { 
        ... opdrachten (met parameter) ...
     },
     init: function() { 
        ... opdrachten ...
     }
  }

In de method init() komen dan de opdrachten, buiten de functies stonden.
In ons geval zijn dat de beide for-lussen.
Als je de init-method wil aanroepen, kan dat met nObject.init().
je roept hem dan aan van buiten het object, in deze instructie zelfs vanuit het HTML-document.
Als je binnen het object naar een eigenschap verwijst, kan dat met het this-keyword.
this.eigenschap2 bijvoorbeeld geeft de waarde van eigenschap2 in nObject.
Merk op dat het this-keyword hier dus anders verwijst dan bij een event.