Dialog / 30 モーフィング|Morphing
デザイン見本
Morphing Dialog
小さな点(円)から長方形のカードへシームレスに変形するデザインです。
`border-radius` とサイズ要素(width / height)をアニメーション操作し、点や小さな円から長方形のダイアログカードへとシームレスにトランスフォーム(変形)して展開する、モーフィングアニメーションを搭載したデザインです。
実装コード
HTML
<button id="dialog-btn-30">Morphing<br>Dialog</button>
<div id="dialog-30" class="dialog">
<div class="dialog-content-30">
<div class="morph-inner">
<div class="morph-header">
<span>Morphing Dialog</span>
</div>
<div class="morph-body">
<p>小さな点(円)から長方形のカードへシームレスに変形するデザインです。</p>
</div>
<div class="morph-footer">
<button class="close-btn-30">Got it</button>
</div>
</div>
</div>
</div>
CSS
#dialog-btn-30 {
background-color: #833ab4;
background: linear-gradient(to right, #fcb045, #fd1d1d, #833ab4);
color: white;
border: none;
padding: 12px 24px;
border-radius: 30px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
min-width: 200px;
min-height: 60px;
display: block;
margin: 0 auto;
text-align: center;
transition: transform 0.3s, box-shadow 0.3s;
}
#dialog-btn-30:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(253, 29, 29, 0.3);
}
#dialog-30 {
display: none;
position: fixed;
z-index: 2147483647;
left: 0; top: 0; width: 100%; height: 100%;
background-color: rgba(255, 255, 255, 0.9);
animation: fadeIn-30 0.3s;
}
.dialog-content-30 {
background: #fff;
width: 80%;
max-width: 400px;
margin: 10% auto;
position: relative;
padding: 40px 30px;
text-align: center;
box-shadow: 0 20px 50px rgba(0,0,0,0.1);
/* モーフィングの中核:border-radiusとサイズのキーフレーム展開 */
animation: morphExpand-30 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}
.morph-inner {
opacity: 0;
animation: fadeInContent-30 0.4s ease forwards;
animation-delay: 0.6s;
}
.morph-header {
margin-bottom: 20px;
}
.morph-header span {
font-size: 24px;
font-weight: 800;
background: linear-gradient(to right, #fcb045, #fd1d1d, #833ab4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.morph-body p {
font-size: 15px;
line-height: 1.6;
margin-bottom: 30px;
color: #444;
}
.morph-footer {
display: flex;
justify-content: center;
}
.close-btn-30 {
background: linear-gradient(to right, #fcb045, #fd1d1d, #833ab4);
color: white;
border: none;
padding: 10px 30px;
border-radius: 20px;
cursor: pointer;
font-size: 15px;
font-weight: bold;
transition: filter 0.3s;
}
.close-btn-30:hover {
filter: brightness(1.1);
}
@keyframes fadeIn-30 {
from { opacity: 0; } to { opacity: 1; }
}
@keyframes morphExpand-30 {
0% {
width: 10px; padding: 0; height: 10px;
border-radius: 50%; opacity: 0;
background: #fd1d1d;
}
40% {
width: 100px; padding: 0; height: 100px;
border-radius: 50%; opacity: 1;
background: #fff;
}
100% {
width: 80%; padding: 40px 30px; height: auto;
border-radius: 12px; opacity: 1;
background: #fff;
}
}
@keyframes fadeInContent-30 {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 768px) {
.dialog-content-30 { width: 90%; }
}
JS
(function () {
var btn = document.getElementById('dialog-btn-30');
var dialog = document.getElementById('dialog-30');
var closeBtns = dialog.querySelectorAll('.close-btn-30');
if (!btn || !dialog) return;
function openDialog() {
dialog.style.display = 'block';
document.body.style.overflow = 'hidden';
}
function closeDialog() {
dialog.style.display = 'none';
document.body.style.overflow = 'auto';
}
btn.addEventListener('click', openDialog);
closeBtns.forEach(function(b) { b.addEventListener('click', closeDialog); });
dialog.addEventListener('click', function (e) {
if (e.target === dialog) {
closeDialog();
}
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && dialog.style.display === 'block') {
closeDialog();
}
});
})();