超強的純 CSS 滑鼠點擊拖拽效果

来源:https://www.cnblogs.com/coco1s/archive/2022/10/10/16774696.html
-Advertisement-
Play Games

背景 滑鼠拖拽元素移動,算是一個稍微有點點複雜的交互。 而在本文,我們就將打破常規,向大家介紹一種超強的僅僅使用純 CSS 就能夠實現的滑鼠點擊拖拽效果。 在之前的這篇文章中 -- 不可思議的純 CSS 實現滑鼠跟隨,我們介紹了非常多有意思的純 CSS 的滑鼠跟隨效果,像是這樣: 但是,可以看到,上 ...


背景

滑鼠拖拽元素移動,算是一個稍微有點點複雜的交互。

而在本文,我們就將打破常規,向大家介紹一種超強的僅僅使用純 CSS 就能夠實現的滑鼠點擊拖拽效果。

在之前的這篇文章中 -- 不可思議的純 CSS 實現滑鼠跟隨,我們介紹了非常多有意思的純 CSS 的滑鼠跟隨效果,像是這樣:

但是,可以看到,上面的效果中,元素的移動不是很絲滑。如果你瞭解上述的實現方式,就會知道它存在比較大的局限性。

本文,我們還是僅僅通過 CSS,來實現一種絲滑的滑鼠點擊拖動元素移動的效果。

滑鼠點擊拖拽跟隨效果

OK,什麼意思呢?我們先來看一個最最簡單的效果示意圖,實現點擊一個元素,能夠拖動元素進行移動的效果:

好的,到這裡,在繼續往下閱讀之前,你可以停一停。這種效果,正常而言,都是必須要藉助 JavaScript 才能夠實現的。從表現上來看:

  1. 首先拖拽元素過程,可以任意將元素進行移動
  2. 然後放置元素,讓元素停留在另外一個地方

思考一下,如果不藉助 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>
  • 我們可以通過 resizehorizontalverticalboth 來設置橫向拖動、縱向拖動、橫向縱向皆可拖動。
  • 可以配合容器的 max-widthmin-widthmax-heightmin-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>

解釋一下上述代碼,其中:

  1. g-container 設置為絕對定位加上 display: inline-block,這樣其盒子大小就可以由內部正常流式佈局盒子的大小撐開
  2. g-resize 設置為 position: relative 並且設置 resize,負責提供一個可拖動大小元素,在這個元素的變化過程中,就能動態改變父容器的高寬
  3. 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 結構,方便你去理解。

  1. 紅色邊框表示整個 g-container 的大小
  2. 用藍色矩形表示設置了 g-resize 元素的大小
  3. 關掉 ::-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 實現的自由拖拽的便簽貼。我們可以自由的將其拖拽到任意地方。看看效果:

bbg1.gif

當然,我們可以再配合上另外一個有意思是 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 實現強大的圖片拖拽切換預覽功能 可以一併看看,相信能碰撞出更多火花。

感興趣的同學可以自己動手,更多的去嘗試,組合。

好了,本文到此結束,希望本文對你有所幫助

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在應用開發的早期,數據量少,開發人員開發功能時更重視功能上的實現,隨著生產數據的增長,很多SQL語句開始暴露出性能問題,對生產的影響也越來越大,有時可能這些有問題的SQL就是整個系統性能的瓶頸。 ...
  • [Android開發學iOS系列] iOS寫UI的幾種方式 作為一個現代化的平臺, iOS的發展也經歷了好幾個時代. 本文講講iOS寫UI的幾種主要方式和各自的特點. iOS寫UI的方式 在iOS中寫UI有多種選擇, 大的分類: 使用UIKit還是SwiftUI. 在使用UIKit的情形下, 還根據 ...
  • 一、新建原生工程和Flutter Module 1、新建Android工程 搭建一個空的Android工程FlutterDemo_Android模擬已經存在的原有工程 Android項目配置: 2、新建iOS工程 搭建一個空的iOS工程FlutterDemo_iOS模擬已經存在的原有工程 Xcode ...
  • 鬥魚直播相信大家都聽說過,打開鬥魚官網就可以直接在瀏覽器中觀看直播。那麼鬥魚是如何實現瀏覽器視頻直播的呢?本篇文章就來解析鬥魚是如何實現直播的,以及它是如何節省 80% 的 CDN 流量,要知道視頻直播流量費並不便宜,鬥魚每個月光這些流量費都要支付幾個億,節省 CDN 流量就是省錢。 直播技術方案 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 隨著業務的需求,項目需要支持H5、各類小程式以及IOS和Android,這就需要涉及到跨端技術,不然每一端都開發一套,人力成本和維護成本太高了。團隊的技術棧主要以Vue為主,最終的選型是以uni-app+uview2.0作為跨端技術 ...
  • 在《基於 vite 創建 vue3 項目》一文中整合了 pinia,有不少伙伴不知道 pinia 是什麼,本文簡單介紹 pinia。主要包括三方面: pinia 的基本用法,在《基於 vite 創建 vue3 項目》中 demo 的基礎上簡單重構。 如何持久化 pinia 中的數據,保證瀏覽器刷新時 ...
  • 項目地址 npm庫地址:https://www.npmjs.com/package/dd-ui-library 組件庫:https://github.com/YolandaKisses/ui-library 目錄結構 ├─ src │ └─ components // 存放測試頁面 │ └─ lib ...
  • 微前端概述 微前端概念是從微服務概念擴展而來的,摒棄大型單體方式,將前端整體分解為小而簡單的塊,這些塊可以獨立開發、測試和部署,同時仍然聚合為一個產品出現在客戶面前。可以理解微前端是一種將多個可獨立交付的小型前端應用聚合為一個整體的架構風格。 微前端不是一門具體的技術,而是整合了技術、策略和方法,可 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...