共计 6785 个字符,预计需要花费 17 分钟才能阅读完成。
背景
鼠标拖拽元素挪动,算是一个略微有点点简单的交互。
而在本文,咱们就将打破常规,向大家介绍一种超强的仅仅应用纯 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 实现弱小的图片拖拽切换预览性能 能够一并看看,置信能碰撞出更多火花。
感兴趣的同学能够本人入手,更多的去尝试,组合。
好了,本文到此结束,心愿本文对你有所帮忙 :)
如果还有什么疑难或者倡议,能够多多交换,原创文章,文笔无限,满腹经纶,文中若有不正之处,万望告知。