首页 > 其他分享 >创建水平滚动的正确方式【CSS 网格布局】

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

时间:2022-11-28 11:09:49浏览次数:37  
标签:滚动 hs 网格 grid columns template 10px CSS

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

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

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

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

UX(用户体验)的考虑

UX/UE -> User Experience 译者加

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

  • ​​你的设计必须在视觉上提醒他人,这是一组可以水平滚动的内容。最好的方法,就是让可滚动的内容露出一部分。​​
  • ​​用户知道什么时候滚到末尾,这很重要。我们注意到用户重复进行滚动操作,是因为他们认为自己并未充分滚动。一种方法指明列表已经滚到最后:在列表末尾使用额外的空间​​

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

布局大纲

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

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

如下:

创建水平滚动的正确方式【CSS 网格布局】_内边距_03

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

整体布局

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

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

.app {
display: grid;
grid-template-columns: 20px 1fr 20px;
}
.app > * {
grid-column: 2 / -2;
}
.app > .full {
grid-column: 1 / -1;
}

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

滚动容器

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

.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​​。这时候,我们会看到第三张卡片露出来。

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

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

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

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

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

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

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

.hs > li:last-child {
margin-right: 20px;
}

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

建议的解决方案

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

.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​​,所以满足我们整体布局的内边距要求。

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

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

.hs::before,
.hs::after {
content: ‘’;
}

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

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

注意事项

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

grid-template-columns:
10px
repeat(6, calc(50% - 40px))
10px;

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

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

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 中使用变量:

grid-template-columns:
10px
repeat(var(--total) , calc(50% - 40px)) // 重点
10px;

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

为此,我们调整下代码:

.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-flow​​​ 为 ​​column​​​(默认值是 ​​row​​)。

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

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

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

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


标签:滚动,hs,网格,grid,columns,template,10px,CSS
From: https://blog.51cto.com/u_11966691/5890702

相关文章

  • css代码大全
    字体属性:(font)大小{font-size:x-large;}(特大)xx-small;(极小)一般中文用不到,只要用数值就可以,单位:PX、PD样式{font-style:oblique;}(偏斜体)italic;(斜体)norm......
  • css代码大全2
    一CSS文字属性:color:#999999;/*文字颜色*/font-family:宋体,sans-serif;/*文字字体*/font-size:9pt;/*文字大小*/font-style:itelic;/*文字斜体*/font-var......
  • CSS错题小结
    一.列出所知的CSS选择器1.基本选择器:id选择器,类选择器,标签选择器,通配符选择器(*)复合选择器:后代选择器(.box1.box2),并集选择器(.box1,.box2),交集选择器(.box1.bo......
  • css五彩导航栏设计
    1.将行内元素转换为行内块元素,display:inline-block;2.文字水平垂直居中,text-align:center;               line-height:40px;       ......
  • 76.图表的常用设置—设置坐标轴和网格线
     ---------------------------------------------------------------------------------------------------------------------------------------------------------......
  • 基于一段神奇的CSS渐变制作噪点效果
    提及噪点效果,首先想到的就是以前的旧电视机信号不稳定时或者画面不稳定时的效果。如果你没有看过那种旧电视,可以看下面的gif动图,真实的情况噪点的变化速度会快很多,这里为了g......
  • 拓端tecdat|Python编程指导中基于网格搜索算法优化的深度学习模型分析糖尿病数据
    Python中基于网格搜索算法优化的深度学习模型分析糖尿病数据  介绍在本教程中,我们将讨论一种非常强大的优化(或自动化)算法,即网格搜索算法。它最常......
  • css背景线性渐变实现图标
    利用css的linear-gradient绘制图标。效果如图。代码如下。<!DOCTYPEhtml><htmllang="zh"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content=......
  • 介绍27款经典的CSS框架
    利用CSS框架,可以简化你的工作,提高工作效率。CSS框架是一系列CSS文件的集合体,包含了基本的元素重置,页面排版、网格布局、表单样式、通用规则等代码块。下面给你推荐了27......
  • 43个PSD to XHTML,CSS教程
    在中国,很多前端开发初学者都会把xHTML+CSS页面制作说成​​DIV+CSS​​​,甚至很多人都还不知道xHTML+​​CSS​​是什么意思,只知道盲目的追求DIV+CSS,但在国外,是没有DIV+CSS......