Het doel van het Open UI-initiatief is om het voor ontwikkelaars gemakkelijker te maken geweldige gebruikerservaringen te creëren. Om dit te bereiken, proberen we de meest voorkomende problemen aan te pakken waarmee ontwikkelaars te maken krijgen. We kunnen dit doen door betere, ingebouwde API's en componenten voor het platform aan te bieden.
Een van die probleemgebieden zijn pop-ups, die in Open UI worden aangeduid als "Popovers".
Popovers hebben al lange tijd een nogal controversiële reputatie. Dit komt deels door de manier waarop ze worden gebouwd en geïmplementeerd. Het is geen eenvoudig patroon om goed te bouwen, maar ze kunnen veel waarde opleveren door gebruikers naar bepaalde dingen te leiden of hen attent te maken op de inhoud van je site – vooral wanneer ze op een smaakvolle manier worden gebruikt.
Bij het bouwen van pop-ups zijn er vaak twee belangrijke aandachtspunten:
- Hoe zorg je ervoor dat het boven de rest van je content op een geschikte plek wordt geplaatst?
- Hoe maak je het toegankelijk (toetsenbordvriendelijk, focusseerbaar, enzovoort)?
De ingebouwde Popover API heeft verschillende doelen , die allemaal hetzelfde overkoepelende doel hebben: het voor ontwikkelaars gemakkelijk maken om dit patroon te implementeren. Enkele van die doelen zijn:
- Maak het eenvoudig om een element en de bijbehorende subelementen boven de rest van het document weer te geven.
- Maak het toegankelijk.
- Voor de meeste gangbare functionaliteiten (lichte sluiting, singleton, stapelen, enzovoort) is geen JavaScript vereist.
De volledige specificaties voor pop-ups vind je op de OpenUI-website .
Browsercompatibiliteit
Waar kun je de ingebouwde Popover API nu gebruiken? Deze wordt in Chrome Canary ondersteund achter de vlag "Experimentele webplatformfuncties" (op het moment van schrijven).
Om die vlag in te schakelen, open je Chrome Canary en ga je naar chrome://flags . Schakel vervolgens de vlag "Experimentele webplatformfuncties" in.
Er is ook een Origin-proefversie beschikbaar voor ontwikkelaars die dit in een productieomgeving willen testen.
Tot slot is er een polyfill in ontwikkeling voor de API. Bekijk de repository op github.com/oddbird/popup-polyfill .
Je kunt controleren of pop-upondersteuning beschikbaar is met:
const supported = HTMLElement.prototype.hasOwnProperty("popover");
Huidige oplossingen
Wat kun je momenteel doen om je content boven alles uit te laten stijgen? Als je browser het ondersteunt, kun je het HTML-dialoogvenster gebruiken. Je moet het wel in de "modale" vorm gebruiken. En hiervoor is JavaScript nodig.
Dialog.showModal();
Er zijn een aantal aandachtspunten met betrekking tot toegankelijkheid. Het is aan te raden om bijvoorbeeld a11y-dialog te gebruiken als de website bedoeld is voor gebruikers van Safari ouder dan versie 15.4.
Je kunt ook een van de vele beschikbare bibliotheken gebruiken die pop-ups, waarschuwingen of tooltips weergeven. Veel daarvan werken op een vergelijkbare manier.
- Voeg een container toe aan de body om pop-ups weer te geven.
- Zorg ervoor dat het boven alles uitsteekt.
- Maak een element aan en voeg dit toe aan de container om een pop-upvenster weer te geven.
- Verberg het door het popover-element uit de DOM te verwijderen.
Dit vereist een extra afhankelijkheid en meer beslissingen voor ontwikkelaars. Het vereist ook onderzoek om een oplossing te vinden die alles biedt wat je nodig hebt. De Popover API is ontworpen om tegemoet te komen aan veel scenario's, waaronder tooltips. Het doel is om al die veelvoorkomende scenario's af te dekken, zodat ontwikkelaars niet nog een extra beslissing hoeven te nemen en zich kunnen concentreren op het bouwen van hun eigen gebruikerservaringen.
Je eerste pop-up
Dit is alles wat je nodig hebt.
<div id="my-first-popover" popover>Popover Content!</div>
<button popovertoggletarget="my-first-popover">Toggle Popover</button>
Maar wat gebeurt hier?
- Je hoeft het popover-element niet in een container te plaatsen of iets dergelijks; het is standaard verborgen.
- Je hoeft geen JavaScript te schrijven om het te laten verschijnen. Dat wordt geregeld door het attribuut
popovertoggletarget. - Wanneer de popover verschijnt, wordt deze naar de bovenste laag gepromoveerd. Dat betekent dat deze boven het
documentin de viewport wordt geplaatst. Je hoeft je geen zorgen te maken overz-indexof de positie van je popover in de DOM. Deze kan diep in de DOM genesteld zijn, met clipping ancestors. Je kunt ook via de ontwikkelaarstools zien welke elementen zich momenteel in de bovenste laag bevinden. Lees dit artikel voor meer informatie over de bovenste laag.

