Responsive arrow progress bar with transparent borders
Asked Answered
T

2

8

I am trying to build a progress bar as seen often within checkouts.

Transparent border progress bar

The problem is, that the borders between the arrows are transparent and the whole thing should be responsive. I got it this far:

http://codepen.io/MrBambule/pen/rVBeoz

But I can't figure out how to get the items of the bar to span the whole width of the parent container (red border in the pen) and stay responsive.
I think I could figure it out with JS but I'd rather have a CSS solution.
Help would be much appreciated.

HTML

<ul class="progress-nav">
  <li class="active">
    <span>1. FOO</span>
  </li>
  <li>
    <span>2. BAR</span>
  </li>
  <li>
    <span>3. BAZ</span>
  </li>
</ul>

CSS

$bar-color: rgba(255, 255, 255, 0.2);
$bar-active-color: rgba(255, 255, 255, 0.6);
$arrow-size: 22px;

body {
  background: linear-gradient(left, #803689, #5eb6e4);
}

.progress-nav {
  position: relative;
  font-size: 0;
  margin: 100px auto;
  width: 80%;
  max-width: 900px;

  // dummy border to display the width problem 
  border: 1px solid red;

  li {
    position: relative;
    color: #fff;
    font-size: 12px;
    display: inline-block;
    width: 20%;
    margin-right: 48px;
    list-style: none;
    background: $bar-color;
    padding: $arrow-size 0;

    transition: background .5s, color .5s;

    span {
      position: absolute;
      width: 100%;
      top: 50%;
      left: 50%;
      transform: translateX(-33px) translateY(-35%);
    }

    &:before,
    &:after {
      content: '';
      position: absolute;
      display: block;
      top: 0;

      transition: all .5s;
    }
    &:before {
      border: $arrow-size solid $bar-color;
      border-left-color: transparent;
      left: -$arrow-size*2;
    }
    &:after {
      border: $arrow-size solid transparent;
      border-left-color: $bar-color;
      right: -$arrow-size*2;
    }
    &:first-child:before {
      border: none;
      width: $arrow-size*2;
      height: $arrow-size*2;
      background: $bar-color;
      border-radius: 4px 0 0 4px;
    }
    &:last-child:after {
      border: none;
      right: -$arrow-size;
      width: $arrow-size;
      height: $arrow-size*2;
      background: $bar-color;
      border-radius: 0 4px 4px 0;
    }

    &.active,
    &:hover {
      background: $bar-active-color;
      color: #000;

      &:before {
        border-color: $bar-active-color;
        border-left-color: transparent;
      }
      &:after {
        border-left-color: $bar-active-color;
      }
      &:first-child:before,
      &:last-child:after {
        background: $bar-active-color;
      }
    }
  }
}
Tapp answered 20/4, 2015 at 9:31 Comment(1)
Is the number of arrows set, or are these being dynamically added?Thiazole
T
17

you could use something like:

.wrap {
  width: 100%;
  height: 30px;
  z-index:-2;white-space: nowrap;
  overflow:hidden;
}
.wrap div:first-child{margin-left:-2%;}
.progress {
  margin:0;
  margin-left:0.5%;
  height: 30px;
  width: 25%;
  position: relative;
  display: inline-block;
  text-align: center;
  line-height: 30px;
  transition: all 0.8s;
}
.progress:before,
.progress:after {
  content: "";
  position: absolute;
  transition: all 0.8s;
  z-index:-1;
}
.progress:before {
  height: 50%;
  width: 100%;
  top: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.2);
  -webkit-transform: skew(45deg);
  -moz-transform: skew(45deg);
  transform: skew(45deg);
}
.progress:after {
  height: 50%;
  width: 100%;
  top: 50%;
  left: 0;
  background: rgba(0, 0, 0, 0.2);
  -webkit-transform: skew(-45deg);
  -moz-transform: skew(-45deg);
  transform: skew(-45deg);
}
.progress:hover:before,
.progress:hover:after {
  background: tomato;
}
<div class="wrap">
  <div class="progress">
    simple
  </div>
  <div class="progress">
    as
  </div>
  <div class="progress">
    complex
  </div>
  <div class="progress">
    Web Development
  </div>
</div>

which is responsive to the width of the screen.

It makes use of the transform:skew property for the middle bars, and a small border hack for the two far elements. This results in the output shown below:

Result

enter image description here

NOTE

If you are creating these dynamically (and want them all along the same line), then you will need to alter the width stated in the first css rule (currently set to 23%).

Thiazole answered 20/4, 2015 at 10:2 Comment(0)
E
1

Another nice responsive implementation i made in 2023:

CSS:

<style>
ul.progressArrows {
    margin:0;
    padding:0;
    font-size: inherit;
}

ul.progressArrows > li {
    position:relative;
    list-style: none;
    vertical-align: middle;
    display: inline-block;
    margin: 0.25em -0.9em 0.25em 0;
    text-align: center;
}

ul.progressArrows > li:last-child {
    margin-right: 0;
}

ul.progressArrows > li:after {
    content: "";
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    position:absolute;
    display: block;
    color: #fff;
    filter: brightness(0) saturate(100%) invert(65%) sepia(80%) saturate(317%) hue-rotate(154deg) brightness(93%) contrast(87%); /* from: #5bc0de | https://angel-rs.github.io/css-color-filter-generator/ */
    background: url('data:image/svg+xml;utf8,<svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 55 100" fill="%23000000"><polygon points="55 0 0 .015 49.97 50.015 0 99.985 55 100 55 0"/></svg>') left center/contain no-repeat,
                url('data:image/svg+xml;utf8,<svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 55 100" fill="%23000000"><polygon points="5 100 0 100 0 0 5 0 5 0 55 50 5 100 5 100"/></svg>') right center/contain no-repeat,
                linear-gradient(90deg, rgba(255,255,255,0) 1em, rgba(0,0,0,1) 1em, rgba(0,0,0,1) calc(100% - 1em), rgba(255,255,255,0) calc(100% - 1em));
}

ul.progressArrows > li:hover:after {
    filter: brightness(0) saturate(100%) invert(63%) sepia(91%) saturate(1072%) hue-rotate(157deg) brightness(90%) contrast(84%); /* from: #31b0d5 | https://angel-rs.github.io/css-color-filter-generator/ */
}

ul.progressArrows > li > a {
    position: relative;
    z-index: 1;
    color: #fff;
    text-decoration: none;
    display: inline-block;
    padding: 0.2em;
    margin: 0 0.8em 0 1.2em;
    line-height: 1.5em;
    white-space: nowrap;
}
</style>

HTML:

<ul class="progressArrows">
    <li><a href="">Arrow</a></li>
    <li><a href="">Longer Arrow</a></li>
    <li><a href="">The longest Arrow of all</a></li>
</ul>

RESULT:

bar example

Elixir answered 8/7, 2023 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.