bootstrap 轮播中的负边距如何工作?
How does negative margin work in bootstrap carousel?
我在下面为 bootstrap 4 轮播创建了一个演示,其转换速度减慢到 30 秒,以便每个人都可以检查并正确查看 js 添加的动态 css:
.carousel-item {
transition: transform 30s ease-in-out!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://getbootstrap.com/docs/4.6/dist/js/bootstrap.bundle.js"></script>
<link href="https://getbootstrap.com/docs/4.6/dist/css/bootstrap.css" rel="stylesheet"/>
<div id="carouselExampleCaptions" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselExampleCaptions" data-slide-to="0" class="active"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="1"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">First slide</text></svg>
</div>
<div class="carousel-item">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">Second slide</text></svg>
</div>
<div class="carousel-item">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">Third slide</text></svg>
</div>
</div>
<a class="carousel-control-prev" href="#carouselExampleCaptions" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleCaptions" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
如您所见,所有幻灯片都已给出 margin-right: -100%
,然后活动幻灯片被转换 translateX(-100%)
。我没有得到的是:
问题 1:margin-right -100%
应该为每张幻灯片创建底片 space,使所有幻灯片都出现在彼此之上,但实际上它们是并排的, 为什么?
问题2:如果只变换活动幻灯片,为什么右边的幻灯片也跟着活动幻灯片一起变换?
对于问题 1,请考虑以下演示:https://jsfiddle.net/2j1ug8x4/ 在这里您可以看到 1
和 2
如何出现在同一个地方。他们被给予 float: left
就像 bootstrap.
问题一:
margin-right
实际上 是 将幻灯片放在彼此之上 - CSS 转换解决了这个问题并使幻灯片出现在彼此旁边彼此。查看 this example 幻灯片被迫 display: block
的位置,您会看到第三张幻灯片,另外两张叠放在下面。
使用 margin-right: -100%
的真正原因是确保幻灯片连续显示,而不是垂直堆叠。请参阅 this example 幻灯片可见且负边距已移除的位置 - 您可以向下滚动以查看所有幻灯片都是垂直堆叠的。
问题二:
那为什么右边的幻灯片也变形了呢?这个调试起来有点棘手,但我认为正在发生的事情是 bootstrap 向右幻灯片添加了两个 class:carousel-item-next
和 carousel-item-left
如果您查看来源 CSS,carousel-item-next
会向元素添加一个 transform: translateX(100%)
。但是 CSS 规则仅在第二个 class 不存在时才包含转换:
.carousel-item-next:not(.carousel-item-left),
transform: translateX(100%);
}
所以我相信正在发生的事情是 bootstrap 正在添加第一个 class (carousel-item-next
),然后在第二个 class 之前有一个轻微的延迟( carousel-item-left
) 添加。
该延迟意味着右侧幻灯片会短暂地进行 translateX(100%)
的转换,然后立即将其删除。因为幻灯片元素上有一个过渡,这会导致右幻灯片从 translateX(100%)
到 translateX(0)
或从右到左动画。
这是一个简化的示例,在没有 bootstrap 的情况下复制此行为 - 单击 Move
按钮触发移动。注意 setTimeout
用于人为模拟第一个和第二个 CSS classes:
相加之间的差距
const button = document.getElementById('move');
button.addEventListener('click', () => {
const childElements = document.querySelectorAll('.child');
childElements[0].classList.toggle('left');
childElements[1].classList.toggle('right');
setTimeout(() => {
childElements[1].classList.toggle('skip');
}, 0);
});
#move {
position: absolute;
top: 10px;
left: 55%;
}
.container {
position: relative;
width: 50%;
}
.child {
display: none;
position: relative;
width: 100%;
height: 300px;
border: 1px dotted blue;
float: left;
margin-right: -100%;
transition: 1s transform ease;
}
.left {
transform: translateX(-100%);
}
.right:not(.skip) {
transform: translateX(100%);
}
.active,
.right {
display: block;
}
<div class="container">
<div class="child active">1</div>
<div class="child">2</div>
</div>
<button id="move">Move</button>
我在下面为 bootstrap 4 轮播创建了一个演示,其转换速度减慢到 30 秒,以便每个人都可以检查并正确查看 js 添加的动态 css:
.carousel-item {
transition: transform 30s ease-in-out!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://getbootstrap.com/docs/4.6/dist/js/bootstrap.bundle.js"></script>
<link href="https://getbootstrap.com/docs/4.6/dist/css/bootstrap.css" rel="stylesheet"/>
<div id="carouselExampleCaptions" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselExampleCaptions" data-slide-to="0" class="active"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="1"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">First slide</text></svg>
</div>
<div class="carousel-item">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">Second slide</text></svg>
</div>
<div class="carousel-item">
<svg class="bd-placeholder-img bd-placeholder-img-lg d-block w-100" width="800" height="400" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: First slide" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#777"></rect><text x="50%" y="50%" fill="#555" dy=".3em">Third slide</text></svg>
</div>
</div>
<a class="carousel-control-prev" href="#carouselExampleCaptions" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleCaptions" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
如您所见,所有幻灯片都已给出 margin-right: -100%
,然后活动幻灯片被转换 translateX(-100%)
。我没有得到的是:
问题 1:margin-right -100%
应该为每张幻灯片创建底片 space,使所有幻灯片都出现在彼此之上,但实际上它们是并排的, 为什么?
问题2:如果只变换活动幻灯片,为什么右边的幻灯片也跟着活动幻灯片一起变换?
对于问题 1,请考虑以下演示:https://jsfiddle.net/2j1ug8x4/ 在这里您可以看到 1
和 2
如何出现在同一个地方。他们被给予 float: left
就像 bootstrap.
问题一:
margin-right
实际上 是 将幻灯片放在彼此之上 - CSS 转换解决了这个问题并使幻灯片出现在彼此旁边彼此。查看 this example 幻灯片被迫 display: block
的位置,您会看到第三张幻灯片,另外两张叠放在下面。
使用 margin-right: -100%
的真正原因是确保幻灯片连续显示,而不是垂直堆叠。请参阅 this example 幻灯片可见且负边距已移除的位置 - 您可以向下滚动以查看所有幻灯片都是垂直堆叠的。
问题二:
那为什么右边的幻灯片也变形了呢?这个调试起来有点棘手,但我认为正在发生的事情是 bootstrap 向右幻灯片添加了两个 class:carousel-item-next
和 carousel-item-left
如果您查看来源 CSS,carousel-item-next
会向元素添加一个 transform: translateX(100%)
。但是 CSS 规则仅在第二个 class 不存在时才包含转换:
.carousel-item-next:not(.carousel-item-left),
transform: translateX(100%);
}
所以我相信正在发生的事情是 bootstrap 正在添加第一个 class (carousel-item-next
),然后在第二个 class 之前有一个轻微的延迟( carousel-item-left
) 添加。
该延迟意味着右侧幻灯片会短暂地进行 translateX(100%)
的转换,然后立即将其删除。因为幻灯片元素上有一个过渡,这会导致右幻灯片从 translateX(100%)
到 translateX(0)
或从右到左动画。
这是一个简化的示例,在没有 bootstrap 的情况下复制此行为 - 单击 Move
按钮触发移动。注意 setTimeout
用于人为模拟第一个和第二个 CSS classes:
const button = document.getElementById('move');
button.addEventListener('click', () => {
const childElements = document.querySelectorAll('.child');
childElements[0].classList.toggle('left');
childElements[1].classList.toggle('right');
setTimeout(() => {
childElements[1].classList.toggle('skip');
}, 0);
});
#move {
position: absolute;
top: 10px;
left: 55%;
}
.container {
position: relative;
width: 50%;
}
.child {
display: none;
position: relative;
width: 100%;
height: 300px;
border: 1px dotted blue;
float: left;
margin-right: -100%;
transition: 1s transform ease;
}
.left {
transform: translateX(-100%);
}
.right:not(.skip) {
transform: translateX(100%);
}
.active,
.right {
display: block;
}
<div class="container">
<div class="child active">1</div>
<div class="child">2</div>
</div>
<button id="move">Move</button>