前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >创建水平滚动的正确方式【CSS 网格布局】

创建水平滚动的正确方式【CSS 网格布局】

作者头像
Jimmy_is_jimmy
发布2022-11-22 16:35:40
2.6K0
发布2022-11-22 16:35:40
举报
文章被收录于专栏:call_me_R

theme: fancy

原文链接 Creating horizontal scrolling containers the right way [CSS Grid] -- 作者 Dannie Vinther

自从奈飞 Netflix 成为了家喻户晓的名字以来,在移动端中我们一直使用横向布局。水平滚动容器(列表)已经成为了一种常见的布局做法,而不是将东西都堆叠在页面上,这将减少占用小屏幕设备垂直的空间。

本文,我们探讨 CSS 网格的弹性布局,它是如何帮助我们实现水平滚动的,同时处理它带来的缺陷。

UX(用户体验)的考虑

UX/UE -> User Experience 译者加

本文不会深入讨论水平滚动的用户体验方面。但是,当采用水平滚动布局时,至少需要满足两点 UX 原则:

布局大纲

开始前,我们概览下需要实现的布局特性:

  • 滚动的容器必须准守页面的整体布局。比如,外边距和内边距整体要一致。
  • 滚动的部分内容,必须在容器边缘露出来。
  • 滚动时,容器的内容必须从屏幕的边缘滑出来。
  • 容器内两个内容之间的距离要小于边缘的距离,这样容器两端都会有更大的空间(这提示用户他们已经滑到最后)。

如下:

需要注意的是,容器两端的距离和周围内容的距离是匹配的(也就是整体布局要和谐)。

整体布局

现在,我们已经基本明白水平滚动容器的特性了。接下来,我们考虑使用 CSS Grid 网格布局来编码。使用 CSS Grid 网格布局方便我们控制元素之间的距离,无需进一步计算。

对于整体布局,我们将使用简单但强大的 CSS Grid 技术:

代码语言:javascript
复制
.app {
  display: grid;
  grid-template-columns: 20px 1fr 20px;
}
.app > * {
  grid-column: 2 / -2;
}
.app > .full {
  grid-column: 1 / -1;
}

.app 类元素下的子元素都会被“容器化”,它们都有 20px 的边距,使得内容远离边缘。带 .full 类名的子元素,将会占据全部视窗的宽度且没有内边距。

滚动容器

我们使用六个卡片来创建水平滚动容器,一次显示两张。因为我们考虑整体布局,水平滚动的两边填充内边距,我们删除了 .full 类,然后添加如下:

代码语言:javascript
复制
.hs {  
  display: grid;  
  grid-gap: 10px;  
  grid-template-columns: repeat(6, calc(50% - 40px));  
  grid-template-rows: minmax(150px, 1fr);  
}

使用 grid-template-columns,我们可以设置每个卡片需要的空间。在这个例子中,卡片占有视图空间的 50% 减去间隔 40px。这时候,我们会看到第三张卡片露出来。

然而,需要注意的是,卡片两端被砍断部分。还记得不,当水平滚动的时候,我们希望可滚动的内容是从屏幕的边缘滑出。

所以,我们在容器中添加 .full 类,并填补缺失的内边距。

代码语言:javascript
复制
.hs {  
  display: grid;  
  grid-gap: 10px;  
  grid-template-columns: repeat(6, calc(50% - 40px));  
  grid-template-rows: minmax(150px, 1fr);  
  padding: 0 20px; // 添加
}

乍一看,我们好像实现了需求,但是当你滚动到尾部的时候,你会注意到并没有其他空间了 -- 所以这并不符合整体布局。

你可能想在最后一个元素添加 margin-right 的属性值以处理这个问题:

代码语言:javascript
复制
.hs > li:last-child {
  margin-right: 20px;
}

很不幸,这并不起作用。那么,我们要怎么处理呢?

建议的解决方案

考虑我们目前都有了些什么内容,我们删除容器中的内边距:

代码语言:javascript
复制
.hs {  
  display: grid;  
  grid-gap: 10px;  
  grid-template-columns: repeat(6, calc(50% - 40px));  
  grid-template-rows: minmax(150px, 1fr);
}

如果我们在 grid-template-columns 两边添加内边距,会实现我们要的布局。

我们在网格列两端添加了 2 x 10px 的空间。结合 10px 的网格距离,我们总共有 20px,所以满足我们整体布局的内边距要求。

代码语言:javascript
复制
.hs {  
  display: grid;  
  grid-gap: 10px;  
  grid-template-columns: // 更改
    10px  
    repeat(6, calc(50% - 40px))  
    10px;  
    grid-template-rows: minmax(150px, 1fr);
}

为了不让第一张卡片占用第一列的 10px 的空间,我们在每一端引入空的伪元素:

代码语言:javascript
复制
.hs::before,  
.hs::after {  
  content: ‘’;  
}

伪元素 ::before::after 非常适合 grid-columns 布局,因为会自动添加到水平滚动容器的开头和结尾。伪元素能够参与网格化布局让人心存感激。

现在,我们实现了一开始在大纲中提到的特性。

注意事项

这项技术的一个注意事项是在 grid-template-columns 中对既定卡片数量的计算。

代码语言:javascript
复制
grid-template-columns:  
  10px
  repeat(6, calc(50% - 40px))  
  10px;

如果容器中只是包含 4 个卡片,你需要为该特定容器设定新的网格规则。这不是很灵活。

一种使其更灵活的处理方式是,你可以使用 Javascript 来计算卡片的数量,然后将其分配给 CSS 变量。

代码语言:javascript
复制
var root = document.documentElement;
const lists = document.querySelectorAll('.hs');lists.forEach(el => {
  const listItems = el.querySelectorAll('li');
  const n = el.children.length;
  el.style.setProperty('--total', n); 
});

然后,你就可以在 grid-template-columns 中使用变量:

代码语言:javascript
复制
grid-template-columns:  
  10px  
  repeat(var(--total) , calc(50% - 40px)) // 重点 
  10px;

更新:Alex Baciu 提及,我们可以通过使用隐式网格完全省略 Javascript(或者 CSS 变量解决方案)。这样,我们不需要计算超出列的数量,因为这是浏览器为我们计算的。

为此,我们调整下代码:

代码语言:javascript
复制
.hs {
  ...
  grid-template-columns: 10px;
  grid-auto-flow: column; 
  grid-auto-columns: calc(50% - var(--gutter) * 2);
  ...
....hs:before,
.hs:after {
  content: '';
  width: 10px; 
}

我们仍然需要最初的 10px 内边距来弥补不足,然而,剩下的卡片通过自动放置算法布局。为此,我们需要设置 grid-auto-flowcolumn(默认值是 row)。

最后,我们需要确保的是 .hs:after ,它继承了其他卡片的大小,其占用的空间不超过 10px。所以我们需要通过固定的宽度来限定。

代码片段

你可能会争辩,代码变得不那么清晰了,因为赋值更加分散,使得正在发生的东西变得混乱。但是,我觉得还行 :)

译者加:本文滚动的技术交流为主,熟悉其原理。真正业务上操作,建议使用成熟的 Swiper 操作。

本文正在参加「金石计划 . 瓜分6万现金大奖」

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • theme: fancy
    • UX(用户体验)的考虑
      • 布局大纲
        • 整体布局
          • 滚动容器
            • 建议的解决方案
              • 注意事项
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档