【问题标题】:Streching Layout & Even Distribution of Project Steps: Visualisation of a Custom Progress Bar (CSS/HTML)拉伸布局和项目步骤的均匀分布:自定义进度条 (CSS/HTML) 的可视化
【发布时间】:2022-06-11 04:53:55
【问题描述】:

我一直在制作一个显示三种步骤的自定义进度条:donebusytodo 步骤。基本的 html ul li 是基于 flexbox 的,可以在其中添加或取出项目,而不会破坏布局的完整性。

我想要左右延伸的步骤,但是如果不破坏项目的宽度就无法实现。 所有台阶的宽度应相等。 当前的设计工作(并且必须继续工作)只需一、二、三、四或五个步骤。

我希望整个进度条按比例拉伸并完全填充黄色区域。

最终的预期结果应如下所示:

这里,第一个和最后一个项目符号应该接触黄色背景的末端,所有项目符号应该在文本单词上方居中。

可以有两种变化:1)子弹之间的距离相等。 2)项目符号间距取决于文本单词的长度。两者都可以,以包含最少的代码为准。

总之,答案应该是:

  • 去掉进度条左右两边未使用的黄色空间
  • 在均匀分布所有项目符号及其文本的同时
  • 所有项目符号应保持在文本上方的中心
  • 当两个、三个、四个和五个 li 项目填充无序列表时保持工作。

演示

https://jsfiddle.net/9s48naw0/

body{
  background: lightblue;
  width: auto;
  padding: 50px;
}
a{text-decoration: none}

.progress {
    display: flex;
    background: yellow;
    width: auto;
}

.progress>li {
    flex: 1;
}

.progress>li, .progress>li a{
    list-style: none;
    text-align: center;
    width: auto;
    padding: 0;
    margin: 0;
    position: relative;
    text-overflow: ellipsis;
    color: lightgrey;
    display: block;
}

.progress>li .circle {
    border-radius: 50%;
    width: 24px;
    height: 24px;
    background: lightgrey;
    display: block;
    margin: 0 auto .5em;
}

.progress>li .circle:after,
.progress>li .circle:before {
    display: block;
    position: absolute;
    top: 10px;
    width: 100%;
    height: 4px;
    content: '';
    background: lightgrey;
}


.progress>li :before {left: 0}
.progress>li :after {right: 0}

.progress>li:first-child .circle:after,
.progress>li:first-child .circle:before {
    width: 50%;
    margin-left: 50%
}

.progress>li:last-child .circle:after,
.progress>li:last-child .circle:before {
    width: 50%;
    margin-right: 50%
}

.progress>li.done .circle,
.progress>li.done .circle:after,
.progress>li.done .circle:before {background: green}
.progress>li.done,
.progress>li.done a{color: green}

.progress>li.busy .circle,
.progress>li.busy .circle:after,
.progress>li.busy .circle:before {background: violet}
.progress>li.busy,
.progress>li.busy a{color: violet}
<ul class="progress">


  <li class="done">
    <a href="#" title="More about the First Step">
      <span class="circle"></span>
    Step1</a>
  </li>


  <li class="done">
    <a href="#" title="Afterwards the Second Step">
      <span class="circle"></span>
    Step2</a>
  </li>


  <li class="busy">
    <a href="#" title="This about the current active Step">
      <span class="circle"></span>
    Step3</a>
  </li>


  <li>
    <a href="#" title="Future Next Step">
      <span class="circle"></span>
    Step4</a>
  </li>


  <li>
    <a href="#" title="And the Final Step">
      <span class="circle"></span>
    Step5</a>
  </li>


</ul>

