十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
鼠標(biāo)拖拽元素移動(dòng),算是一個(gè)稍微有點(diǎn)點(diǎn)復(fù)雜的交互。

創(chuàng)新互聯(lián)公司2013年開(kāi)創(chuàng)至今,先為武漢等服務(wù)建站,武漢等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為武漢企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。
而在本文,我們就將打破常規(guī),向大家介紹一種超強(qiáng)的僅僅使用純 CSS 就能夠?qū)崿F(xiàn)的鼠標(biāo)點(diǎn)擊拖拽效果。
在之前的這篇文章中 -- [1],我們介紹了非常多有意思的純 CSS 的鼠標(biāo)跟隨效果,像是這樣:
但是,可以看到,上面的效果中,元素的移動(dòng)不是很絲滑。如果你了解上述的實(shí)現(xiàn)方式,就會(huì)知道它存在比較大的局限性。
本文,我們還是僅僅通過(guò) CSS,來(lái)實(shí)現(xiàn)一種絲滑的鼠標(biāo)點(diǎn)擊拖動(dòng)元素移動(dòng)的效果。
OK,什么意思呢?我們先來(lái)看一個(gè)最最簡(jiǎn)單的效果示意圖,實(shí)現(xiàn)點(diǎn)擊一個(gè)元素,能夠拖動(dòng)元素進(jìn)行移動(dòng)的效果:
好的,到這里,在繼續(xù)往下閱讀之前,你可以停一停。這種效果,正常而言,都是必須要借助 JavaScript 才能夠?qū)崿F(xiàn)的。從表現(xiàn)上來(lái)看:
思考一下,如果不借助 JavaScript 的話,有辦法將元素小球從 A 點(diǎn)移動(dòng)到 B 點(diǎn)么?這個(gè)效果完全就不像是純 CSS 能夠完成的。
答案必然是可以的!整個(gè)過(guò)程也非常之巧妙,這里我們核心需要利用強(qiáng)大的 resize 屬性。以及,配合通過(guò)構(gòu)建一種巧妙的布局,去解決可能會(huì)遇到的各種難題。
首先,我們利用 resize 屬性來(lái)實(shí)現(xiàn)一個(gè)可改變大小的元素。
什么是 resize 呢?根據(jù) [2]:該 CSS 屬性允許你控制一個(gè)元素的可調(diào)整大小性。
其 CSS 語(yǔ)法如下所示:
{
resize: none;
resize: both;
resize: horizontal;
resize: vertical;
resize: block;
resize: inline;
}簡(jiǎn)單解釋一下:
看一個(gè)最簡(jiǎn)單的 DEMO:
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 {
width: 200px;
height: 200px;
resize: horizontal;
overflow: scroll;
}這里,我們?cè)O(shè)置了一個(gè)長(zhǎng)寬為 200px 的
為橫向可拖拽改變寬度。效果如下:
簡(jiǎn)單總結(jié)一些小技巧:
這里,如果你的對(duì) resize 還有所疑惑,或者想了解更多 resize 的有趣用法,可以看看我的這篇文章:[3]。
OK,接下來(lái),我們將 resize 實(shí)際運(yùn)用到我們本文的例子中去,首先,我們先簡(jiǎn)單實(shí)現(xiàn)一個(gè) DIV:
.g-resize {
width: 100px;
height: 100px;
border: 1px solid deeppink;
}如下,非常普通,沒(méi)有什么特別的:
但是,通過(guò)給這個(gè)元素加上 resize: both 以及 overflow: scroll,此時(shí),這個(gè)元素的大小就通過(guò)元素右下角的 ICON 進(jìn)行拖動(dòng)改變。
簡(jiǎn)單修改下我們的 CSS 代碼:
.g-resize {
width: 100px;
height: 100px;
border: 1px solid deeppink;
resize: both;
overflow: scroll;
}這樣,我們就得到了一個(gè)靈活可以拖動(dòng)的元素:
是的,我們的整個(gè)效果,就需要借助這個(gè)特性進(jìn)行實(shí)現(xiàn)。
在此基礎(chǔ)上,我們可以嘗試將一個(gè)元素定位到上面這個(gè)可拖動(dòng)放大縮小的元素的右下角,看著能不能實(shí)現(xiàn)上述的效果。
簡(jiǎn)單加一點(diǎn)代碼:
.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;
}我們利用元素的偽元素實(shí)現(xiàn)了一個(gè)小球,放置在容器的右下角看看效果:
? ?
如果我們?cè)侔颜麄€(gè)設(shè)置了 resize: both 的邊框隱藏呢?那么效果就會(huì)是這樣:
Wow,整個(gè)效果已經(jīng)非常的接近了!只是,認(rèn)真看的話,能夠看到一些瑕疵,就是還是能夠看到設(shè)置了 resize 的元素的這個(gè) ICON:
這個(gè)也好解決,在 Chrome 中,我們可以通過(guò)另外一個(gè)偽元素 ::-webkit-resizer ,設(shè)置這個(gè) ICON 的隱藏。
根據(jù) [4],它屬于整體的滾動(dòng)條偽類樣式家族中的一員。
其中 ::-webkit-resizer 可以控制出現(xiàn)在某些元素底角的可拖動(dòng)調(diào)整大小的滑塊的樣式。
所以,這里我就利用這個(gè)偽類:
.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,將滑塊的顏色設(shè)置為了透明色。我們就得到了與文章一開(kāi)始,一模一樣的效果:
當(dāng)然,這里有個(gè)很致命的問(wèn)題,如果需要移動(dòng)的內(nèi)容,遠(yuǎn)比設(shè)置了 resize 的容器要大,或者其初始位置不在該容器內(nèi),超出了的部分因?yàn)樵O(shè)置了 overflow: scroll,將無(wú)法看到。
因此上述方案存在比較大的缺陷。
舉個(gè)例子,假設(shè)我們需要被拖動(dòng)的元素不再是一個(gè)有這樣一個(gè)簡(jiǎn)單的結(jié)構(gòu):
.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è)更為復(fù)雜的布局內(nèi)容展示(當(dāng)然下面展示的也比較簡(jiǎn)單,實(shí)際中可以想象成任意復(fù)雜結(jié)構(gòu)內(nèi)容):
? ?
如果將這個(gè)結(jié)構(gòu),扔到上面的 g-resize 中:
那么就會(huì)因?yàn)樵O(shè)置了 overflow: scroll 的原因,將完全看不到,只剩下一小塊:
為了解決這個(gè)問(wèn)題,我們得修改原本的 DOM 結(jié)構(gòu),另辟蹊徑。
方法有很多,譬如可以利用 Grid 布局的一些特性。當(dāng)然,這里我們只需要巧妙的加多一層,就可以完全解決這個(gè)問(wèn)題。
我們來(lái)實(shí)現(xiàn)這樣一個(gè)布局:
解釋一下上述代碼,其中:
看看完整的 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 呈現(xiàn)出來(lái)的元素,整個(gè)效果就是這樣:
是的,可能你會(huì)有所疑惑,下面我用簡(jiǎn)單不同顏色,標(biāo)識(shí)不同不同的 DOM 結(jié)構(gòu),方便你去理解。
.g-container {
border: 3px solid red;
}
.g-resize {
content: "";
background: blue;
resize: both;
overflow: scroll;
}
.g-resize::-webkit-resizer {
// background-color: transparent;
}看看這個(gè)圖,整個(gè)原理基本就比較清晰的浮現(xiàn)了出來(lái):
完整的原理代碼,你可以戳這里:[5]
OK,用了比較大篇幅對(duì)原理進(jìn)行了描述。下面我們舉一個(gè)實(shí)際的應(yīng)用場(chǎng)景。使用上述技巧制作的可拖動(dòng)便簽貼。靈感來(lái)自 -- [6]。
代碼也不多,如果你了解了上面的內(nèi)容,下面的代碼將非常好理解:
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;
}我們通過(guò)上述的技巧,實(shí)現(xiàn)了一個(gè)僅僅使用 CSS 實(shí)現(xiàn)的自由拖拽的便簽貼。我們可以自由的將其拖拽到任意地方。看看效果:
當(dāng)然,我們可以再配合上另外一個(gè)有意思是 HTML 屬性 -- contenteditable。
contenteditable 是一個(gè) HTML TAG 的屬性,表示元素是否可被用戶編輯。如果可以,瀏覽器會(huì)修改元素的部件以允許編輯。
簡(jiǎn)單修改一下 DOM 結(jié)構(gòu):
Lorem ipsum dolor sit amet consectetur?
此時(shí),元素不僅可以被拖動(dòng),甚至可以被重寫,感受一下:
純 CSS 實(shí)現(xiàn)的效果,非常的有意思,完整的代碼,你可以戳這里:[7]
基于 resize 這個(gè) CSS 屬性,其實(shí)還有很多有意思的用法。譬如我之前使用了 Resize 實(shí)現(xiàn)了一個(gè)圖片切換預(yù)覽的功能:[8] 可以一并看看,相信能碰撞出更多火花。
感興趣的同學(xué)可以自己動(dòng)手,更多的去嘗試,組合。
好了,本文到此結(jié)束,希望本文對(duì)你有所幫助 ????
[1]不可思議的純 CSS 實(shí)現(xiàn)鼠標(biāo)跟隨: https://github.com/chokcoco/iCSS/issues/46?。
[2]MDN -- resize: https://developer.mozilla.org/zh-CN/docs/Web/CSS/resize?。
[3]CSS 奇思妙想 | 使用 resize 實(shí)現(xiàn)強(qiáng)大的圖片拖拽切換預(yù)覽功能: https://github.com/chokcoco/iCSS/issues/133?。
[4]MDN - ::-webkit-resizer: https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar?。
[5]CodePen Demo -- Pure CSS Auto Drag Demo: https://codepen.io/Chokcoco/pen/PoemNYv?editors=1100?。
[6]scottkellum: https://codepen.io/scottkellum?。
[7]Pure CSS Auto Drag Demo: https://codepen.io/Chokcoco/pen/oNdWxJO?editors=1100?。
[8]CSS 奇思妙想 | 使用 resize 實(shí)現(xiàn)強(qiáng)大的圖片拖拽切換預(yù)覽功能: https://juejin.cn/post/6997224854554411045?。