水平滚动列表完全居中,动态宽度项目

horizontal scrollable list fully centered with dynamic width items

我正在尝试使水平列表居中,其项目也相对于主要父项(window 或正文)居中;因为我不知道我将在该列表中生成什么类型​​和多少项目,所以我需要这些项目的宽度是动态的并且列表是可滚动的,这样我就可以浏览所有这些项目。

到目前为止,我的尝试都很好,我得到了:一个居中的列表,其中包含动态宽度的非居中项目;以及具有固定宽度项目的完全居中的可滚动列表。

核心思想基本上是通过使用实现的:

ul {
  width: 100%;
  overflow-x: scroll;
  overflow-y: hidden;
  white-space: nowrap;
}

li {
  display: inline-block;
}

然后通过将 <ul> 包装成 <div> 并使 <div> 滚动 <ul> 而不是 <ul> 滚动来实现居中<li>。它允许将基于百分比的边距添加到 <ul>

div {
  width: 100%;
  overflow-x: scroll;
  overflow-y: hidden;
  white-space: nowrap;
}

ul {
  margin: 0 50%;
}

li {
  display: inline-block;
}

对于按宽度居中的项目,我的想法是使用 translateX(-50%) 稍微改变一下:因为我不希望我的列表在滚动结束时有额外的 space ,我将最后一项从流程中删除,方法是将其绝对定位在末尾;这样,<ul> 宽度看起来就像是项目宽度减去一项的总和。

ul {
  position: relative;
  margin: 0 50%;
}

li {
  display: inline-block;
  width: some_number;
  transform: translateX(-50%);
}

li:last-child {
  position: absolute;
  left: 100%;
}

但是如何在不设置宽度的情况下保持这种状态对我来说是个谜。
有什么想法吗?

这是我的 fiddle,在 CSS 部分有一些评论:https://jsfiddle.net/11gkrju0/

我希望不要为此使用javascript,因为这只是样式问题,但弄乱dom是一个完全可行的选择。

感谢大家的阅读,

好吧,这有点棘手。已解决的 fiddle 附有评论,我也将在此处进行描述。 https://jsfiddle.net/11gkrju0/7/

首先要注意的是,我在 <li> 中添加了一个 vertical-align: top; 以确保在某些点上没有垂直间隙。

然后.

非居中列表的边界很容易捕捉:

+-----+---+---------+
|  A  | B |    C    |
+-----+---+---------+
^                   ^
a                   b

对于居中列表,它们会稍微改变一下:

+-----+---+---------+
|  A  | B |    C    |
+-----+---+---------+
^  ^           ^    ^
a  c           d    b

为了向右滚动,我们需要将 <ul> 的宽度从 A->B 更改为 C->D。由于它的宽度是由它的 children 宽度动态计算的,我们需要改变 children.

我们可以看到只有第一个和最后一个children是要改变的。由于文本定义了每个 children 的宽度,我们不能更改宽度 属性,但我们可以更容易地除以 2 一些定义的值:font-size,padding.

li {
  font-size: 12px;
  padding: 0 50px;
}

li:first-child, li-last-child {
  font-size: 6px;
  padding: 0 25px;
}

现在列表可能看起来更像

+---+---+-----+
| a | B |  c  |
+---+---+-----+
^  ^       ^  ^
a  c       d  b

但接下来的问题是文本和填充现在变小了。我们可以做的是将真正的按钮代理到 :after 中,只需向 li 添加一个文本属性来提供 content 属性.

<li text='A'>A</li>
<li text='B'>B</li>
<li text='C'>C</li>

在 DOM 中,我们可以编写那种 CSS 来创建看起来像真实按钮的假按钮(更不用说,隐藏真实按钮......)

li {
  position: relative;
  background: transparent;
  color: transparent;
}

li:after {
  display: block;
  overflow: hidden;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  content: attr(text);
  color: #000;
}

快到了,快到...

第一个和最后一个 children 已更改,因此它们的 pseudo-child 也被更改...副作用是宽度将计算为 6px font-size。所以我们需要将宽度设置回所需的两倍,并重置 font-size 以防止继承。

li:first-child:after, #d li:last-child:after {
  font-size: 12px;
  width: 200%;
}

最后(是的),我们将第一个元素填充到其宽度的一半,以防止与第二个元素发生冲突。

li:first-child:after {
  left: -100%;
} 

我们也可以使用 transform: translateX(-50%);,但我们已经在处理绝对值,因此无需对其应用其他计算层。

希望对某人有所帮助。