发挥你的想象,CSS也能实现拖拽效果。
一、拖拽效果示例
这是移动端很常见的一个效果,可以按住拖来拖去,比如下面的 起点中文网 [1] 触屏版:
这类效果用JS可以很容易实现,无非就是多了一些计算,多考虑了一些临界场景,然后代码量也多了一些。不过,经过我的一番脑洞,发现CSS也能几乎实现这一效果,接着往下看。
二、CSS实现原理
在传统 web 中,页面滚动是一个很常见交互,操作上就是 利用鼠标滚轮或者直接拖动滚动条 。但是,移动端可不一样, 直接用手指拖动页面就可以滚动了。 通常页面是要么垂直方向滚动,要么水平方向滚动, 如果两个方向都可以滚动呢? 例如
.dragbox{ width: 300px; height: 300px; overflow: auto } .dragcon{ width: 500px; height: 500px; }
只需要内部元素宽高都大于容器就实现两个方向的滚动了(记得设置 overflow:auto ),示意如下
一般情况下,鼠标滚轮只能同时滚动一个方向(按住 Shift 可以滚动另一方向),但是移动端可以 直接拖着内容任意滚动 ,如下所示
现在,在内容中间添加一个元素,跟随内容区域一起滚动
接下来,把后面的文本隐藏起来
是不是有点 拖拽 的味道了?原理就是这么简单!
三、CSS实现细节
首先确定拖拽目标与拖拽容器的尺寸关系,假设拖拽目标的尺寸是 w * h ,那么很容易得出的尺寸关系为: 内部尺寸是容器的2倍减去拖拽目标的尺寸
.dragbox{ width: 100%; height: 100%; } .dragcon{ width: calc(200% - w); height: calc(200% - h); }
用一张动图描述如下(中间的橙色块块表示拖拽目标)
四、CSS实现布局
接下来需要把这个特性加入到页面当中,这里列举了两种布局
1. fixed 定位
现在直接把刚才的布局添加到页面上,并添加 fixed 定位
<body> ...页面上的其他元素 <div class=“dragbox”> <div class=“dragcon”></div> <div class=“ball”></div> <!--拖拽元素--> </div> </body>
关键样式如下
.dragbox{ position: fixed; left: 0; top: 0; right: 0; bottom: 0; overflow: auto }
层级示意关系如下
这样一来, dragbox 肯定把页面原有的部分遮挡了,所以还需要添加 pointer-events: none; 同时在拖拽时添加 pointer-events: all
.dragbox{ /*...*/ pointer-events: none; } .ball{ /*...*/ pointer-events: all; } .dragbox.active{ /*...*/ pointer-events: all; }
借助 JS 可以在按下时触发外层容器滚动
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 来动态改变容器的状态,有没有什么办法可以实现 既可以拖拽,又不影响原有页面 呢?下面来看这一种布局,用到了 ab s olute 定位
这里需要对原有页面包裹一层 div 容器,如下
<body> <div class=“dragbox”> <div class=“dragcon”></div> <div class=“ball”></div> </div> <div class=“body”> <!--单独用一层实现页面滚动--> ...页面上的其他元素 </div> </body>
关键样式如下
.dragbox{ position: absolute; width: 100%; height: 100%; overflow: auto; } .body{ position: relative; height: 100%; overflow: auto; } .ball{ position: relative; z-index: 10; /*拖拽目标的层级设置高一点*/ }
现在层级关系就变成了这样
这里原先页面内容在层级上处于 dragbox 和 拖拽目标 之间,所以在拖拽时也不会影响到原有页面的滚动, 无需任何 JS 处理
完整代码可访问https://codepen.io/xboxyan/pen/bGBNQxL(PC访问请打开移动端模式)
也可直接扫描以下二维码
提示:上面两种布局方式,第一种方式适应性更好,不影响现有项目;第二种体验更好,但是会使用 div 作为页面滚动容器,会对页面结构做一定的改动,可以根据实际情况自行选择。
五、CSS实现其他功能
1. 吸附功能
很多时候,在拖拽结束时需要让它自动吸附在边缘,就如同文章开头的示意图一样。那么,通过吸附,可以联想到什么属性呢?
答案就是 CSS Scroll Snap [2]
<body> ...页面上的其他元素 <div class=“dragbox”> <div class=“dragcon”>A</div> <div class=“dragcon”>B</div> <div class=“ball”></div> </div> </body>
下面是关键样式
.dragbox{ ... scroll-snap-type: x mandatory; } .dragcon{ scroll-snap-align: start; }
实际效果如下
完整代码可访问https://codepen.io/xboxyan/pen/XWNJyPw(PC访问请打开移动端模式)
也可直接扫描以下二维码
1. 设置初始位置
默认情况下,拖拽目标是唯有右下角的,如何位于左下角呢?很简单,这里拖拽是滚动容器实现的,所以只 需要改变 scrollLeft 或者 scrollTop 即可
dragbox.scrollLeft = 999; dragbox.scrollTop = 999;
除此之外,也可以采用纯 HTML 方式实现, 利用元素的 autofocus 自动聚焦到可视范围的特性
<div class=“dragcon"> ... <button class="pos" autofocus></button> <!--添加一个自动聚焦的元素--> </div>
比如你希望初始位置在 左上角 ,那么添加一个 右下角 的自动聚焦元素就可以了(当然还需要设置透明度等隐藏起来)~
1. 设置边界
现在拖拽目标的边界是屏幕边缘,有时候可能需要留一些间距,这种需要在 CSS 就很容易了,可以改变 left/top/right/bottom 、 padding 、 border ... 很多方式
.dragbox{ left: 10px; top: 10px; right: 10px; bottom: 10px; /*rect: 10px;*/ } .dragbox{ padding: 10px; }
六、说明和小结
关于兼容性本来以为是没什么问题的,实测下来 ios 问题多多,主要是 safari 滚动容器的问题。例如,有些低版本 ios 滚动不顺畅,需要添加
-webkit-overflow-scrolling:touc h , 才能实现平滑滚动和自动吸附,但是又会导致层级问题,有些文档上描述设置该属性会创建一个原生的滚动容器,层级最高。还有第一种 fixed 布局,如果默认情况下设置 pointer-events: none , 在 touchstart 之后设置成 auto ,这个在 ios 上滚动竟然失效了,但是反转过来就可以了(demo中已兼容ios)。
优点嘛,继承 CSS 的灵活性,几乎零成本,容易复用,同时利用了原生滚动,也不会有卡顿。
不过也有少许局限,如果 拖拽目标的尺寸是不固定的 ,可能需要借助 JS 来获取了。当然相比较而言,这还是一个性价比极高的实现方式。
现在回头看看,其实也没有用到什么非常生僻的属性(scroll-snap 可能算一个,不过毕竟是辅助功能),主要还是常见的效果,然后通过联想和发散,根据平日的积累,充分挖掘原生的能力,最终完成所需要的交互,然后就有了本文。
感谢阅读,希望能对日后的工作有所启发。
References
[1]
起点中文网: https://m.qidian.com/
[2]
CSS Scroll Snap: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Scroll_Snap
CSS,实现拖拽效果,css拖拽
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】