超强的纯 CSS 鼠标点击拖拽效果
背景
鼠标拖拽元素移动,算是一个稍微有点点复杂的交互。
而在本文,我们就将打破常规,向大家介绍一种超强的仅仅使用纯 CSS 就能够实现的鼠标点击拖拽效果。
在之前的这篇文章中 -- 不可思议的纯 CSS 实现鼠标跟随,我们介绍了非常多有意思的纯 CSS 的鼠标跟随效果,像是这样:
但是,可以看到,上面的效果中,元素的移动不是很丝滑。如果你了解上述的实现方式,就会知道它存在比较大的局限性。
本文,我们还是仅仅通过 CSS,来实现一种丝滑的鼠标点击拖动元素移动的效果。
鼠标点击拖拽跟随效果
OK,什么意思呢?我们先来看一个最最简单的效果示意图,实现点击一个元素,能够拖动元素进行移动的效果:
好的,到这里,在继续往下阅读之前,你可以停一停。这种效果,正常而言,都是必须要借助 JavaScript 才能够实现的。从表现上来看:
- 首先拖拽元素过程,可以任意将元素进行移动
- 然后放置元素,让元素停留在另外一个地方
思考一下,如果不借助 JavaScript 的话,有办法将元素小球从 A 点移动到 B 点么?这个效果完全就不像是纯 CSS 能够完成的。
答案必然是可以的!整个过程也非常之巧妙,这里我们核心需要利用强大的 resize 属性。以及,配合通过构建一种巧妙的布局,去解决可能会遇到的各种难题。
使用 resize,构建可拖拽改变大小的元素
首先,我们利用 resize 属性来实现一个可改变大小的元素。
什么是 resize 呢?根据 MDN -- resize:该 CSS 属性允许你控制一个元素的可调整大小性。
其 CSS 语法如下所示:
{
/* Keyword values */
resize: none;
resize: both;
resize: horizontal;
resize: vertical;
resize: block;
resize: inline;
}
简单解释一下:
resize: none:元素不能被用户缩放resize: both:允许用户在水平和垂直方向上调整元素的大小resize: horizontal:允许用户在水平方向上调整元素的大小resize: vertical:允许用户在垂直方向上调整元素的大小resize: block:根据书写模式(writing-mode)和方向值(direction),元素显示允许用户在块方向上(block)水平或垂直调整元素大小的机制。resize: inline:根据书写模式(writing-mode)和方向值(direction),元素显示一种机制,允许用户在内联方向上(inline)水平方向或垂直方向调整元素的大小。
看一个最简单的 DEMO:
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A aut qui labore rerum placeat similique hic consequatur tempore doloribus aliquid alias, nobis voluptates. Perferendis, voluptate placeat esse soluta deleniti id!</p>
p {
width: 200px;
height: 200px;
resize: horizontal;
overflow: scroll;
}
这里,我们设置了一个长宽为 200px 的 <p> 为横向可拖拽改变宽度。效果如下:
简单总结一些小技巧:
resize的生效,需要配合overflow: scroll,当然,准确的说法是,overflow不是visible,或者可以直接作用于替换元素譬如图像、<video>及<iframe>、<textarea>等- 我们可以通过
resize的horizontal、vertical、both来设置横向拖动、纵向拖动、横向纵向皆可拖动。 - 可以配合容器的
max-width、min-width、max-height、min-height限制可拖拽改变的一个范围
这里,如果你的对 resize 还有所疑惑,或者想了解更多 resize 的有趣用法,可以看看我的这篇文章:CSS 奇思妙想 | 使用 resize 实现强大的图片拖拽切换预览功能。
将 resize 应用到本文实例中
OK,接下来,我们将 resize 实际运用到我们本文的例子中去,首先,我们先简单实现一个 DIV:
<div class="g-resize"></div>
.g-resize {
width: 100px;
height: 100px;
border: 1px solid deeppink;
}
如下,非常普通,没有什么特别的:
但是,通过给这个元素加上 resize: both 以及 overflow: scroll,此时,这个元素的大小就通过元素右下角的 ICON 进行拖动改变。
简单修改下我们的 CSS 代码:
.g-resize {
width: 100px;
height: 100px;
border: 1px solid deeppink;
resize: both;
overflow: scroll;
}
这样,我们就得到了一个灵活可以拖动的元素:
是的,我们的整个效果,就需要借助这个特性进行实现。
在此基础上,我们可以尝试将一个元素定位到上面这个可拖动放大缩小的元素的右下角,看着能不能实现上述的效果。
简单加一点代码:
<div class="g-resize"></div>
.g-resize {
position: relative;
width: 20px;
height: 20px;
resize: both;
overflow: scroll;
}
.g-resize::before {
content: "";
position: absolute;
bottom: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 50%;
background: deeppink;
}
我们利用元素的伪元素实现了一个小球,放置在容器的右下角看看效果:
如果我们再把整个设置了 resize: both 的边框隐藏呢?那么效果就会是这样:
Wow,整个效果已经非常的接近了!只是,认真看的话,能够看到一些瑕疵,就是还是能够看到设置了 resize 的元素的这个 ICON:
这个也好解决,在 Chrome 中,我们可以通过另外一个伪元素 ::-webkit-resizer ,设置这个 ICON 的隐藏。
根据 MDN - ::-webkit-resizer,它属于整体的滚动条伪类样式家族中的一员。
其中 ::-webkit-resizer 可以控制出现在某些元素底角的可拖动调整大小的滑块的样式。
所以,这里我就利用这个伪类:
.g-resize {
position: relative;
width: 20px;
height: 20px;
resize: both;
overflow: scroll;
}
.g-resize::before {
content: "";
position: absolute;
bottom: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 50%;
background: deeppink;
}
.g-resize::-webkit-resizer {
background-color: transparent;
}
这样,这里的核心在于利用了 .g-resize::-webkit-resizer 中的 background-color: transparent,将滑块的颜色设置为了透明色。我们就得到了与文章一开始,一模一样的效果:
解决溢出被裁剪问题
当然,这里有个很致命的问题,如果需要移动的内容,远比设置了 resize 的容器要大,或者其初始位置不在该容器内,超出了的部分因为设置了 overflow: scroll,将无法看到。
因此上述方案存在比较大的缺陷。
举个例子,假设我们需要被拖动的元素不再是一个有这样一个简单的结构:
<div class="g-content"></div>
.g-content {
width: 100px;
height: 100px;
background: black;
pointer-event: none;
&::before {
content: "";
position: absolute;
width: 20px;
height: 20px;
background: yellow;
border-radius: 50%;
}
而像是这样,是一个更为复杂的布局内容展示(当然下面展示的也比较简单,实际中可以想象成任意复杂结构内容):
如果将这个结构,扔到上面的 g-resize 中:
<div class="g-resize">
<div class="g-content"></div>
</div>
那么就会因为设置了 overflow: scroll 的原因,将完全看不到,只剩下一小块:
为了解决这个问题,我们得修改原本的 DOM 结构,另辟蹊径。
方法有很多,譬如可以利用 Grid 布局的一些特性。当然,这里我们只需要巧妙的加多一层,就可以完全解决这个问题。
我们来实现这样一个布局:
<div class="g-container">
<div class="g-resize"></div>
<div class="g-content"></div>
</div>
解释一下上述代码,其中:
g-container设置为绝对定位加上display: inline-block,这样其盒子大小就可以由内部正常流式布局盒子的大小撑开g-resize设置为position: relative 并且设置resize,负责提供一个可拖动大小元素,在这个元素的变化过程中,就能动态改变父容器的高宽g-content实际内容盒子,通过position: absolute定位到容器的右下角即可
看看完整的 CSS 代码:
.g-container {
position: absolute;
display: inline-block;
}
.g-resize {
content: "";
position: relative;
width: 20px;
height: 20px;
border-radius: 50%;
resize: both;
overflow: scroll;
z-index: 1;
}
.g-content {
position: absolute;
bottom: -80px;
right: -80px;
width: 100px;
height: 100px;
background: black;
pointer-event: none;
&::before {
content: "";
position: absolute;
width: 20px;
height: 20px;
background: yellow;
border-radius: 50%;
transition: .3s;
}
}
.g-container:hover .g-content::before {
transform: scale(1.1);
box-shadow: -2px 2px 4px -4px #333, -4px 4px 8px -4px #333;
}
.g-resize::-webkit-resizer {
background-color: transparent;
}
下图中,你看到的所有元素,都只是 g-content 呈现出来的元素,整个效果就是这样:
是的,可能你会有所疑惑,下面我用简单不同颜色,标识不同不同的 DOM 结构,方便你去理解。
- 红色边框表示整个
g-container的大小 - 用蓝色矩形表示设置了
g-resize元素的大小 - 关掉
::-webkit-resizer的透明设置,展示出 resize 框的可拖拽 ICON
.g-container {
border: 3px solid red;
}
.g-resize {
content: "";
background: blue;
resize: both;
overflow: scroll;
}
.g-resize::-webkit-resizer {
// background-color: transparent;
}
看看这个图,整个原理基本就比较清晰的浮现了出来:
完整的原理代码,你可以戳这里:CodePen Demo -- Pure CSS Auto Drag Demo
实际应用
OK,用了比较大篇幅对原理进行了描述。下面我们举一个实际的应用场景。使用上述技巧制作的可拖动便签贴。灵感来自 -- scottkellum。
代码也不多,如果你了解了上面的内容,下面的代码将非常好理解:
<div class="g-container">
<div class="g-resize"></div>
<div class="g-content"> Lorem ipsum dolor sit amet consectetur?</div>
</div>
完整的 CSS 代码如下:
body {
position: relative;
padding: 10px;
background: url("背景图");
background-size: cover;
}
.g-container {
position: absolute;
display: inline-block;
}
.g-resize {
content: "";
position: relative;
width: 20px;
height: 20px;
resize: both;
overflow: scroll;
z-index: 1;
}
.g-content {
position: absolute;
bottom: -160px;
right: -180px;
color: rgba(#000, 0.8);
background-image: linear-gradient(
160deg,
rgb(255, 222, 30) 50%,
rgb(255, 250, 80)
);
width: 200px;
height: 180px;
pointer-event: none;
text-align: center;
font-family: "marker felt", "comic sans ms", sans-serif;
font-size: 24px;
line-height: 1.3;
padding: 1em;
box-sizing: border-box;
&:before {
content: "";
position: absolute;
width: 20px;
height: 20px;
top: 0;
left: 0;
border-radius: 50%;
background-image: radial-gradient(
at 60% 30%,
#f99,
red 20%,
rgb(180, 8, 0)
);
background-position: 20% 10%;
cursor: pointer;
pointer-events: none;
transform: scale(0.8);
box-shadow: -5px 10px 3px -8.5px #000, -1px 7px 12px -5px #000;
transition: all 0.3s ease;
transform: scale(0.8);
}
}
.g-container:hover .g-content::before {
transform: scale(0.9);
box-shadow: -5px 10px 6px -8.5px #000, -1px 7px 16px -4px #000;
}
.g-resize::-webkit-resizer {
background-color: transparent;
}
我们通过上述的技巧,实现了一个仅仅使用 CSS 实现的自由拖拽的便签贴。我们可以自由的将其拖拽到任意地方。看看效果:
当然,我们可以再配合上另外一个有意思是 HTML 属性 -- contenteditable。
contenteditable 是一个 HTML TAG 的属性,表示元素是否可被用户编辑。如果可以,浏览器会修改元素的部件以允许编辑。
简单修改一下 DOM 结构:
<div class="g-container">
<div class="g-resize"></div>
<div class="g-content" contenteditable="true"> Lorem ipsum dolor sit amet consectetur?</div>
</div>
此时,元素不仅可以被拖动,甚至可以被重写,感受一下:
纯 CSS 实现的效果,非常的有意思,完整的代码,你可以戳这里:Pure CSS Auto Drag Demo
最后
基于 resize 这个 CSS 属性,其实还有很多有意思的用法。譬如我之前使用了 Resize 实现了一个图片切换预览的功能:CSS 奇思妙想 | 使用 resize 实现强大的图片拖拽切换预览功能 可以一并看看,相信能碰撞出更多火花。
感兴趣的同学可以自己动手,更多的去尝试,组合。
好了,本文到此结束,希望本文对你有所帮助
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
超强的纯 CSS 鼠标点击拖拽效果的更多相关文章
- 原生js及H5模拟鼠标点击拖拽
一.原生js 1.拖拽的流程动作 鼠标按下 触发onmousedown事件 鼠标移动 触发onmousemove事件 鼠标松开 触发onmouseup事件 2.注意事项: 要防止div移出可视框,要限 ...
- 纯CSS实现点击事件展现隐藏div菜单列表/元素切换
在写移动端导航的时候经常用到点击按钮出现/隐藏导航条的情况,最常见的方法当然还是前端框架直接调用,省心省力,不易出错:当然还有使用纯JS实现的小代码段.我这里整理了纯CSS实现方式,给需要的人和给自己 ...
- 纯JS Web在线可拖拽的流程设计器
F2工作流引擎之-纯JS Web在线可拖拽的流程设计器 Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回. ...
- 纯CSS实现项目展示遮罩详情效果
本实例主要用于项目展示时鼠标hover后显示一个遮罩显示项目详情的效果,遮罩采用CSS的绝对定位以及CSS3盒子模型. 本实例应用广泛,很多品牌官方网站均有采用. hover: <!DOCTYP ...
- 纯CSS实现各类气球泡泡对话框效果
原文 纯CSS实现各类气球泡泡对话框效果 一.关于纯CSS实现气泡对话框 首先,来张大图: 上边这张黄黄的,大大的,圆圆的,有个小尾巴,文字内容有些YY的图片,就是使用纯CSS实现的气泡对话框效果,一 ...
- react实现的点击拖拽元素效果
之前用vue做日程管理组件的时候,用到了点击拖拽的效果,即点击元素,鼠标移动到哪里,元素移动到哪里,鼠标松开,拖拽停止,现在在弄react,于是也在想实现这个效果,经过一番折腾,效果出来了,代码如下: ...
- Ant Design -- 图片可拖拽效果,图片跟随鼠标移动
Ant Design 图片可拖拽效果,图片跟随鼠标移动,需计算鼠标在图片中与图片左上角的X轴的距离和鼠标在图片中与图片左上角的Y轴的距离. constructor(props) { super(pro ...
- CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身
CSharpGL(21)用鼠标拾取.拖拽VBO图元内的点.线或本身 效果图 以最常见的三角形网格(用GL_TRIANGLES方式进行渲染)为例. 在拾取模式为GeometryType.Point时,你 ...
- 三角形变形记之纯css实现的分布导航条效果
三角形变形记,用纯css实现的分布导航条效果 <style type="text/css"> ul,li { list-style-type:none; font-si ...
随机推荐
- PHP几个数组函数
array_intersect比较两个数组的键值,并返回交集: <?php $a1=array("a"=>"red","b"=& ...
- git diff与linux diff的输出格式之unified format
前言 前面有一篇文章<一个有些意思的项目--文件夹对比工具(一)>,里面简单讲了下diff算法之--Myers算法. 既然是算法,就会有实现,比如git diff中有Myers的实现,gi ...
- kali的安装与配置
VMware虚拟机与kali下载及安装教程 进入官网https://www.kali.org/get-kali/#kali-platforms 安装kali镜像 需要安装虚拟机 这里我们选择安装VMw ...
- MySQL 数据定义语句
表相关 修改表名 alter table grade rename hang; 新增表字段 alter table grade add `name` varchar(100); 修改表字段类型 alt ...
- SQL SERVER数据库服务器CPU不能全部利用原因分析
背景 客户凌晨把HIS数据库迁移到配置更高的新服务器,上午业务高峰时应用非常缓慢,严重影响到业务运行. 1.现象 通过SQL专家云实时可视化界面看到大量的绿点,绿点表示会话在等待某项资源,绿点越大 ...
- java-多态、内部类
1.多态: 1)意义: 1.1)同一类型的引用,指向不同的对象时,有不同的实现-------行为的多态: cut(),run(),teach()... 1.2)同一个对象,被造型为不同的类型时,有不同 ...
- Linux —用户和组
Linux 用户和组 1.用户和组的概念 用户的作用: Authentication:认证 Authorization:授权 Accouting:审计 用户存在的最终目的: 为了实现资源的分派 组的作 ...
- 【建议收藏】Mac VMWare NAT模式安装 CentOS 7-操作教程
学习大数据离不开 Linux 系统,网络上大部分文章都是在 Windows 系统下使用 VMWare Workstation 安装 CentOS ,并使用 NAT 模式配置网络.本文基于 Mac OS ...
- PyTorch中的CUDA操作
CUDA(Compute Unified Device Architecture)是NVIDIA推出的异构计算平台,PyTorch中有专门的模块torch.cuda来设置和运行CUDA相关操作.本 ...
- 图床搭建|chrome插件|操作简单不要钱
为什么需要一个图床 为了写博客 图床:专门用来存放图片,同时允许你把图片对外连接的网上空间. 用markdown格式写作,插入图片需要图片的url地址,然后博客的背景图也是要用url地址. 有段时间, ...