這篇文章跟大家介紹如何使用純CSS實現滑鼠點擊拖曳效果,讓互動更加生動,希望對大家有所幫助!
滑鼠拖曳元素移動,算是稍微有點複雜的互動。
而在本文,我們就將打破常規,向大家介紹一種超強的僅使用純 CSS 就能夠實現的滑鼠點擊拖曳效果。 【推薦學習:css影片教學】
在之前的這篇文章中-- 不可思議的純CSS 實作滑鼠跟隨,我們介紹了非常多有趣的純CSS 的滑鼠跟隨效果,像是這樣:
但是,可以看到,上面的效果中,元素的移動不是很絲滑。如果你了解上述的實作方式,你就會知道它有比較大的限制。
本文,我們還是只是透過 CSS,來實現一種絲滑的滑鼠點擊拖曳元素移動的效果。
#OK,什麼意思呢?我們先來看一個最簡單的效果示意圖,實現點擊一個元素,能夠拖曳元素進行移動的效果:
的,到這裡,在繼續往下閱讀之前,你可以停下來。這種效果,正常而言,都是必須要藉助 JavaScript 才能夠實現的。從表現來看:
先拖曳元素過程,可以任意將元素進行移動
然後放置元素,讓元素停留在另外一個地方
思考一下,如果不借助JavaScript 的話,有辦法將元素小球從A 點移動到B 點麼?這個效果完全不像是純 CSS 能夠完成的。
答案必然是可以的!整個過程也非常巧妙,這裡我們核心需要利用強大的 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></p>
為橫向可拖曳改變寬度。效果如下:
簡單總結一些小技巧:
resize
的生效,需要配合 overflow: scroll
,当然,准确的说法是,overflow
不是 visible
,或者可以直接作用于替换元素譬如图像、<video></video>
及 <iframe></iframe>
、<textarea></textarea>
等resize
的 horizontal
、vertical
、both
来设置横向拖动、纵向拖动、横向纵向皆可拖动。max-width
、min-width
、max-height
、min-height
限制可拖拽改变的一个范围这里,如果你的对 resize
还有所疑惑,或者想了解更多 resize 的有趣用法,可以看看我的这篇文章:CSS 奇思妙想 | 使用 resize 实现强大的图片拖拽切换预览功能。
OK,接下来,我们将 resize 实际运用到我们本文的例子中去,首先,我们先简单实现一个 DIV:
<div></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></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></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></div>
那么就会因为设置了 overflow: scroll
的原因,将完全看不到,只剩下一小块:
为了解决这个问题,我们得修改原本的 DOM 结构,另辟蹊径。
方法有很多,譬如可以利用 Grid 布局的一些特性。当然,这里我们只需要巧妙的加多一层,就可以完全解决这个问题。
我们来实现这样一个布局:
<div></div> <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></div>Lorem ipsum dolor sit amet consectetur?
完整的 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></div>Lorem ipsum dolor sit amet consectetur?
此时,元素不仅可以被拖动,甚至可以被重写,感受一下:
纯 CSS 实现的效果,非常的有意思,完整的代码,你可以戳这里:Pure CSS Auto Drag Demo
基于 resize
这个 CSS 属性,其实还有很多有意思的用法。譬如我之前使用了 Resize 实现了一个图片切换预览的功能:CSS 奇思妙想 | 使用 resize 实现强大的图片拖拽切换预览功能 可以一并看看,相信能碰撞出更多火花。
原文地址:https://www.cnblogs.com/coco1s/p/16774696.html
作者:ChokCoco
(学习视频分享:web前端)
以上是巧用純CSS實現滑鼠點擊拖曳效果,讓互動更加生動!的詳細內容。更多資訊請關注PHP中文網其他相關文章!