【问题讨论】:

    标签: css layout flexbox css-selectors progress-bar


    【解决方案1】:

    @Sam,请检查结果并告诉我您的意见。希望对你有帮助~

    body {
                background: lightblue;
                width: auto;
                padding: 50px;
            }
    
            a {
                text-decoration: none
            }
    
            .progress {
                display: flex;
                background: yellow;
                width: auto;
                padding: 0;
            }
    
            .progress>li {
                flex: 2;
            }
    
            .progress>li:first-child,
            .progress>li:last-child {
                flex: 1;
            }
    
            .progress>li:first-child a {
                text-align: left;
            }
    
            .progress>li:last-child a {
                text-align: right;
            }
    
            .progress>li,
            .progress>li a {
                list-style: none;
                text-align: center;
                padding: 0;
                margin: 0;
                position: relative;
                text-overflow: ellipsis;
                color: lightgrey;
                display: block;
            }
    
            .progress>li .circle {
                border-radius: 50%;
                width: 24px;
                height: 24px;
                background: lightgrey;
                display: block;
                margin: 0 auto .5em;
            }
    
            .progress>li:first-child .circle {
                margin-left: 7px;
            }
    
            .progress>li:last-child .circle {
                margin-right: 7px;
            }
    
            .progress>li .circle:after,
            .progress>li .circle:before {
                display: block;
                position: absolute;
                top: 10px;
                width: 100%;
                height: 4px;
                content: '';
                background: lightgrey;
            }
    
            .progress>li :before {
                left: 0
            }
    
            .progress>li :after {
                right: 0
            }
    
            .progress>li:first-child .circle:after,
            .progress>li:first-child .circle:before {
                width: 50%;
            }
    
            .progress>li:last-child .circle:after,
            .progress>li:last-child .circle:before {
                width: 50%;
            }
    
            .progress>li:first-child .circle::before {
                width: calc(50% - 10px);
                left: 10px;
            }
            .progress>li:last-child .circle::after {
                width: calc(50% - 10px);
                right: 10px;
            }
    
            .progress>li.done .circle,
            .progress>li.done .circle:after,
            .progress>li.done .circle:before {
                background: green
            }
    
            .progress>li.done,
            .progress>li.done a {
                color: green
            }
    
            .progress>li.busy .circle,
            .progress>li.busy .circle:after,
            .progress>li.busy .circle:before {
                background: violet
            }
    
            .progress>li.busy,
            .progress>li.busy a {
                color: violet
            }
    <ul class="progress">
    
    
      <li class="done">
        <a href="#" title="More about the First Step">
          <span class="circle"></span>
        Step1</a>
      </li>
    
    
      <li class="done">
        <a href="#" title="Afterwards the Second Step">
          <span class="circle"></span>
        Step2</a>
      </li>
    
    
      <li class="busy">
        <a href="#" title="This about the current active Step">
          <span class="circle"></span>
        Step3</a>
      </li>
    
    
      <li>
        <a href="#" title="Future Next Step">
          <span class="circle"></span>
        Step4</a>
      </li>
    
    
      <li>
        <a href="#" title="And the Final Step">
          <span class="circle"></span>
        Step5</a>
      </li>
    
    
    </ul>

    【讨论】:

    • @sam,编辑了动态宽度,但是对于文本对齐,我们需要更改 html 的结构。我认为将当前的文本对齐作为前端开发体验非常有用。
    • 使用 calc() 的精妙阐述。从我最初的测试来看,它似乎工作得很好!如果我理解正确,您想更改可能有利于设计的 HTML 结构吗?欢迎您,继续更新您的 sn-p。
    • 再次感谢 Alex 的出色贡献。您的解决方案和 Witney O. 的解决方案都能 100% 完美运行!选择授予谁非常非常困难!差异非常小。她更好的解释和阐述为她赢得了奖项,但你是第一个回答的,所以你我接受你的回答!
    【解决方案2】:

    我的想法是这样开始的: 由于每个 li 项有两半,并且第一项和最后一项是一半,因此最佳比例是1:2:2:2:1。这意味着每个 li 项目将是第一个和最后一个项目的两倍。因此,flex:1 用于 li,flex:0.5 用于第一个和最后一个。

    .progress>li { 
    flex: 1; 
    } 
    .progress>li:last-child{
     flex:0.5;
     } 
    .progress>li:first-child { 
    flex:0.5; 
    }
    

    然后将第一个和最后一个圆圈中的内容发送到边缘而不是中心。

    .progress>li:last-child, 
    .progress>li:last-child a
    { text-align: right; } 
    
    .progress>li:first-child, 
    .progress>li:first-child a
    { text-align: left; }
    

    所有li项的左右边距设置为margin: 0 auto .5em;

    更改第一个和最后一个圆圈中伪元素的边距。

    .progress>li:first-child .circle:after, 
    .progress>li:first-child .circle:before { 
    width: 50%; 
    margin: 0 auto 0 0.5em; 
    } 
    .progress>li:last-child .circle:after, 
    .progress>li:last-child .circle:before { 
    width: 50%; 
    margin: 0 0.5em 0 auto; 
    }
    

    完整的 CSS 是:

    body{
      background: lightblue;
      width: auto;
      padding: 50px;
    }
    a{text-decoration: none}
    
    .progress {
        display: flex;
        background: yellow;
        width: auto;
      padding:0;
    }
    
    .progress>li {
        flex: 1;
    }
    .progress>li:last-child{
      flex:0.5;
    }
    .progress>li:first-child {
      flex:0.5;
    }
    
    .progress>li, .progress>li a{
        list-style: none;
        text-align: center;
        width: auto;
        padding: 0;
        margin: 0;
        position: relative;
        text-overflow: ellipsis;
        color: lightgrey;
        display: block;
    }
    
    .progress>li:last-child, .progress>li:last-child a{
      text-align: right;
      }
    .progress>li:first-child, .progress>li:first-child a{
      text-align: left;
      }
    
    .progress>li .circle {
        border-radius: 50%;
        width: 24px;
        height: 24px;
        background: lightgrey;
        display: block;
        margin: 0 auto .5em;
    }
    
    .progress>li .circle:after,
    .progress>li .circle:before {
        display: block;
        position: absolute;
        top: 10px;
        width: 100%;
        height: 4px;
        content: '';
        background: lightgrey;
    }
    
    
    .progress>li :before {left: 0}
    .progress>li :after {right: 0}
    
    .progress>li:first-child .circle:after,
    .progress>li:first-child .circle:before {
        width: 50%;
        margin: 0 auto 0 0.5em;
    }
    
    .progress>li:last-child .circle:after,
    .progress>li:last-child .circle:before {
        width: 50%;
        margin: 0 0.5em 0 auto;
    }
    
    .progress>li.done .circle,
    .progress>li.done .circle:after,
    .progress>li.done .circle:before {background: green}
    .progress>li.done,
    .progress>li.done a{color: green}
    
    .progress>li.busy .circle,
    .progress>li.busy .circle:after,
    .progress>li.busy .circle:before {background: violet}
    .progress>li.busy,
    .progress>li.busy a{color: violet}
    
    .progress>li:last-child .circle{
      margin: 0 0.5em 0.5em auto;
    }
    .progress>li:first-child .circle{
      margin: 0 auto 0.5em 0.5em;
    }
    

    子弹是等距的。在this pen 上查看结果。

    【讨论】:

    • 请在您的答案中添加支持细节以改进它。
    • 已修复。这是圆圈跨度上的边距。
    • 很棒的 Flexbox 解决方案!如果您希望可以在答案中将新旧 CSS 合并到一个代码块中并清理重复的选择器。 (无需将旧代码与您的答案分开)。随意组合和清理你美丽的答案!更少的代码意味着更优雅的解决方案。根据 Ethan 的建议,您也可以随意用几句话写出您在回答中所做的事情。
    • 添加了更多细节,Ethan。感谢您指出这一点。
    • Whitney O. 欢迎来到 Stack Overflow,作为对我的敬意的一个小小的象征,我向您表示感谢,因为您的代码最短且非常优雅。谢谢!
    【解决方案3】:

    试试这个解决方案,重建。我使用 grid 而不是 flexbox 来删除不必要的 DOM 元素并简化 html 和 css。此外,在您的解决方案中,链接没有间隙。例如,如果用户在两步之间点击中间,会发生什么?在这种情况下,最好的方法是在没有交互的情况下保持差距。 另一种奇怪的做法,busy在中间跟踪(线)?看起来更熟悉,如果只有 dot 具有状态 busy 或 dot 和整个轨道。

    <section class="progress">
      <a href="#" class="step done" title="More about the First Step"> Step1</a>
      <a href="#" class="step done" title="Afterwards the Second Step"> Step2</a>
      <a href="#" class="step busy" title="This about the current active Step"> Step3</a>
      <a href="#" class="step" title="Future Next Step"> Step4</a>
      <a href="#" class="step" title="And the Final Step"> Step5</a>
    </section>
    

    5 个步骤

    *,
    ::after,
    ::before {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    a {
      text-decoration: none;
    }
    
    .progress {
      --step-width: 1.5rem;
      --outside-margin: 1.5rem;
      --track-number: 4;
      --disable-color: lightgrey;
      --busy-color: violet;
      --done-color: green;
    
      display: grid;
      grid-auto-columns: max-content;
      grid-auto-flow: column;
      grid-template-rows: calc(var(--step-width) * 2);
      justify-content: space-between;
      align-items: flex-end;
      background: yellow;
      width: auto;
      margin-inline: var(--outside-margin);
    }
    
    .step {
      display: flex;
      align-items: flex-end;
      height: 100%;
      position: relative;
      color: var(--disable-color);
    }
    .step:not(:first-child):after {
      content: '';
      /* Take entire width and subtracting right, left margin,
      then divide into four tracks and subtract half of one column. */
      width: calc((100vw - var(--outside-margin) * 2) / var(--track-number) - (var(--step-width) / 2));
      height: 4px;
      position: absolute;
      top: 10px;
      right: 50%;
      background: var(--disable-color);
      pointer-events: none;
      z-index: 1;
    }
    .step::before {
      content: '';
      width: var(--step-width);
      height: var(--step-width);
      position: absolute;
      top: 0px;
      left: 50%;
      background: var(--disable-color);
      border-radius: 50%;
      transform: translateX(-50%);
      z-index: 2;
    }
    .done {
      color: var(--done-color);
    }
    .busy {
      color: var(--busy-color);
    }
    .step.done::after,
    .step.done::before {
      background: var(--done-color);
    }
    .step.busy::after,
    .step.busy::before {
      background: var(--busy-color);
    }
    <section class="progress">
      <a href="#" class="step done" title="More about the First Step"> Step1</a>
      <a href="#" class="step done" title="Afterwards the Second Step"> Step2</a>
      <a href="#" class="step busy" title="This about the current active Step"> Step3</a>
      <a href="#" class="step" title="Future Next Step"> Step4</a>
      <a href="#" class="step" title="And the Final Step"> Step5</a>
    </section>

    4 个步骤

    *,
    ::after,
    ::before {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    a {
      text-decoration: none;
    }
    
    .progress {
      --step-width: 1.5rem;
      --outside-margin: 1.5rem;
      --track-number: 3;
      --disable-color: lightgrey;
      --busy-color: violet;
      --done-color: green;
    
      display: grid;
      grid-auto-columns: max-content;
      grid-auto-flow: column;
      grid-template-rows: calc(var(--step-width) * 2);
      justify-content: space-between;
      align-items: flex-end;
      background: yellow;
      width: auto;
      margin-inline: var(--outside-margin);
    }
    
    .step {
      display: flex;
      align-items: flex-end;
      height: 100%;
      position: relative;
      color: var(--disable-color);
    }
    .step:not(:first-child):after {
      content: '';
      /* Take entire width and subtracting right, left margin,
      then divide into four tracks and subtract half of one column. */
      width: calc((100vw - var(--outside-margin) * 2) / var(--track-number) - (var(--step-width) / 2));
      height: 4px;
      position: absolute;
      top: 10px;
      right: 50%;
      background: var(--disable-color);
      pointer-events: none;
      z-index: 1;
    }
    .step::before {
      content: '';
      width: var(--step-width);
      height: var(--step-width);
      position: absolute;
      top: 0px;
      left: 50%;
      background: var(--disable-color);
      border-radius: 50%;
      transform: translateX(-50%);
      z-index: 2;
    }
    .done {
      color: var(--done-color);
    }
    .busy {
      color: var(--busy-color);
    }
    .step.done::after,
    .step.done::before {
      background: var(--done-color);
    }
    .step.busy::after,
    .step.busy::before {
      background: var(--busy-color);
    }
    <section class="progress">
      <a href="#" class="step done" title="More about the First Step"> Step1</a>
      <a href="#" class="step done" title="Afterwards the Second Step"> Step2</a>
      <a href="#" class="step busy" title="This about the current active Step"> Step3</a>
      <a href="#" class="step" title="Future Next Step"> Step4</a>
      <!-- <a href="#" class="step" title="And the Final Step"> Step5</a> -->
    </section>

    【讨论】:

    • 非常感谢您的精彩回答!不幸的是,问题中的最后一个子弹没有解决! (当&lt;li&gt; 步数少于五个时,布局会中断)。我奖励了刚刚加入 Stack Overflow 的新人,因为她的解决方案确实解决了最后一个问题:当&lt;li&gt; 步骤少于五个时,她的布局不会中断。
    • 布局中断,因为我创建了五个步骤的计算。所以,5 个步骤有 4 个轨道,如果你需要 4 个步骤,process 类有变量 --track-number 并且只需要将数量轨道从 4 更改为 3。
    猜你喜欢
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    相关资源
    最近更新 更多