水平滚动列表完全以动态宽度项为中心

时间:2016-07-21 07:00:35

标签: html css width centering horizontal-scrolling

我试图使一个水平列表居中,其中的项目也是关于主要父级(窗口或正文)的中心;因为我不知道我将在该列表中生成什么类型​​和多少项目,所以我需要这些项目在宽度上是动态的,并且列表可以滚动,因此我可以浏览所有项目。 / p>

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

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

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

li {
  display: inline-block;
}

然后通过将<ul>打包到<div>,并使<div>滚动<ul>而不是<ul>滚动<li>来进行居中{1}}。它允许将基于%的边距添加到<ul>

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

ul {
  margin: 0 50%;
}

li {
  display: inline-block;
}

对于以宽度为中心的项目,我们的想法是稍微使用translateX(-50%):因为我不希望我的列表在滚动结束时有额外的空间,我&#39 ; m通过在末尾将其放在绝对位置来移除流中的最后一项;这样,<ul>宽度看起来就像是项目宽度减去一个项目的总和。

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

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

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

但如何在不设置宽度的情况下保持这种方式对我来说是一个谜 那里有什么想法吗?

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

我希望完全使用javascript,因为它只是造型的问题,但是弄乱dom是一个完全可行的选择。

感谢大家的阅读,

1 个答案:

答案 0 :(得分:0)

好的,这有点棘手。解决的小提琴在这里有评论,我也将在这里描述。 https://jsfiddle.net/11gkrju0/7/

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

,然后

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

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

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

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

要使向右滚动,我们需要将<ul>的宽度从A-> B更改为C-> D。由于其宽度是通过子宽度动态计算的,我们需要改变孩子。

我们可以看到只有第一个和最后一个孩子才被改变。由于文本定义了每个子元素的宽度,我们不能更改width属性,但我们可以更容易地将某些定义值除以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添加一个text属性,以便为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;
}

几乎就在那里,差不多......

第一个和最后一个孩子已经被改变了,所以他们的伪孩子也被改变了...副作用是宽度将被计算为6px字体大小。所以我们需要将宽度设置为需要的两倍,并重置字体大小以防止继承。

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

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

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

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

希望它可以帮助别人。