- Je krijgt de optie "Licht sluiten" standaard. Daarmee bedoelen we dat je de pop-up kunt sluiten met een sluitsignaal, bijvoorbeeld door buiten de pop-up te klikken, met het toetsenbord naar een ander element te navigeren of op de Esc- toets te drukken. Open de pop-up opnieuw en probeer het uit!
Wat krijg je nog meer met een popover? Laten we het voorbeeld eens verder uitwerken. Bekijk deze demo met wat inhoud op de pagina.
Die zwevende actieknop heeft een vaste positionering met een hoge z-index .
.fab {
position: fixed;
z-index: 99999;
}
De inhoud van de popover is genest in de DOM, maar wanneer je de popover opent, wordt deze boven dat element met vaste positie geplaatst. Je hoeft geen stijlen in te stellen.
Je ziet misschien ook dat de popover nu een ::backdrop pseudo-element heeft. Alle elementen in de bovenste laag krijgen een aanpasbaar ::backdrop pseudo-element. In dit voorbeeld wordt ::backdrop gestyled met een achtergrondkleur met een verlaagde transparantie en een achtergrondfilter dat de onderliggende inhoud vervaagt.
Een popover stylen
Laten we ons nu richten op het stylen van de popover. Standaard heeft een popover een vaste positie en een bepaalde opvulling (padding). Ook heeft deze display: none . Je zou dit kunnen overschrijven om een popover weer te geven. Maar dat zou de popover niet naar de bovenste laag verplaatsen.
[popover] { display: block; }
Ongeacht hoe je je popover promoot, zodra je een popover naar de bovenste laag promoot, moet je deze mogelijk nog indelen of positioneren. Je kunt de bovenste laag niet selecteren en dan zoiets doen als...
:open {
display: grid;
place-items: center;
}
Standaard wordt een popover in het midden van het scherm geplaatst met margin: auto . In sommige gevallen wilt u de positionering echter expliciet bepalen. Bijvoorbeeld:
[popover] {
top: 50%;
left: 50%;
translate: -50%;
}
Als je de inhoud van je popover wilt rangschikken met behulp van CSS Grid of Flexbox, is het wellicht verstandig om dit in een `<div>`-element te plaatsen. Anders moet je een aparte regel definiëren die de display aanpast zodra de popover zich in de bovenste laag bevindt. Als je dit standaard instelt, wordt de popover standaard weergegeven en wordt display: none overschreven.
[popover]:open {
display: flex;
}
Als je die demo hebt uitgeprobeerd, zul je merken dat de popover nu in- en uitgaat. Je kunt popovers in- en uit laten gaan door de pseudo-selector :open te gebruiken. De pseudo-selector :open komt overeen met popovers die zichtbaar zijn (en zich dus in de bovenste laag bevinden).
Dit voorbeeld gebruikt een aangepaste eigenschap om de overgang aan te sturen. Je kunt ook een overgang toepassen op de ::backdrop van de popover.
[popover] {
--hide: 1;
transition: transform 0.2s;
transform: translateY(calc(var(--hide) * -100vh))
scale(calc(1 - var(--hide)));
}
[popover]::backdrop {
transition: opacity 0.2s;
opacity: calc(1 - var(--hide, 1));
}
[popover]:open::backdrop {
--hide: 0;
}
Een tip is om overgangen en animaties te groeperen onder een mediaquery voor beweging. Dit kan ook helpen om de timing te behouden. Dit komt omdat je geen waarden kunt delen tussen de popover en de ::backdrop via een aangepaste eigenschap.
@media(prefers-reduced-motion: no-preference) {
[popover] { transition: transform 0.2s; }
[popover]::backdrop { transition: opacity 0.2s; }
}
Tot nu toe heb je gezien hoe je popovertoggletarget gebruikt om een popover weer te geven. Om deze te sluiten, gebruiken we "Light dismiss". Maar je hebt ook de attributen popovershowtarget en popoverhidetarget tot je beschikking. Laten we een knop aan een popover toevoegen waarmee deze verborgen kan worden en de toggle-knop aanpassen zodat deze popovershowtarget gebruikt.
<div id="code-popover" popover>
<button popoverhidetarget="code-popover">Hide Code</button>
</div>
<button popovershowtarget="code-popover">Reveal Code</button>
Zoals eerder vermeld, omvat de Popover API meer dan alleen ons traditionele idee van pop-ups. Je kunt er allerlei scenario's mee bouwen, zoals meldingen, menu's, tooltips, enzovoort.
Sommige van die scenario's vereisen andere interactiepatronen. Interacties zoals hoveren. Het gebruik van een popoverhovertarget attribuut is geëxperimenteerd, maar is momenteel niet geïmplementeerd.
<div popoverhovertarget="hover-popover">Hover for Code</div>
Het idee is dat je met de muis over een element beweegt om het doelelement te tonen. Dit gedrag kan worden geconfigureerd via CSS-eigenschappen. Deze CSS-eigenschappen definiëren de tijdsduur waarop een popover reageert wanneer je met de muis over een element beweegt. Het standaardgedrag waarmee geëxperimenteerd werd, was dat een popover verscheen na een expliciete :hover van 0.5s . Vervolgens was een lichte sluiting of het openen van een andere popover nodig om de popover te sluiten (hierover later meer). Dit kwam doordat de duur van het verbergen van de popover was ingesteld op Infinity .
In de tussentijd zou je JavaScript kunnen gebruiken om die functionaliteit te polyfillen.
let hoverTimer;
const HOVER_TRIGGERS = document.querySelectorAll("[popoverhovertarget]");
const tearDown = () => {
if (hoverTimer) clearTimeout(hoverTimer);
};
HOVER_TRIGGERS.forEach((trigger) => {
const popover = document.querySelector(
`#${trigger.getAttribute("popoverhovertarget")}`
);
trigger.addEventListener("pointerenter", () => {
hoverTimer = setTimeout(() => {
if (!popover.matches(":open")) popover.showPopover();
}, 500);
trigger.addEventListener("pointerleave", tearDown);
});
});
Het voordeel van het expliciet weergeven van een pop-upvenster bij het hoveren is dat het ervoor zorgt dat de actie van de gebruiker opzettelijk is (bijvoorbeeld, een gebruiker beweegt de muiswijzer over een object). We willen de pop-up niet tonen tenzij dat de bedoeling van de gebruiker is.
Probeer deze demo eens uit, waarbij je met de muis over het doelwit kunt bewegen terwijl het venster is ingesteld op 0.5s .
Voordat we enkele veelvoorkomende gebruiksscenario's en voorbeelden bekijken, laten we eerst een paar dingen doornemen.
Soorten popovers
We hebben het interactiegedrag zonder JavaScript al behandeld. Maar hoe zit het met het gedrag van popovers in het algemeen? Wat als je geen "Licht sluiten" wilt? Of als je een singleton-patroon wilt toepassen op je popovers?
Met de Popover API kunt u drie typen popovers specificeren die verschillen in gedrag.
[popover=auto]/[popover] :
- Ondersteuning voor geneste elementen. Dit betekent niet alleen geneste elementen in de DOM. De definitie van een ancestrale popover is er een die:
- gerelateerd door DOM-positie (kind).
- verwant door het activeren van attributen op kindelementen zoals
popovertoggletarget,popovershowtarget, enzovoort. - verbonden via het
anchorattribuut (CSS Anchoring API in ontwikkeling).
- Licht afwijzen.
- Door het openen worden andere popovers gesloten die geen voorouderlijke popovers zijn. Experimenteer met de onderstaande demo die laat zien hoe geneste popovers met voorouderlijke popovers werken. Zie hoe het wijzigen van sommige
popoverhidetarget/popovershowtargetinstanties naarpopovertoggletargetde zaken verandert. - Als je één element in de stapel verwijdert, worden alle elementen verwijderd, maar als je één element in de stapel verwijdert, worden alleen de elementen erboven in de stapel verwijderd.
[popover=manual] :
- Sluit geen andere pop-ups.
- Geen licht, wegwezen.
- Vereist expliciete sluiting via een triggerelement of JavaScript.
JavaScript API
Wanneer je meer controle over je popovers nodig hebt, kun je JavaScript gebruiken. Je hebt dan de mogelijkheid om een showPopover en hidePopover . Daarnaast kun je luisteren naar de gebeurtenissen popovershow en popoverhide .
Een popover weergeven: js popoverElement.showPopover() Een popover verbergen:
popoverElement.hidePopover()
Luister of er een pop-upvenster verschijnt:
popoverElement.addEventListener('popovershow', doSomethingWhenPopoverShows)
Luister of er een pop-upvenster verschijnt en annuleer het indien nodig:
popoverElement.addEventListener('popovershow',event => {
event.preventDefault();
console.warn(‘We blocked a popover from being shown’);
})
Luister of er een pop-upvenster wordt verborgen:
popoverElement.addEventListener('popoverhide', doSomethingWhenPopoverHides)
Je kunt het verbergen van een pop-upvenster niet ongedaan maken:
popoverElement.addEventListener('popoverhide',event => {
event.preventDefault();
console.warn("You aren't allowed to cancel the hiding of a popover");
})
Controleer of er een pop-upvenster in de bovenste laag aanwezig is:
popoverElement.matches(':open')
Dit biedt extra mogelijkheden voor minder gangbare scenario's. Bijvoorbeeld om een pop-upvenster weer te geven na een periode van inactiviteit.
Deze demo bevat pop-ups met hoorbare geluiden, dus we hebben JavaScript nodig om de audio af te spelen. Bij een klik verbergen we de pop-up, spelen we de audio af en tonen we hem vervolgens weer.
Toegankelijkheid
Toegankelijkheid staat centraal bij de ontwikkeling van de Popover API. Toegankelijkheidsmapping koppelt de popover, indien nodig, aan het triggerelement. Dit betekent dat u geen aria-* attributen zoals aria-haspopup hoeft te declareren, ervan uitgaande dat u een van de triggerattributen zoals popovertoggletarget gebruikt.
Voor focusbeheer kunt u het autofocus-attribuut gebruiken om de focus naar een element binnen een popover te verplaatsen. Dit is hetzelfde als voor een dialoogvenster, maar het verschil zit hem in het teruggeven van de focus, en dat komt door het sluiten van een popover met een lichte klik. In de meeste gevallen geeft het sluiten van een popover de focus terug aan het element waarop eerder de focus stond. Maar bij het sluiten van een popover met een lichte klik wordt de focus verplaatst naar een aangeklikt element, als dat element de focus kan krijgen. Bekijk het gedeelte over focusbeheer in de uitleg.
Je moet de " volledig schermversie " van deze demo openen om te zien hoe het werkt.
In deze demo krijgt het geselecteerde element een groene omlijning. Probeer met je toetsenbord door de interface te navigeren. Let op waar de focus terugkeert wanneer een pop-upvenster wordt gesloten. Je zult misschien ook merken dat het pop-upvenster sluit als je met de tabtoets beweegt. Dat is de bedoeling. Hoewel pop-upvensters focusbeheer hebben, houden ze de focus niet vast. Toetsenbordnavigatie detecteert een sluitsignaal wanneer de focus het pop-upvenster verlaat.
Verankering (in ontwikkeling)
Bij popovers is het lastig om een element aan de trigger te verankeren. Stel bijvoorbeeld dat een tooltip boven de trigger moet verschijnen, maar er wordt gescrold in het document. Dan kan de tooltip buiten het zichtbare gedeelte van het scherm vallen. Gelukkig zijn er JavaScript-oplossingen zoals " Floating UI " die dit probleem verhelpen. Deze functies herpositioneren de tooltip automatisch, afhankelijk van de gewenste positievolgorde.
Maar we willen dat je dit met je eigen stijlen kunt definiëren. Er is een bijbehorende API in ontwikkeling, parallel aan de Popover API, om dit mogelijk te maken. De " CSS Anchor Positioning " API stelt je in staat om elementen aan andere elementen te koppelen, en doet dit op een manier die elementen herpositioneert zodat ze niet buiten het zichtbare gedeelte van het scherm vallen.
Deze demo maakt gebruik van de Anchoring API in de huidige staat. De positie van de boot reageert op de positie van het anker in het weergavegebied.
Hier is een fragment van de CSS die deze demo laat werken. Geen JavaScript nodig.
.anchor {
--anchor-name: --anchor;
}
.anchored {
position: absolute;
position-fallback: --compass;
}
@position-fallback --compass {
@try {
bottom: anchor(--anchor top);
left: anchor(--anchor right);
}
@try {
top: anchor(--anchor bottom);
left: anchor(--anchor right);
}
}
Je kunt de specificaties hier bekijken. Er komt ook een polyfill voor deze API.
Voorbeelden
Nu je weet wat popover te bieden heeft en hoe het werkt, gaan we eens kijken naar een paar voorbeelden.
Meldingen
Deze demo toont een melding "Kopiëren naar klembord".
- Gebruikt
[popover=manual]. - Actiepop-up weergeven met
showPopover. - Verberg het na een time-out van
2000msmethidePopover.
Toasts
Deze demo gebruikt de bovenste laag om meldingen in toaststijl weer te geven.
- Een pop-upvenster van het type '
manualfungeert als container. - Nieuwe meldingen worden aan de pop-up toegevoegd en de pop-up wordt weergegeven.
- Ze worden verwijderd met behulp van de webanimatie-API bij een klik en vervolgens uit de DOM verwijderd.
- Als er geen toasts zijn om weer te geven, wordt de popover verborgen.
Genest menu
Deze demo laat zien hoe een genest navigatiemenu zou kunnen werken.
- Gebruik
[popover=auto]omdat dit geneste popovers mogelijk maakt. - Gebruik
autofocusop de eerste link van elk dropdownmenu om met het toetsenbord te navigeren. - Dit is een perfecte kandidaat voor de CSS Anchoring API. Maar voor deze demo kun je een klein beetje JavaScript gebruiken om de posities bij te werken met behulp van aangepaste eigenschappen.
const ANCHOR = (anchor, anchored) => () => {
const { top, bottom, left, right } = anchor.getBoundingClientRect();
anchored.style.setProperty("--top", top);
anchored.style.setProperty("--right", right);
anchored.style.setProperty("--bottom", bottom);
anchored.style.setProperty("--left", left);
};
PRODUCTS_MENU.addEventListener("popovershow", ANCHOR(PRODUCT_TARGET, PRODUCTS_MENU));
Houd er rekening mee dat deze demo gebruikmaakt van autofocus en daarom in de " volledig schermweergave " moet worden geopend om met het toetsenbord te kunnen navigeren.
Media pop-up
Deze demo laat zien hoe je media in een pop-upvenster kunt weergeven.
- Gebruikt
[popover=auto]voor een snelle sluiting. - JavaScript luistert naar de
playvan de video en laat de video op het scherm verschijnen. - De popovers
popoverhidegebeurtenis pauzeert de video.
Wiki-achtige pop-ups
Deze demo laat zien hoe je tooltips met media inline content kunt maken.
- Gebruikt
[popover=auto]. Het tonen van één element verbergt de andere, omdat ze niet tot de voorouders behoren. - Weergegeven op
pointerentermet JavaScript. - Nog een perfecte kandidaat voor de CSS Anchoring API.
Navigatielade
Deze demo laat zien hoe je een navigatielade maakt met behulp van een popover.
- Gebruikt
[popover=auto]voor een snelle sluiting. - Maakt gebruik van
autofocusom het eerste navigatie-item scherp te stellen.
Achtergronden beheren
Deze demo laat zien hoe je achtergronden kunt beheren voor meerdere pop-ups, waarbij je slechts één ::backdrop zichtbaar wilt hebben.
- Gebruik JavaScript om een lijst bij te houden van de zichtbare pop-ups.
- Geef de onderste pop-up in de bovenste laag een klassenaam.
Aangepaste cursor-pop-up
Deze demo laat zien hoe je met popover een canvas naar de bovenste laag kunt verplaatsen en deze kunt gebruiken om een aangepaste cursor weer te geven.
- Plaats
canvasop de bovenste laag metshowPopoveren[popover=manual]. - Wanneer andere pop-ups geopend zijn, verberg en toon de
canvas-pop-up dan om ervoor te zorgen dat deze bovenaan blijft staan.
Actieblad pop-up
Deze demo laat zien hoe je een popover als actieblad kunt gebruiken.
- Zorg ervoor dat de popover standaard wordt weergegeven, waarbij de
displaywordt overschreven. - Het actieblad wordt geopend met de popover-trigger.
- Wanneer de popover wordt weergegeven, wordt deze naar de bovenste laag verplaatst en in beeld gebracht.
- Je kunt Light dismiss gebruiken om het terug te geven.
Toetsenbordgeactiveerde pop-up
Deze demo laat zien hoe je popover kunt gebruiken voor een gebruikersinterface in de stijl van een commandopalet.
- Gebruik cmd + j om de popover te tonen.
- De
inputwordt scherpgesteld metautofocus. - De keuzelijst is een tweede
popoverdat onder het hoofdinvoerveld is geplaatst. - De functie 'Licht afwijzen' sluit het palet als het vervolgkeuzemenu niet aanwezig is.
- Nog een kandidaat voor de Anchoring API
Getimede pop-up
Deze demo toont een inactiviteitspop-up na vier seconden. Een UI-patroon dat vaak wordt gebruikt in apps die gevoelige gebruikersinformatie bevatten om een uitlogvenster weer te geven.
- Gebruik JavaScript om de popover na een periode van inactiviteit weer te geven.
- Wanneer de pop-up verschijnt, reset dan de timer.
Schermbeveiliging
Net als in de vorige demo kun je je site een speels tintje geven door een screensaver toe te voegen.
- Gebruik JavaScript om de popover na een periode van inactiviteit weer te geven.
- Licht uit om de timer te verbergen en te resetten.
Caret volgt
Deze demo laat zien hoe je een pop-upvenster kunt laten volgen op een cursor in een invoerveld.
- Toon de pop-up op basis van selectie, toetsaanslag of invoer van speciale tekens.
- Gebruik JavaScript om de positie van de popover bij te werken met behulp van aangepaste eigenschappen met een beperkt bereik.
- Dit patroon vereist zorgvuldige overwegingen met betrekking tot de getoonde inhoud en de toegankelijkheid.
- Het wordt vaak gezien in de gebruikersinterface van tekstbewerkingsprogramma's en apps waar je tags kunt toevoegen.
Zwevend actieknopmenu
Deze demo laat zien hoe je met popover een zwevend actiemenu kunt implementeren zonder JavaScript.
- Promoot een
manualpop-upvenster met de `showPopovermethode. Dit is de hoofdknop. - Het menu is een apart pop-upvenster dat het doelwit is van de hoofdknop.
- Het menu wordt geopend met
popovertoggletarget. - Gebruik
autofocusom het eerste menu-item dat wordt weergegeven scherp te stellen. - Het menu wordt gesloten met het lichte kruisje.
- De icon twist maakt gebruik van
:has(). Je kunt meer lezen over:has()in dit artikel .
Dat is alles!
Dit was dus een introductie tot popover, een functie die in de toekomst onderdeel zal uitmaken van het Open UI-initiatief. Mits verstandig gebruikt, zal het een fantastische toevoeging aan het webplatform zijn.
Bekijk zeker Open UI eens. De uitleg over de pop-up wordt regelmatig bijgewerkt naarmate de API zich ontwikkelt. En hier vind je de verzameling met alle demo's.
Bedankt voor je bezoek!