目录
一、实现效果
如下图所示,当鼠标移动到某个图片时,就给这个图片添加四角线框;
四角线框效果
二、完整代码
【test.html】
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>四角线框效果</title>
<style>
:root {
/* 定义变量 */
/* 图片的宽度 */
--img-width: 240px;
/* 图片的高度 */
--img-height: 160px;
/* 图片的间距 */
--img-gap: 40px;
/* 线框的样式 */
--line-box-border: 2px solid #666;
}
* {
/* 清除默认边距 */
margin: 0;
padding: 0;
}
body {
/* 设为flex布局 */
display: flex;
/* 设置子元素水平居中 */
justify-content: center;
/* 设置子元素垂直居中 */
align-items: center;
width: 100vw;
height: 100vh;
background-color: #eeffff;
caret-color: transparent;
}
.grid-container {
/* 设为相对定位 */
position: relative;
/* 设为Grid布局 */
display: grid;
/* 划分3列,列宽为240px */
grid-template-columns: repeat(3, var(--img-width));
/* 划分3行,行高为160px */
grid-template-rows: repeat(3, var(--img-height));
/* 元素间距为40px */
gap: var(--img-gap);
}
.one-img {
/* 图片大小为其父元素大小 240px * 160px */
width: 100%;
height: 100%;
box-shadow: 0 0 6px 1px #666;
border-radius: 6px;
}
.line-box {
/* 设置线框为绝对定位 */
position: absolute;
/* 距离父元素的上、左距离为0; */
top: 0;
left: 0;
/* 线框盒子的宽度为图片宽度(240px) + 图片的间距(40px) */
width: calc(var(--img-width) + var(--img-gap));
/* 线框盒子的高度为图片高度(160px) + 图片的间距(40px) */
height: calc(var(--img-height) + var(--img-gap));
/* 设置线框的margin值 */
margin-top: calc(-1 * var(--img-gap) / 2);
margin-left: calc(-1 * var(--img-gap) / 2);
/* 添加过渡效果 */
transition: top 0.4s, left 0.4s;
}
.line-item {
/* 四角边框采用绝对定位 */
position: absolute;
/* 盒子的宽高均为20px */
width: calc(var(--img-gap) / 2);
height: calc(var(--img-gap) / 2);
}
/* 左上角的线框 */
.line-item:nth-child(1) {
top: 0;
left: 0;
border-top: var(--line-box-border);
border-left: var(--line-box-border);
}
/* 右上角的线框 */
.line-item:nth-child(2) {
top: 0;
right: 0;
border-top: var(--line-box-border);
border-right: var(--line-box-border);
}
/* 左下角的线框 */
.line-item:nth-child(3) {
bottom: 0;
left: 0;
border-bottom: var(--line-box-border);
border-left: var(--line-box-border);
}
/* 右下角的线框 */
.line-item:nth-child(4) {
right: 0;
bottom: 0;
border-bottom: var(--line-box-border);
border-right: var(--line-box-border);
}
</style>
</head>
<body>
<div class="grid-container">
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_1.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_2.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_3.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_4.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_5.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_6.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_7.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_8.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_9.jpg" alt="">
</div>
<div class="line-box">
<div class="line-item"></div>
<div class="line-item"></div>
<div class="line-item"></div>
<div class="line-item"></div>
</div>
</div>
</body>
<script>
// 获取图片元素列表
var itemList = document.querySelectorAll(".grid-item");
// 获取线框盒子
var lineBox = document.querySelector(".line-box");
itemList.forEach(item => {
// 给每个图片注册鼠标进入事件
item.addEventListener("mouseenter", function () {
// 获取图片的左、上边距(距离父元素),并赋值给线框作为left、top值
lineBox.style.top = item.offsetTop + 'px';
lineBox.style.left = item.offsetLeft + 'px';
})
});
</script>
</html>
三、页面准备
1、页面结构
(1)结构分析
根据上述效果图,可知:
- 页面中有一个大容器,在其父容器中水平垂直居中;
- 容器中排列了三行三列,总共9个元素;
- 每个元素中放一张图片;
(2)结构代码
- 页面中添加一个Grid布局容器【.grid-container 】和9个Grid元素【.grid-item】;
- 每个Grid元素中添加一个img元素【.one-img】,用来展示图片;
html
<body>
<div class="grid-container">
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_1.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_2.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_3.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_4.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_5.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_6.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_7.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_8.jpg" alt="">
</div>
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_9.jpg" alt="">
</div>
</div>
</body>
2、初始样式
(1)样式分析
根据上述效果图,可知:
- Grid容器【.grid-container 】中的9个Grid元素【.grid-item 】,呈现【3行3列】的排列方式;
- 设置body为Flex布局,使Grid容器在页面中水平垂直居中显示;
- img元素的大小为父容器Grid元素【.grid-item】的大小;
(2)样式代码
css
<style>
* {
/* 清除默认边距 */
margin: 0;
padding: 0;
}
body {
/* 设为flex布局 */
display: flex;
/* 设置子元素水平居中 */
justify-content: center;
/* 设置子元素垂直居中 */
align-items: center;
width: 100vw;
height: 100vh;
background-color: #eeffff;
caret-color: transparent;
}
.grid-container {
/* 设为Grid布局 */
display: grid;
/* 划分3列,列宽为240px */
grid-template-columns: repeat(3, 240px);
/* 划分3行,行高为160px */
grid-template-rows: repeat(3, 160px);
/* 元素间距为40px */
gap: 40px;
}
.one-img {
/* 图片大小为其父元素大小 240px * 160px */
width: 100%;
height: 100%;
box-shadow: 0 0 6px 1px #666;
border-radius: 6px;
}
</style>
3、基本效果
三、线框实现
1、需求分析
对于上述图中的线框效果,实现步骤如下:
(1)准备线框盒子
需要准备一个盒子【.line-box】,这个盒子要比图片大,包裹住图片,如下图所示:
(2)添加四角小盒子
但是效果图中的边框只在四角出现,这个盒子显然不能实现这样的效果;
这里采用的办法是,给这个线框盒子的四角分别添加一个小盒子【.line-item】,如下图所示:
(3)边框调整
到这里,基本上已经很明显了,只需要去除线框盒子【.line-box 】的边框效果,再给四角小盒子【.line-item】分别添加上对应位置的边框,就可以实现了;
注意:线框效果的实现方式有很多,这里仅介绍这种简单粗暴的实现方式;
( 如果有其他更好的实现方式,还希望请各位大佬不吝赐教~!)
2、线框结构
根据上述分析可知:
- 线框盒子的位置是相对与Grid容器【.grid-container】的;
- 在Grid容器中添加一个div盒子【.line-box】,与9个图片盒子同级;
- 在【.line-box 】盒子中添加四角小盒子【.line-item】* 4;
注意:这里将线框添加到Grid容器【.grid-container】中,是为了给后续线框的定位做准备;
html
<body>
<div class="grid-container">
<div class="grid-item">
<img class="one-img" src="D:\\test\\zyl-img\\bg_1.jpg" alt="">
</div>
......
<div class="line-box">
<div class="line-item"></div>
<div class="line-item"></div>
<div class="line-item"></div>
<div class="line-item"></div>
</div>
</div>
</body>
3、线框大小
如何确定线框的大小?
分析效果图可知:它的位置如下图红色框所示:
- 线框的宽度 = 图片的宽度(240px) + 两图的间距(40px);(左右间距各一半)
- 线框的高度 = 图片的高度(160px) + 两图的间距(40px);(上下间距各一半)
4、线框位置
如何确定线框位置?
分析效果图可知:
- 首先,线框需要采用绝对定位,相对其父元素【.grid-container】(脱离标准流,覆盖在图片上);
- 其次,当线框出现在第一个图片之上时,很明显不能和和它的父元素【.grid-container】的上边界和左边界贴合;
如下图所示,这并不是想要的结果:
这里采用的方式是给线框【.line-box】一个负的margin值(当然也可以采用其他方式);
这样一来,线框中心就会与图片中心重合,在视觉上达到需要的效果,如下图所示:
5、线框样式
根据上述分析可知:
- 线框【.line-box 】采用绝对定位:position: absolute;
- 父元素【.grid-container 】采用相对定位:position: relative;
- 线框距离父元素的左、上距离均为0(线框的初始位置);
- 线框设置负的margin值:margin-top: -20px; margin-left: -20px;
- 四角盒子采用绝对定位,相对于父元素线框【.line-box 】:position: absolute;
- 四角盒子大小为图片间距(40px)的一半:width: 20px; height: 20px;
- 分别给每个顶角盒子单独设置位置和样式;
相关元素的样式代码如下:
css
<style>
......
.grid-container {
/* 设为相对定位 */
position: relative;
......
}
.line-box {
/* 设置线框为绝对定位 */
position: absolute;
/* 距离父元素的上、左距离为0; */
top: 0;
left: 0;
/* 线框盒子的宽度为图片宽度(240px) + 图片的间距(40px) */
width: 280px;
/* 线框盒子的高度为图片高度(160px) + 图片的间距(40px) */
height: 200px;
/* 设置线框的margin值 */
margin-top: -20px;
margin-left: -20px;
}
.line-item {
/* 四角边框采用绝对定位 */
position: absolute;
/* 盒子的宽高均为20px */
width: 20px;
height: 20px;
}
/* 左上角的线框 */
.line-item:nth-child(1) {
top: 0;
left: 0;
border-top: 2px solid red;
border-left: 2px solid red;
}
/* 右上角的线框 */
.line-item:nth-child(2) {
top: 0;
right: 0;
border-top: 2px solid red;
border-right: 2px solid red;
}
/* 左下角的线框 */
.line-item:nth-child(3) {
bottom: 0;
left: 0;
border-bottom: 2px solid red;
border-left: 2px solid red;
}
/* 右下角的线框 */
.line-item:nth-child(4) {
right: 0;
bottom: 0;
border-bottom: 2px solid red;
border-right: 2px solid red;
}
</style>
效果如下图所示:
6、移动线框
分析需求可知:
- 当鼠标移入某个图片时,将线框移动到该图片周围;
- 分别给每个图片盒子注册鼠标进入事件;
- 当鼠标进入该图片时,计算其到父盒子【.grid-container】的上边距和左边距,并赋值给线框作为top和left值;
javascript
<script>
// 获取图片元素列表
var itemList = document.querySelectorAll(".grid-item");
// 获取线框盒子
var lineBox = document.querySelector(".line-box");
itemList.forEach(item => {
// 给每个图片注册鼠标进入事件
item.addEventListener("mouseenter", function () {
// 获取图片的左、上边距(距离父元素),并赋值给线框作为left、top值
lineBox.style.top = item.offsetTop + 'px';
lineBox.style.left = item.offsetLeft + 'px';
})
});
</script>
7、添加过渡效果
可以给线框添加过渡效果,让它的移动看起来平滑一点;
css
.line-box {
......
/* 添加过渡效果 */
transition: top 0.4s, left 0.4s;
}
8、使用CSS变量
上述代码中,很多地方都使用了同样的属性值;例如,
- 顶角盒子边框样式;
- 根据图片大小和间距计算的线框大小和位置等;
这些内容均可以通过CSS中的变量来实现;具体可以这样修改:
css
<style>
:root{
/* 定义变量 */
/* 图片的宽度 */
--img-width:240px;
/* 图片的高度 */
--img-height:160px;
/* 图片的间距 */
--img-gap:40px;
/* 线框的样式 */
--line-box-border: 2px solid red;
}
......
.grid-container {
......
/* 划分3列,列宽为240px */
grid-template-columns: repeat(3, var(--img-width));
/* 划分3行,行高为160px */
grid-template-rows: repeat(3, var(--img-height));
/* 元素间距为40px */
gap: var(--img-gap);
}
.line-box {
......
/* 线框盒子的宽度为图片宽度(240px) + 图片的间距(40px) */
width: calc(var(--img-width) + var(--img-gap));
/* 线框盒子的高度为图片高度(160px) + 图片的间距(40px) */
height: calc(var(--img-height) + var(--img-gap));
/* 设置线框的margin值 */
margin-top: calc(-1 * var(--img-gap) / 2);
margin-left: calc(-1 * var(--img-gap) / 2);
......
}
.line-item {
......
/* 盒子的宽高均为20px */
width: calc(var(--img-gap) / 2);
height: calc(var(--img-gap) / 2);
}
/* 左上角的线框 */
.line-item:nth-child(1) {
......
border-top: var(--line-box-border);
border-left:var(--line-box-border);
}
/* 右上角的线框 */
.line-item:nth-child(2) {
......
border-top: var(--line-box-border);
border-right: var(--line-box-border);
}
/* 左下角的线框 */
.line-item:nth-child(3) {
......
border-bottom: var(--line-box-border);
border-left: var(--line-box-border);
}
/* 右下角的线框 */
.line-item:nth-child(4) {
......
border-bottom: var(--line-box-border);
border-right: var(--line-box-border);
}
</style>
这样一来,如果需要更改图片大小、间距,线框大小、位置、样式等,直接在变量声明的地方统一更改即可,不需要再多做修改;
=========================================================================
每天进步一点点~!
记录一下这个有意思的CSS效果~~!