Dialog animé avec les CSS layers
Dialog animé avec les CSS layers
HTML
index.html <button
class="open"
type="button"
aria-haspopup="dialog"
aria-controls="dialog"
>
<span aria-hidden="true">⚡️</span>
</button>
<dialog id="dialog" aria-labelledby="dialog-title">
<div class="dialog-inner">
<header>
<h2 id="dialog-title">Dialog</h2>
<form>
<button
type="button"
aria-label="Fermer le dialogue"
data-dialog-close
>
<svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24">
<path d="M22.1 24a1.8 1.8 0 0 1-1.3-.6L12 14.6l-8.7 8.7a1.9 1.9 0 0 1-2.7-2.7L9.4 12 .6 3.2A1.9 1.9 0 0 1 3.3.5L12 9.3 20.7.6a1.9 1.9 0 0 1 2.7 2.7L14.7 12l8.7 8.7a1.9 1.9 0 0 1-1.3 3.3z"></path>
</svg>
</button>
</form>
</header>
<main>
<p>Les nouvelles transitions CSS permettent d’animer l’entrée et la sortie d’un élément dans le top layer.</p>
<p>Clique sur le fond autour de la boîte pour fermer le dialogue.</p>
</main>
<footer>
<a href="https://www.samuelgomez.fr" target="_blank" rel="noreferrer">Samuel Gomez</a>
<form>
<button type="button" data-dialog-close>Fermer</button>
</form>
</footer>
</div>
</dialog>
CSS
style.css @layer demo {
dialog,
::backdrop {
opacity: 0;
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
dialog {
transform: scale(0);
transition:
opacity 1s,
display 1s allow-discrete,
overlay 1s allow-discrete,
transform 1s;
}
[open],
[open]::backdrop {
opacity: 1;
}
[open] {
transform: scale(1);
}
@starting-style {
[open],
[open]::backdrop {
opacity: 0;
}
[open] {
transform: scale(0);
}
}
::backdrop {
background-color: rgb(0 255 255);
mix-blend-mode: overlay;
}
dialog {
max-width: 60vw;
margin-inline: auto;
padding: 0;
background: #fff;
border: 1px solid #fff;
border-radius: 10px;
backdrop-filter: blur(6.5px);
header {
display: grid;
grid-template-columns: 1fr auto;
align-content: center;
align-items: center;
button {
z-index: 2;
display: grid;
width: 40px;
aspect-ratio: 1;
place-content: center;
padding: 0.5rem;
color: #000;
border: 0;
border-radius: 100%;
svg {
width: 20px;
height: 20px;
}
}
}
.dialog-inner {
display: grid;
gap: 1rem;
padding: 1rem;
}
footer {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
form {
display: flex;
justify-self: end;
button {
display: flex;
place-content: center;
padding: 0.5rem 2rem;
background: #85cdff;
border: 0;
border-radius: 100vmax;
font-size: 1rem;
}
}
}
}
.open {
width: 62px;
height: 62px;
margin: 80px auto;
color: #fff;
cursor: pointer;
background: linear-gradient(180deg, #3c4349, #252a2d);
border: 1px solid #15181a;
border-radius: 100%;
box-shadow:
0 -3px 2px #212428 inset,
0 2px 2px #535d65 inset,
0 2px 2px -1px #050606,
0 7px 4px -1px #1a1d1f;
&:hover {
background: linear-gradient(180deg, #252a2d, #3c4349);
span {
background-image: linear-gradient(90deg, #ff9100, #ffd601);
}
}
&:focus-visible {
outline: 3px solid #00ffff;
outline-offset: 3px;
}
span {
font-size: 2rem;
color: transparent;
background: #fff;
background-clip: text;
background-size: cover;
filter: drop-shadow(2px 2px 5px #000);
-webkit-text-fill-color: transparent;
}
}
}
JavaScript
script.js const openButton = document.querySelector('.open');
const dialog = document.querySelector('#dialog');
openButton.addEventListener('click', () => dialog.showModal());
document.querySelectorAll('[data-dialog-close]').forEach(button => {
button.addEventListener('click', () => dialog.close());
});
dialog.addEventListener('click', event => {
if (event.target === dialog) dialog.close();
});