公共部分
Html
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Style
:root {
--num: 300px;
}
body {
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: #171717;
}
.box {
width: var(--num);
height: var(--num);
display: grid;
grid-template-columns: repeat(3, 1fr);
cursor: pointer;
}
解析
Hhtml
html定义一个带有类名为box的div容器,里面包含9个类名为item的子div元素。这些item元素将被用来创建一个3x3的网格布局。
Style
1、:root定义CSS变量–num,其值为300px。变量在.box的宽度和高度中被使用。
2、body设置页面的宽度和高度为视口的100%,移除默认的外边距,并使用Flexbox布局居中显示.box,同时设置背景颜色为深灰色。
3、.box设置宽度和高度为–num变量的值,使用网格布局(display: grid;
),并定义三列(grid-template-columns: repeat(3, 1fr);
),并且设置鼠标指针为指针形状,暗示可以交互。
代码段创建一个带有9个子项的网格布局,每个子项默认情况下没有特别的样式。当鼠标悬停在.box上时,由于.box的cursor属性被设置为pointer,鼠标指针会变成指针形状,暗示用户可以与.box进行交互。然而,没有提供.box:hover .item的样式规则,所以悬停.box时,.item的样式不会发生变化。
要使.item在悬停时有反应,需要添加额外的CSS规则来定义.box:hover .item的行为。
纯样式版
预览
默认
激活
Style
.item {
box-shadow: inset 0 0 0 1px #ffffff;
transition: 0.5s;
background-image: url('../../image/5_.jpg');
background-size: var(--num) var(--num);
position: relative;
}
.item:nth-child(3n+1) {
left: -20px;
background-position-x: 0;
}
.item:nth-child(3n+2) {
left: 0px;
background-position-x: -100px;
}
.item:nth-child(3n) {
left: 20px;
background-position-x: -200px;
}
.item {
top: 20px;
background-position-y: -200px;
}
.item:nth-child(-n+6) {
top: 0;
background-position-y: -100px;
}
.item:nth-child(-n+3) {
top: -20px;
background-position-y: 0px;
}
.box:hover .item {
left: 0;
top: 0;
box-shadow: inset 0 0 0 0 #ffffff;
}
解析
概述
1、代码段定义.item类的样式规则,以及基于:nth-child伪类选择器的特定子项的样式规则。此外,还包含一个悬停效果,当鼠标悬停在.box上时,所有.item元素的样式会发生变化。
2、代码段定义一个网格布局,其中.item元素具有背景图片和内阴影效果,并在鼠标悬停时,所有.item元素会移动到网格的起始位置,并且移除内阴影效果。通过使用CSS变量、网格布局和伪类选择器,实现复杂的布局和交互效果。
item类样式
1、box-shadow: inset 0 0 0 1px #ffffff;
为.item元素添加了一个白色的内阴影,边框宽度为1px。
2、transition: 0.5s;
定义背景位置和阴影变化的过渡效果,持续时间为0.5秒。
3、background-image: url('../../image/5_.jpg');
设置.item的背景图片为…/…/image/5_.jpg。
4、background-size: var(--num) var(--num);
设置背景图片的大小,使用之前定义的CSS变量–num,其值为300px,因此背景图片会被缩放至300px*300px。
5、position: relative;
将.item元素的定位设置为相对定位,允许使用left和top属性进行偏移。
特定子项x
css规则使用:nth-child选择器来选择特定的.item元素,并为它们设置不同的left偏移和背景图片的水平位置(background-position-x
)。
特定子项y
css规则为.item元素设置top偏移和背景图片的垂直位置(background-position-y
)。其中,:nth-child(-n+6)和:nth-child(-n+3)选择器分别选择前六个和前三个.item元素,并为它们设置不同的top偏移和背景图片的垂直位置。
悬停效果
当鼠标悬停在.box上时,所有.item元素的left和top偏移会被重置为0,内阴影会消失(变为0宽度的内阴影),使得所有.item元素在悬停时移动到网格的起始位置,并且移除内阴影效果。
JavaScript版
预览
默认
激活
Style
.item {
box-shadow: inset 0 0 0 1px #ffffff;
transition: 0.5s;
background-image: url('../../image/1_.jpg');
background-size: var(--num) var(--num);
background-position: var(--bgX, 0) var(--bgY, 0);
transform: translate(var(--disX, 0), var(--disY, 0));
}
.box:hover .item {
transform: translate(0, 0);
box-shadow: inset 0 0 0 0 #ffffff;
}
JavaScript
function init() {
const items = document.querySelectorAll('.item');
for (let i = 0; i < items.length; i++) {
const item = items[i];
const r = Math.floor(i / 3);
const c = i % 3;
const bgX = -c * 100 + '%';
const bgY = -r * 100 + '%';
const disX = (c - 1) * 20 + 'px';
const disY = (r - 1) * 20 + 'px';
item.style.setProperty('--bgX', bgX);
item.style.setProperty('--bgY', bgY);
item.style.setProperty('--disX', disX);
item.style.setProperty('--disY', disY);
}
}
init();
解析
Style
1、.item设置内阴影、过渡效果、背景图片、背景大小和位置,以及变换效果。背景位置和变换使用了CSS自定义属性(变量)–bgX、–bgY、–disX和–disY。
2、.box:hover .item规则定义鼠标悬停在.box上时,所有.item元素的变换效果会被重置,内阴影也会消失。
JavaScript
1、init函数通过查询所有.item元素,然后为每个元素设置CSS自定义属性–bgX、–bgY、–disX和–disY的值。这些值基于元素在网格中的位置(行r和列c)计算得出。
2、–bgX和–bgY控制背景图片的位置,而–disX和–disY控制元素在网格中的偏移量。
总结
代码段创建一个带有9个子项的网格布局,每个子项都有一个背景图片,并且在鼠标悬停时,所有子项会移动到网格的起始位置,并且移除内阴影效果。使用CSS变量、网格布局和JavaScript,实现复杂的布局和交互效果。
拓展版(完整的JavaScript版代码)
Html
<div class="box"></div>
Style
:root {
--num: 300px;
}
body {
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: #171717;
}
.box {
width: var(--num);
height: var(--num);
display: grid;
grid-template-columns: repeat(3, 1fr);
cursor: pointer;
}
.item {
box-shadow: inset 0 0 0 1px #ffffff;
transition: 0.5s;
background-image: var(--url);
background-size: var(--num) var(--num);
background-position: var(--bgX, 0) var(--bgY, 0);
transform: translate(var(--disX, 0), var(--disY, 0));
}
.box:hover .item {
transform: translate(0, 0);
box-shadow: inset 0 0 0 0 #ffffff;
}
JavaScript
let oldImg = '';
const list = Array.from({ length: 5 }, (v, i) => i + 1);
const runRandom = () => list[Math.floor(Math.random() * list.length)];
const runItems = () => document.querySelectorAll('.item');
function handleTaBar() {
const items = runItems();
const img = runRandom();
let url = ``;
if (img === oldImg) {
handleTaBar();
} else {
let i = 0;
oldImg = img;
url = `url(../../image/${img}_.jpg)`;
for (; i < items.length; i++) items[i].style.setProperty('--url', url);
}
}
function runInit() {
const box = document.querySelector('.box');
const elStr = '<div class="item" οnclick="handleTaBar()"></div>';
let el = '';
for (let i = 0; i < 9; i++) el += elStr;
box.innerHTML = el;
setTimeout(() => {
const items = runItems();
handleTaBar();
for (let i = 0; i < items.length; i++) {
const item = items[i];
const r = Math.floor(i / 3);
const c = i % 3;
const bgX = -c * 100 + '%';
const bgY = -r * 100 + '%';
const disX = (c - 1) * 20 + 'px';
const disY = (r - 1) * 20 + 'px';
item.style.setProperty('--bgX', bgX);
item.style.setProperty('--bgY', bgY);
item.style.setProperty('--disX', disX);
item.style.setProperty('--disY', disY);
}
});
}
runInit();
解析
1、承载背景图片的div通过JavaScript生成,并绑定触发函数(handleTaBar)。
2、使用JavaScript版样式规则。
3、点击handleTaBar方法随意切换图片,获取的图片与上一张不重复。
补充知识
前言
向空的list数组中生成1到5个值。
for
const list = []; for (let i = 1; i <= 5; i++) list.push(i); console.log(list); // (5) [1, 2, 3, 4, 5]
代码段创建一个空数组list,然后使用for循环从1迭代到5,每次迭代都将当前的数字i添加到list数组中。循环结束后,list数组将包含从1到5的整数。
Array.from
const list = Array.from({ length: 5 }, (v, i) => i + 1); console.log(list); // (5) [1, 2, 3, 4, 5]
展开运算符(keys+map)
const list = [...Array(5).keys()].map(e => e + 1); console.log(list); // (5) [1, 2, 3, 4, 5]