这个切换效果在firebox上测试正常,但到了chrome上就没有切换效果了。原因可能是它们在处理transition的流程上有差别,解决方案就是用animation来实现更精细的动画。
(通常只有两个状态,这种简单的情况适用transition比较方便;多个状态就需要适用animation进行详细的控制了)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf8">
<style>
/*
图片分隔动画有两种思路
(1)大背景是一张静图,每个小方格做动画
(2)连每个小方格都是静态的,方格里面的伪元素做动画
*/
/* 这里提一下 column-count 这个属性,他可以将一段文本分隔成多列,就跟报纸中的分栏一样 */
.louver {
width: 30em;
height: 20em;
border: 1px solid black;
background-size: 100% 100%;
position: relative;
display: flex;
/** flex-wrap: nowrap|wrap|wrap-reverse|initial|inherit; 默认值是nowrap */
flex-wrap: wrap;
overflow:hidden;
}
.louver>span {
/** border: 1px solid black; */
position: relative;
/** width和height对于inline元素是无效的 */
display:inline-block;
/** 只有边框占据内部宽高,才能填满整个父元素 */
box-sizing: border-box;
/** CSS3的attr 目前还只能用在伪元素里,如果非要这么用,建议使用LESS/SESS
attr( <attr-name> <type-or-unit>? [ , <fallback> ]? )
width: calc(100% / attr(data-row px));
height: calc(100% / attr(data-column px));
*/
overflow: hidden;
border: 1px solid white;
}
.louver>span>span {
position: absolute;
width: 1.5em;
height: 1.5em;
color: black;
background-color: white;
border-radius: 50%;
/** box-shadow不指定color的话,默认用的是元素的color */
box-shadow: 0 0 .5em;
display: flex;
justify-content: center;
align-items: center;
bottom: .3em;
left: 50%;
transform: translateX(-50%);
z-index: 1;
}
.louver>span::before, .louver>span::after {
/** border: 1px solid red; */
content: '';
position: absolute;
width: 100%;
height: 100%;
background-size: inherit;
background-position: inherit;
}
</style>
<style>
.card-transition::before, .card-transition::after {
transition: all 1s;
}
/* import表示优先生效,如果没加important的话,如果两个class都指定了相同的属性哪个生效就说不清楚了
(一般是后面的覆盖前面的,详细的覆盖模糊的【比如nth-child就比普通样式优先级高,即使它定义在前面】,行内样式>内嵌>外部) */
.card-flip {
/** preserve是保持;perspective是透视
transform-style和perspective都是作用于它们的子元素的
*/
transform-style: preserve-3d;
/** 透视距离必须和3d同时定义才会有3d效果 */
perspective: 15em;
/** overflow 属性规定当内容溢出元素框时发生的事情。
visible 默认值。内容不会被修剪,会呈现在元素框之外。
hidden 内容会被修剪,并且其余内容是不可见的。
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit 规定应该从父元素继承 overflow 属性的值。
*/
overflow: visible !important;
}
.card-flip::before, .card-flip::after {
/** 隐藏背面 */
backface-visibility: hidden;
}
.card-flip::after {
transform: rotateY(180deg);
}
.card-flip-run::before {
transform: rotateY(180deg) !important;
}
.card-flip-run::after {
transform: rotateY(360deg) !important;
}
/* 推拉挤出 */
.card-push::before {
left: 0;
}
.card-push::after {
left: -100%;
}
.card-push-run::before {
left: 100% !important;
}
.card-push-run::after {
left: 0 !important;
}
/* 交叉推拉 */
.card-pushPull::before {
left: 0;
}
/** odd表示奇数,会被翻译为2n+1;even是偶数,会被翻译为2n */
.card-pushPull:nth-child(odd)::after {
left: -100%;
}
.card-pushPull:nth-child(even)::after {
left: 100%;
}
.card-pushPull-run:nth-child(odd)::before {
left: 100% !important;
}
.card-pushPull-run:nth-child(even)::before {
left: -100% !important;
}
.card-pushPull-run::after {
left: 0 !important;
}
/* 按下反弹 */
.card-pressSpring::before {
top: 0;
}
.card-pressSpring:nth-child(odd)::after {
top: -100%;
}
.card-pressSpring:nth-child(even)::after {
top: 100%;
}
.card-pressSpring-run:nth-child(odd)::before {
top: 100% !important;
}
.card-pressSpring-run:nth-child(even)::before {
top: -100% !important;
}
.card-pressSpring-run::after {
top: 0 !important;
}
/** 毛玻璃淡出
.card-blur::before, .card-blur::after {
transition: transform .5s ease, filter 1s ease, opacity .5s ease;
}
*/
.card-blur::after {
transform: scale(1.5, 1.5);
filter: blur(10px);
opacity: 0;
}
.card-blur-run::before {
transform: scale(1, 1);
filter: blur(0);
opacity: 1;
}
.card-blur-run::before {
transform: scale(1.5, 1.5) !important;
filter: blur(10px) !important;
opacity: 0 !important;
}
.card-blur-run::after {
transform: scale(1, 1) !important;
filter: blur(0) !important;
opacity: 1 !important;
}
</style>
<script>
let imgs = [
"https://www.html5tricks.com/demo/SlidingImagePanels/images/1.jpg",
"https://www.html5tricks.com/demo/SlidingImagePanels/images/2.jpg",
"https://www.html5tricks.com/demo/SlidingImagePanels/images/3.jpg",
"https://www.html5tricks.com/demo/SlidingImagePanels/images/4.jpg"];
let containerClsName = "louver";
let animStyle;
let index = 0;
/*
background-size
bg-size = [ <length> | <percentage> | auto ]{1,2} | cover | contain
(1)按指定数值<length>、百分比<percentage>、原图像大小auto 显示
(2)cover 按比例调整图片,使之正好能自适应整个背景区域的宽高比,长边铺满短边留白
(3)contain 按比例调整图片,使之刚好能自适应铺满整个背景区域,短边铺满长边溢出的部分被咔嚓
*/
function createCells() {
//const louver = document.querySelector("." + containerClsName);
const louver = document.getElementsByClassName(containerClsName)[0];
//删除其下的所有子元素
louver.innerHTML = "";
const row = louver.dataset.row;
const column = louver.dataset.column;
const count = row * column;
const perWidth = louver.offsetWidth / column;
const perHeight = louver.offsetHeight / row;
//公共的数值写在style里
const style = document.createElement("style");
/*
background-image
url('URL') 指向图像的路径。
none 默认值。不显示背景图像。
inherit 规定应该从父元素继承 background-image 属性的设置。
*/
style.textContent = "." + containerClsName + ">span{width:" + 100/column + "%;height:" + 100/row + "%;background-size:" + column*100 + "% " + row*100 + "%;}";
for(let i = 1; i <= count; i++) {
//nth-child 的第一个子元素的下标是1
//background-position: left top
style.appendChild(document.createTextNode("." + containerClsName + ">span:nth-child(" + i + "){background-position:" + ((i-1)%column)*-100 + "% " + parseInt((i-1)/column)*-100 + "%}"));
//本来是在after里面做序号,但如果这样的话动画就要另一个元素了
//style.appendChild(document.createTextNode("." + containerClsName + ">span:nth-child(" + i + ")::before{content:'" + i + "'}"));
const child = document.createElement("span");
child.innerHTML = "<span>" + i + "</span>";
louver.append(child);
}
document.head.appendChild(style);
const backgroundUrlStyle = document.createElement("style");
backgroundUrlStyle.id = "backgroundUrlStyle";
document.head.appendChild(backgroundUrlStyle);
}
function setAnimStyle(_animStyle) {
animStyle = _animStyle;
const louvers = document.getElementsByClassName(containerClsName);
for(let i=0; i<louvers.length; i++) {
const childs = louvers[i].children;
for(let j=0; j<childs.length; j++) {
//由于classList没有清空所有的方法,所以只能用className
childs[j].className = animStyle;
//要临时禁用动画,必须先改变值,然后调用getComputedStyle,触发recalculateStyle,之后再设置transition
getComputedStyle(childs[j]).length;
childs[j].classList.add("card-transition");
}
}
}
//该方法要求不执行过渡动画
function setImage(index) {
const next = (index+1) % imgs.length;
const backgroundUrlStyle = document.getElementById("backgroundUrlStyle");
backgroundUrlStyle.innerHTML="." + containerClsName + ">span::after{background-image:url(" + imgs[next] + ");}";
backgroundUrlStyle.appendChild(document.createTextNode("." + containerClsName + ">span::before{background-image:url(" + imgs[index] + ");}"));
/*
const louvers = document.getElementsByClassName(containerClsName);
for(let i=0;i<louvers.length; i++) {
louvers[i].style.backgroundImage = "url(" + imgs[index] + ")";
}
*/
}
//该方法要求每次都执行过渡动画
function changeImage() {
setImage(index);
setAnimStyle(animStyle);
index = ++index % imgs.length;
const e = window.event || arguments.callee.caller.arguments[0]; //火狐没定义event,因此必须用这种方式做兼容
//currentTarget是绑定事件的元素;target是实际被点击的元素;事件从源冒泡到上层,除非调用了stopPropagation停止传递
//e.currentTarget.classList.toggle("flip");
//直接改父元素的class,然后在css中控制对应的子元素样式也是可以的,但是这里为了复用之前定义的css变量不这么操作
//JS forEach()方法不能用于HTMLCollection NodeList等类似于数组但又不是真正的数组。
const childs = e.currentTarget.children;
for(let i=0; i<childs.length; i++) {
childs[i].classList.toggle(animStyle + "-run");
};
}
function setListener() {
document.querySelectorAll("input[name='animStyle']").forEach((elem)=>{
elem.onchange=()=>{
index = 0;
setAnimStyle("card-" + elem.value);
setImage(0);
}
});
document.getElementsByName("numberVisible")[0].onchange = function() {
const louvers = document.getElementsByClassName(containerClsName);
for(let i=0; i<louvers.length; i++) {
const childs = louvers[i].children;
for(let j=0; j<childs.length; j++) {
const firstChild = childs[j].firstChild;
if(firstChild.localName == "span") {
firstChild.style.display = this.checked ? "flex" : "none";
}
}
}
};
}
window.onload = ()=>{
createCells();
setImage(0);
setListener();
setAnimStyle("card-flip");
};
</script>
</head>
<body>
<div class="louver" data-row="2" data-column="4" onclick="changeImage()"></div>
<form action="" method="get" style="display:inline-block;">
<input type="checkbox" name="numberVisible" checked="checked"><label for="flip">NumberVisible</label></input>
<input type="radio" name="animStyle" value="flip" id="flip" checked="checked"><label for="flip">flip</label></input>
<input type="radio" name="animStyle" value="push" id="push"><label for="push">push</label></input>
<input type="radio" name="animStyle" value="pushPull" id="pushPull"><label for="pushPull">pushPull</label></input>
<input type="radio" name="animStyle" value="pressSpring" id="pressSpring"><label for="pressSpring">pressSpring</label></input>
<input type="radio" name="animStyle" value="blur" id="blur"><label for="blur">blur</label></input>
</form>
</body>
</html>