什么?CSS 能实现鼠标滚轮的横向滚动?

再次考验你的css功底,这样的横向平滑滚动效果,只用css就可以实现,想不想来挑战一下?

看到这个效果同学们脑子里第一个想到的是什么?监听鼠标的滚轮事件吗?其实也可以实现但是非常的麻烦,因为要做到平滑滚动的话,还要去算这个事件的触发频率以及滚动的距离。

我是渡一子辰老师,今天给大家介绍的是纯CSS 实现横向滚动的原理和步骤,通过具体的代码示例和深入的技术分析,让你的技术更上一层楼!

思考

要实现这个效果其实很简单,只需要换个角度看问题就行了。

我们都知道鼠标滚轮可以控制的是竖向的滚动条,那如果我们把显示器旋转 90 度呢?比如下图这样:

这样竖的滚动条是不是就变成横的了,而且鼠标依然可以控制它。怎么样?是不是很有趣。

虽然旋转显示器是在搞笑,但是这个思维的转换其实就是这个效果实现的切入点,我们可以用 css 来旋转元素,达到同样的效果。

我们今天将这个效果做成一个 vue 的通用组件,组件的名字就叫做 XScroll 吧。先看一下 XScroll 组件的嵌套结构,为什么这样嵌套看接下来的图例你就明白了。

<template>
  <div class="container">
    <div class="scroll">
      <div class="content">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

如上图所示,通过之前的思考我们知道换个角度看就可以实现效果,那么我们用代码把想法实现出来就好了。

通过图 我们知道,scroll 其实是竖着的,这样 scroll 的滚动条我们才可以通过鼠标滚轮控制,然后我们通过 css 将 scroll 旋转成图 的样子,这样 scroll 的竖向滚动条就变成了横向的,我们依然可以通过鼠标滚轮来控制。

因为 container 是我们的最外围的容器,而 scroll 与 container 是一样大的,但是我们要知道 scroll 最开始是竖着的。也就说,scroll 的宽等于 container 的高,scroll 的高等于 container 的宽。

好了,思路到这里我们已经清楚了,接下来就是用代码把想法实现出来。

实现

首先我们知道 scroll 的大小是根据 container 的大小来的,所以我们必须知道 container 的大小,这里我们通过之前写过的一个 Vue 指令来获取 container 的大小,并且指令可以在 dom 元素的大小改变时获取最新的尺寸,指令的代码放在最后。

<template>
  <!-- v-size-ob 指令,可以在 dom 元素改变大小时获取 dom 元素的尺寸,并且返回尺寸 -->
  <div v-size-ob="handleChange" class="container">
    <div class="scroll">
      <div class="content">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

<script setup>
import { reactive } from 'vue';
const s = reactive({ // 声明一个响应式数据存储一下
  w: 0,
  h: 0,
});
function handleChange(size) { // 通过 v-size-ob 指令的返回值获取 container 的大小
  s.w = size.width;
  s.h = size.height;
}
</script>

<style scoped>
/* 为每一个盒子加上边框方便查看效果 */
.container {
  outline: 5px solid #ec7270;
  width: 100%;
  height: 100%;
}
.scroll {
  outline: 5px solid #7985ec;
  /* 通过 vue3 的 v-bind 在 style 中获取值 */
  /* 因为宽高是有单位的,所以利用 calc 乘以 1px 给宽高加上单位 */
  /* scroll 宽等于 container 的高  */
  width: calc(v-bind("s.h") * 1px);
  /* scroll 高等于 container 的宽  */
  height: calc(v-bind("s.w") * 1px);
}
.content {
  outline: 5px solid #f1ac6a;
  height: calc(v-bind("s.h") * 1px);
}
</style>

通过以上代码我们可以的到上图中的效果,那么下一步我们就要旋转一下 content,使其放置于 scroll 中,并且 scroll 要出现滚动条。

.scroll {
  outline: 5px solid #7985ec;
  width: calc(v-bind("s.h") * 1px);
  height: calc(v-bind("s.w") * 1px);
  position: relative;
  overflow: auto;
}
.content {
  outline: 5px solid #f1ac6a;
  height: calc(v-bind("s.h") * 1px);
  position: absolute;
  left: 100%;
  transform-origin: 0 0;
  transform: rotate(90deg);
}

现在我们得到了这样的效果。

可以说现在我们已经实现了,就差最后一步了,我们将 content 旋转到 container 里就大功告成了。

按照惯例请看图。

.scroll {
  outline: 5px solid #7985ec;
  width: calc(v-bind("s.h") * 1px);
  height: calc(v-bind("s.w") * 1px);
  position: relative;
  overflow: auto;
  transform-origin: 0 0;
  transform: translateY(calc(v-bind("s.h") * 1px)) rotate(-90deg);
}

最后我们隐藏滚动条去除边框就得到了我们所需要的效果啦!

自定义指令代码

const map = new WeakMap();
const ob = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const handler = map.get(entry.target);
    if (handler) {
      const box = entry.borderBoxSize[0];
      handler({
        width: box.inlineSize,
        height: box.blockSize,
      });
    }
  }
});

export default {
  mounted(el, binding) {
    ob.observe(el);
    map.set(el, binding.value);
  },
  unmounted(el) {
    ob.unobserve(el);
  },
};

总结

整个实现过程非常巧妙地使用了 css,让我们感受到了 css 的强大和灵活。

当然这只是一个非常小的知识点,因为 CSS 是我们永远学不会的语音啊。

如果你有什么问题或建议,请在评论区留言,如果你觉得这篇文章有用,请点赞收藏或分享给你的朋友!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容