如何使用 css 动画显示和关闭弹出窗口?
How to animate a pop up on show and close using css?
我的布局如下,
容器 - 容纳所有卡片。
卡片 - div 包含信息。
上图中,左边是屏幕的初始渲染图,
当用户点击任何内卡时,对应的卡应该popout/zoomout,
当用户在弹出卡片上单击后退时,它应该会消失并显示第一个屏幕。
弹窗动画应该是这样的,应该从卡片的位置开始,我们点击了。
第二次点击弹出窗口关闭动画(当弹出窗口打开时),动画应该是这样的,弹出窗口应该最小化到第一步点击的卡片。
我试过下面的代码,但它真的很生动..
let isOpen = false;
$(".child").on("click", function() {
if (!isOpen) {
$(".child").removeClass("active");
$(this).addClass("active");
isOpen = true;
} else {
$(this).removeClass("active");
isOpen = false;
}
})
* {
box-sizing: border-box;
}
.parent {
margin: 40px auto;
width: 400px;
height: 600px;
border: 1px solid #3b3b3b;
border-radius: 20px;
padding: 20px 40px;
position: relative;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.5s ease-in;
}
.child.active {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 10;
border: 1px solid red;
background: #000;
border-radius: 20px;
color: #fff;
}
@keyframes zoomIn {
0% {
transform: scale(1.1);
}
50% {
transform: scale(1.2);
}
100% {}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
请帮我模拟一下。
你的动画已经基本完成了。我看到的问题是,当 .active
class 添加到 child 时,另一个 children 填补了网格中的空白。这使得活动 child 不会从其原始位置放大。
我使用 CSS 制作了自己的解决方案,但没有动画 - 和香草 JavaScript。在我的代码中(就像在你的代码中一样),child 从网格中丢失,获得绝对位置,然后用 width: 100%;
和 height: 100%;
填充整个 parent 容器我还向其他 children 添加了 CSS 规范,以便在发生这种情况时保持原状(见下文)。
这是一个相当活泼的效果,因为 transition
不会应用于宽度和高度,除非 child 绝对定位在 之前 活动 class 被添加。要实现更“放大”的效果有点棘手:
- 你可以观察DOM属性(class)与JavaScript的突变(换句话说,添加一个class绝对定位,当该操作完成后,添加另一个 class 和
width: 100%;
和 height: 100%;
).
- 或者您可以从一开始就在所有 child 元素上使用
position: absolute
,但是您还需要指定宽度、高度、顶部、左侧等。
- 其他一些我太累或不够熟练的解决方案。
当前解决方案
// Turn all 4 .child selectors into an integer array ranging from 0-3
let cardArray = Array.from(document.querySelectorAll(".child"));
// Loop over each integer [0-3] and give them an index number
// Listen for clicks, and then toggle the "larger" class onto the item with the corresponding index number [0-3]
cardArray.forEach(function(everyItem, index) {
everyItem.addEventListener("click", function() {
cardArray[index].classList.toggle("larger");
});
});
* {
box-sizing: border-box;
}
.parent {
margin: 40px auto;
width: 400px;
height: 600px;
border: 1px solid #3b3b3b;
border-radius: 20px;
padding: 20px 40px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 20px;
transition: all 0.5s;
/* relative position required for enlarged items to stay within parent container */
position: relative;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.2s;
/* z-index not neccessary, just a precaution */
z-index: 1;
}
/* top/bottom/left/right required for the CURRENTLY ACTIVE child to resize from the correct corner.
:nth-child() with grid-area specified required for NOT CURRENTLY active children to stay put in grid. */
.child:nth-child(1) {
grid-area: 1 / 1;
top: 0;
left: 0;
}
.child:nth-child(2) {
grid-area: 1 / 2;
top: 0;
right: 0;
}
.child:nth-child(3) {
grid-area: 2 / 1;
bottom: 0;
left: 0;
}
.child:nth-child(4) {
grid-area: 2 / 2;
bottom: 0;
right: 0;
}
/* .larger class added with the help
of JavaScript on click */
.child.larger {
/* Unhinge from the grid */
grid-area: unset;
/* Position absolute in order to resize it */
position: absolute;
/* Fill the WIDTH of the parent container */
width: 100%;
/* Fill the HEIGHT of the parent container */
height: 100%;
/* z-index not neccessary, just a precaution */
z-index: 2;
background: #000;
opacity: 0.5;
color: #fff;
}
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
您可以尝试通过 css 变量 计算,position: absolute
和单独的 .active
class 来实现元素.
let isOpen = false;
$('.child').on('click', function() {
if (!isOpen) {
$('.child').removeClass('active');
$(this).addClass('active');
isOpen = true;
} else {
$(this).removeClass('active');
isOpen = false;
}
});
*,
::after,
::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--parent-width: 400px;
--parent-height: 600px;
--gap: 20px;
}
.parent {
margin: 40px auto;
width: var(--parent-width);
height: var(--parent-height);
border: 1px solid #3b3b3b;
border-radius: 20px;
position: relative;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.5s ease-in;
position: absolute;
height: calc((var(--parent-height) / 2) - (var(--gap) * 2));
width: calc((var(--parent-width) / 2) - (var(--gap) * 3));
}
/* Init size */
.child:nth-child(1) {
top: var(--gap); /* padding top 20px */
left: calc(var(--gap) * 2); /* padding left 40px */
}
.child:nth-child(2) {
top: var(--gap);
right: calc(var(--gap) * 2); /* padding right 40px */
}
.child:nth-child(3) {
bottom: var(--gap); /* padding bottom 20px */
left: calc(var(--gap) * 2); /* padding left 40px */
}
.child:nth-child(4) {
bottom: var(--gap);
right: calc(var(--gap) * 2);
}
/* Full size */
.child:nth-child(1).active {
top: 0;
left: 0;
}
.child:nth-child(2).active {
top: 0;
right: 0;
}
.child:nth-child(3).active {
bottom: 0;
left: 0;
}
.child:nth-child(4).active {
bottom: 0;
right: 0;
}
.child.active {
width: 100%;
height: 100%;
z-index: 10;
border: 1px solid red;
background: #000;
border-radius: 20px;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
我的布局如下,
容器 - 容纳所有卡片。
卡片 - div 包含信息。
上图中,左边是屏幕的初始渲染图, 当用户点击任何内卡时,对应的卡应该popout/zoomout,
当用户在弹出卡片上单击后退时,它应该会消失并显示第一个屏幕。
弹窗动画应该是这样的,应该从卡片的位置开始,我们点击了。
第二次点击弹出窗口关闭动画(当弹出窗口打开时),动画应该是这样的,弹出窗口应该最小化到第一步点击的卡片。
我试过下面的代码,但它真的很生动..
let isOpen = false;
$(".child").on("click", function() {
if (!isOpen) {
$(".child").removeClass("active");
$(this).addClass("active");
isOpen = true;
} else {
$(this).removeClass("active");
isOpen = false;
}
})
* {
box-sizing: border-box;
}
.parent {
margin: 40px auto;
width: 400px;
height: 600px;
border: 1px solid #3b3b3b;
border-radius: 20px;
padding: 20px 40px;
position: relative;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.5s ease-in;
}
.child.active {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 10;
border: 1px solid red;
background: #000;
border-radius: 20px;
color: #fff;
}
@keyframes zoomIn {
0% {
transform: scale(1.1);
}
50% {
transform: scale(1.2);
}
100% {}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
请帮我模拟一下。
你的动画已经基本完成了。我看到的问题是,当 .active
class 添加到 child 时,另一个 children 填补了网格中的空白。这使得活动 child 不会从其原始位置放大。
我使用 CSS 制作了自己的解决方案,但没有动画 - 和香草 JavaScript。在我的代码中(就像在你的代码中一样),child 从网格中丢失,获得绝对位置,然后用 width: 100%;
和 height: 100%;
填充整个 parent 容器我还向其他 children 添加了 CSS 规范,以便在发生这种情况时保持原状(见下文)。
这是一个相当活泼的效果,因为 transition
不会应用于宽度和高度,除非 child 绝对定位在 之前 活动 class 被添加。要实现更“放大”的效果有点棘手:
- 你可以观察DOM属性(class)与JavaScript的突变(换句话说,添加一个class绝对定位,当该操作完成后,添加另一个 class 和
width: 100%;
和height: 100%;
). - 或者您可以从一开始就在所有 child 元素上使用
position: absolute
,但是您还需要指定宽度、高度、顶部、左侧等。 - 其他一些我太累或不够熟练的解决方案。
当前解决方案
// Turn all 4 .child selectors into an integer array ranging from 0-3
let cardArray = Array.from(document.querySelectorAll(".child"));
// Loop over each integer [0-3] and give them an index number
// Listen for clicks, and then toggle the "larger" class onto the item with the corresponding index number [0-3]
cardArray.forEach(function(everyItem, index) {
everyItem.addEventListener("click", function() {
cardArray[index].classList.toggle("larger");
});
});
* {
box-sizing: border-box;
}
.parent {
margin: 40px auto;
width: 400px;
height: 600px;
border: 1px solid #3b3b3b;
border-radius: 20px;
padding: 20px 40px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 20px;
transition: all 0.5s;
/* relative position required for enlarged items to stay within parent container */
position: relative;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.2s;
/* z-index not neccessary, just a precaution */
z-index: 1;
}
/* top/bottom/left/right required for the CURRENTLY ACTIVE child to resize from the correct corner.
:nth-child() with grid-area specified required for NOT CURRENTLY active children to stay put in grid. */
.child:nth-child(1) {
grid-area: 1 / 1;
top: 0;
left: 0;
}
.child:nth-child(2) {
grid-area: 1 / 2;
top: 0;
right: 0;
}
.child:nth-child(3) {
grid-area: 2 / 1;
bottom: 0;
left: 0;
}
.child:nth-child(4) {
grid-area: 2 / 2;
bottom: 0;
right: 0;
}
/* .larger class added with the help
of JavaScript on click */
.child.larger {
/* Unhinge from the grid */
grid-area: unset;
/* Position absolute in order to resize it */
position: absolute;
/* Fill the WIDTH of the parent container */
width: 100%;
/* Fill the HEIGHT of the parent container */
height: 100%;
/* z-index not neccessary, just a precaution */
z-index: 2;
background: #000;
opacity: 0.5;
color: #fff;
}
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
您可以尝试通过 css 变量 计算,position: absolute
和单独的 .active
class 来实现元素.
let isOpen = false;
$('.child').on('click', function() {
if (!isOpen) {
$('.child').removeClass('active');
$(this).addClass('active');
isOpen = true;
} else {
$(this).removeClass('active');
isOpen = false;
}
});
*,
::after,
::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--parent-width: 400px;
--parent-height: 600px;
--gap: 20px;
}
.parent {
margin: 40px auto;
width: var(--parent-width);
height: var(--parent-height);
border: 1px solid #3b3b3b;
border-radius: 20px;
position: relative;
}
.child {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #000;
border-radius: 40px;
cursor: pointer;
transition: all 0.5s ease-in;
position: absolute;
height: calc((var(--parent-height) / 2) - (var(--gap) * 2));
width: calc((var(--parent-width) / 2) - (var(--gap) * 3));
}
/* Init size */
.child:nth-child(1) {
top: var(--gap); /* padding top 20px */
left: calc(var(--gap) * 2); /* padding left 40px */
}
.child:nth-child(2) {
top: var(--gap);
right: calc(var(--gap) * 2); /* padding right 40px */
}
.child:nth-child(3) {
bottom: var(--gap); /* padding bottom 20px */
left: calc(var(--gap) * 2); /* padding left 40px */
}
.child:nth-child(4) {
bottom: var(--gap);
right: calc(var(--gap) * 2);
}
/* Full size */
.child:nth-child(1).active {
top: 0;
left: 0;
}
.child:nth-child(2).active {
top: 0;
right: 0;
}
.child:nth-child(3).active {
bottom: 0;
left: 0;
}
.child:nth-child(4).active {
bottom: 0;
right: 0;
}
.child.active {
width: 100%;
height: 100%;
z-index: 10;
border: 1px solid red;
background: #000;
border-radius: 20px;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>