代码之家  ›  专栏  ›  技术社区  ›  y_nk

水平可滚动列表完全居中,具有动态宽度项

  •  0
  • y_nk  · 技术社区  · 8 年前

    我正试图使一个水平列表居中,它的项目也要居中于主父项(窗口或正文);因为我不知道我会在这个列表中生成什么类型和多少项,所以我需要这些项的宽度是动态的,列表是可滚动的,这样我就可以浏览所有的项。

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

    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%) 稍微改变一下:由于我不希望我的列表在滚动结束时有额外的空间,我将通过在末尾将其定位为绝对值来从流中删除最后一项;那样的话 <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/

    我想

    谢谢大家的阅读,

    1 回复  |  直到 8 年前
        1
  •  0
  •   y_nk    8 年前

    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添加一个文本属性即可满足 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%;
    }
    

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

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

    我们本来可以用 transform: translateX(-50%); 而且,我们已经在操作绝对值,因此不需要在其上应用其他计算层。

    希望它能帮助别人。