<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          純 CSS 也能實現(xiàn)拖拽效果?

          共 4403字,需瀏覽 9分鐘

           ·

          2021-05-30 00:24

          發(fā)揮你的想象,CSS也能實現(xiàn)拖拽效果。

          一、拖拽效果示例

          這是移動端很常見的一個效果,可以按住拖來拖去,比如下面的起點中文網(wǎng)[1]觸屏版:

          這類效果用JS可以很容易實現(xiàn),無非就是多了一些計算,多考慮了一些臨界場景,然后代碼量也多了一些。不過,經(jīng)過我的一番腦洞,發(fā)現(xiàn)CSS也能幾乎實現(xiàn)這一效果,接著往下看。

          二、CSS實現(xiàn)原理

          在傳統(tǒng) web 中,頁面滾動是一個很常見交互,操作上就是利用鼠標滾輪或者直接拖動滾動條。但是,移動端可不一樣,直接用手指拖動頁面就可以滾動了。通常頁面是要么垂直方向滾動,要么水平方向滾動,如果兩個方向都可以滾動呢?例如

          .dragbox{  width: 300px;  height: 300px;  overflow: auto}.dragcon{  width: 500px;  height: 500px;}

          只需要內(nèi)部元素寬高都大于容器就實現(xiàn)兩個方向的滾動了(記得設(shè)置overflow:auto),示意如下

          一般情況下,鼠標滾輪只能同時滾動一個方向(按住Shift可以滾動另一方向),但是移動端可以直接拖著內(nèi)容任意滾動,如下所示


          我們先在內(nèi)容中間添加一個元素,跟隨內(nèi)容區(qū)域一起滾動

          接下來,把后面的文本隱藏起來

          是不是有點拖拽的味道了?原理就是這么簡單!

          三、CSS實現(xiàn)細節(jié)

          首先確定拖拽目標與拖拽容器的尺寸關(guān)系,假設(shè)拖拽目標的尺寸是w * h,那么很容易得出的尺寸關(guān)系為:內(nèi)部尺寸是容器的2倍減去拖拽目標的尺寸

          .dragbox{  width: 100%;  height: 100%;}.dragcon{  width: calc(200% - w);  height: calc(200% - h);}

          用一張動圖描述如下(中間的橙色塊塊表示拖拽目標)

          四、CSS實現(xiàn)布局

          接下來需要把這個特性加入到頁面當中,這里列舉了兩種布局

          1.fixed 定位

          現(xiàn)在直接把剛才的布局添加到頁面上,并添加fixed定位

          <body>  ...頁面上的其他元素  <div class=“dragbox”>    <div class=“dragcon”></div>    <div class=“ball”></div> <!--拖拽元素-->  </div></body>

          關(guān)鍵樣式如下

          .dragbox{  position: fixed;  left: 0;  top: 0;  right: 0;  bottom: 0;  overflow: auto}

          層級示意關(guān)系如下

          這樣一來,dragbox肯定把頁面原有的部分遮擋了,所以還需要添加pointer-events: none;同時在拖拽時添加pointer-events: all

          .dragbox{  /*...*/  pointer-events: none;}.ball{  /*...*/  pointer-events: all;}.dragbox.active{  /*...*/  pointer-events: all;}

          借助 JS 可以在按下時觸發(fā)外層容器滾動

          ball.addEventListener('touchstart',(ev)=>{   dragbox.classList.add('active');})document.addEventListener('touchend',()=>{   dragbox.classList.remove('active');})

          實際效果如下

          完整代碼可訪問https://codepen.io/xboxyan/pen/PobwxBK(PC訪問請打開移動端模式)

          也可直接掃描以下二維碼

          1.absolute 定位 + 層級

          前面一種布局由于fixed定位層級的影響,不得不借助 JS 來動態(tài)改變?nèi)萜鞯臓顟B(tài),有沒有什么辦法可以實現(xiàn)既可以拖拽,又不影響原有頁面呢?下面來看這一種布局,用到了absolute定位

          這里需要對原有頁面包裹一層div容器,如下

          <body>  <div class=“dragbox”>    <div class=“dragcon”></div>    <div class=“ball”></div>  </div>  <div class=“body”> <!--單獨用一層實現(xiàn)頁面滾動-->    ...頁面上的其他元素  </div></body>

          關(guān)鍵樣式如下

          .dragbox{  position: absolute;  width: 100%;  height: 100%;  overflow: auto;}.body{  position: relative;  height: 100%;  overflow: auto;}.ball{  position: relative;  z-index: 10;  /*拖拽目標的層級設(shè)置高一點*/}

          現(xiàn)在層級關(guān)系就變成了這樣

          這里原先頁面內(nèi)容在層級上處于dragbox拖拽目標之間,所以在拖拽時也不會影響到原有頁面的滾動,無需任何 JS 處理

          完整代碼可訪問https://codepen.io/xboxyan/pen/bGBNQxL(PC訪問請打開移動端模式)

          也可直接掃描以下二維碼

          提示:上面兩種布局方式,第一種方式適應(yīng)性更好,不影響現(xiàn)有項目;第二種體驗更好,但是會使用div作為頁面滾動容器,會對頁面結(jié)構(gòu)做一定的改動,可以根據(jù)實際情況自行選擇。

          五、CSS實現(xiàn)其他功能

          1.吸附功能

          很多時候,在拖拽結(jié)束時需要讓它自動吸附在邊緣,就如同文章開頭的示意圖一樣。那么,通過吸附,可以聯(lián)想到什么屬性呢?

          答案就是CSS Scroll Snap[2]

          <body>  ...頁面上的其他元素  <div class=“dragbox”>    <div class=“dragcon”>A</div>    <div class=“dragcon”>B</div>    <div class=“ball”></div>  </div></body>

          下面是關(guān)鍵樣式

          .dragbox{  ...  scroll-snap-type: x mandatory;}.dragcon{  scroll-snap-align: start;}

          實際效果如下

          完整代碼可訪問https://codepen.io/xboxyan/pen/XWNJyPw(PC訪問請打開移動端模式)

          也可直接掃描以下二維碼

          1.設(shè)置初始位置

          默認情況下,拖拽目標是唯有右下角的,如何位于左下角呢?很簡單,這里拖拽是滾動容器實現(xiàn)的,所以只需要改變scrollLeft 或者 scrollTop 即可

          dragbox.scrollLeft = 999;dragbox.scrollTop = 999;

          除此之外,也可以采用純 HTML 方式實現(xiàn),利用元素的 autofocus 自動聚焦到可視范圍的特性

          <div class=“dragcon">  ...  <button class="pos" autofocus></button> <!--添加一個自動聚焦的元素--></div>

          比如你希望初始位置在左上角,那么添加一個右下角的自動聚焦元素就可以了(當然還需要設(shè)置透明度等隱藏起來)~

          1.設(shè)置邊界

          現(xiàn)在拖拽目標的邊界是屏幕邊緣,有時候可能需要留一些間距,這種需要在 CSS 就很容易了,可以改變left/top/right/bottompaddingborder ...很多方式

          .dragbox{  left: 10px;  top: 10px;  right: 10px;  bottom: 10px;  /*rect: 10px;*/}.dragbox{  padding: 10px;}

          六、說明和小結(jié)

          關(guān)于兼容性本來以為是沒什么問題的,實測下來 ios 問題多多,主要是 safari 滾動容器的問題。例如,有些低版本 ios 滾動不順暢,需要添加

          -webkit-overflow-scrolling:touch才能實現(xiàn)平滑滾動和自動吸附,但是又會導(dǎo)致層級問題,有些文檔上描述設(shè)置該屬性會創(chuàng)建一個原生的滾動容器,層級最高。還有第一種 fixed 布局,如果默認情況下設(shè)置pointer-events: nonetouchstart之后設(shè)置成auto,這個在 ios 上滾動竟然失效了,但是反轉(zhuǎn)過來就可以了(demo中已兼容ios)。


          優(yōu)點嘛,繼承 CSS 的靈活性,幾乎零成本,容易復(fù)用,同時利用了原生滾動,也不會有卡頓。

          不過也有少許局限,如果拖拽目標的尺寸是不固定的,可能需要借助 JS 來獲取了。當然相比較而言,這還是一個性價比極高的實現(xiàn)方式。

          現(xiàn)在回頭看看,其實也沒有用到什么非常生僻的屬性(scroll-snap 可能算一個,不過畢竟是輔助功能),主要還是常見的效果,然后通過聯(lián)想和發(fā)散,根據(jù)平日的積累,充分挖掘原生的能力,最終完成所需要的交互,然后就有了本文。

          感謝閱讀,希望能對日后的工作有所啟發(fā)。

          References

          [1] 起點中文網(wǎng): https://m.qidian.com/
          [2] CSS Scroll Snap: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Scroll_Snap



          推薦閱讀




          一文弄懂 CSS 中重要的 BFC(附圖解)

          你真的懂 JavaScript 閉包與高階函數(shù)嗎?

          JS 中強大的操作符,總有幾個你沒聽說過


          最后



          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)

          2. 歡迎加我微信「 sherlocked_93 」拉你進技術(shù)群,長期交流學(xué)習...

          3. 關(guān)注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。


          點個在看支持我吧,轉(zhuǎn)發(fā)就更好了



          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  麻豆大黑鸡吧 | 亚洲综合网址 | 国产Av特级片 | 俺来俺去在线3区 | 欧美在线无码视频 |