<main>
  <header>
      <slider min="1" max="4" step="1" label="Segments" v-model.number="segments"></slider>
      <slider min="1" max="5" step="0.05" label="Size" v-model.number="size"></slider>
  </header>
  <section>
    <div>
      <h3>CSS</h3>
      <div :style="'--fontsize: calc('+size+' * 1vmin)'">
        <template v-for="n in segments">
          <css-arrow :index="n-1" :segments="segments"></css-arrow>
        </template>
      </div>
      <ul>
        <li>template: simple</li>
        <li>styles: more</li>
        <li>resize: glitchy</li>
      </ul>
    </div>
    <div class="vs">vs.</div>
    <div>
      <h3>SVG</h3>
      <div :style="'--fontsize: calc('+size+' * 1vmin)'">
        <template v-for="n in segments">
          <svg-arrow :index="n-1" :segments="segments"></svg-arrow>
        </template>
      </div>
      <ul>
        <li>template: complex</li>
        <li>styles: less</li>
        <li>resize: buttery</li>
      </ul>
    </div>
  </section>
</main>
:root {
  --color: #08a6e6;
  --accent: #9c63c7;
  --fg: #573659;
  --bg: #f0f2f0;
  --fontsize: 2vmin; // example size, set appropriately
}

@media (orientation: portrait) {
  :root {
    --fontsize: 2vmax; // example size, set appropriately 
  }
}

.css-arrow {
  position: relative;
  display: flex;
  align-items: center;
  height: 1em;
  padding: .2em 0;
  font-size: calc(var(--fontsize) * 2);
  transition: font-size 300ms linear;
  span + span {
    margin-left: .15em;
  }
  &__leg,
  &__stop {
    box-sizing: border-box;
    position: relative;
    display: block;
    border-radius: 1em;
    opacity: .4;
  }
  &__stop {
    width: .75em;
    height: .75em;
    border: .2em solid var(--color);
    + .css-arrow__leg--last {
      width: 1em;
    }
  }
  &__leg {
    width: .85em;
    height: .2em;
    background: var(--color);
    &--last {
      width: 3em;
      &::before,
      &::after {
        content: '';
        position: absolute;
        right: 0;
        background: var(--color);
        width: .7em;
        height: .2em;
        border-radius: 1em;
      }
      &::before {
        top: 50%;
        transform: translate(0, -.15em) rotate(-45deg); 
        transform-origin: 100% 50%;
      }
      &::after {
        top: 50%;
        transform: translate(0, -.05em) rotate(45deg); 
        transform-origin: 100% 50%;
      }
    }
  }
  &--active {
    opacity: 1;
  }
}

.svg-arrow {
  display: flex;
  padding: .2em 0;
  font-size: calc(var(--fontsize) * 2);
  transition: font-size 300ms linear;
  svg {
    height: 1em;
    opacity: .4;
    &.svg-arrow--active {
      opacity: 1;
    }
    > * {
      stroke: var(--color);
      stroke-width: 10;
      stroke-linecap: round;
      stroke-linejoin: round;
      fill: transparent;
    }
  }
  &--summary {
    font-size: .7em;
    svg {
      opacity: 1;
      > * {
        stroke: var(--color);
      }
    }
  }
}











// layout & stuff - has nothing to do with the arrows
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  font-family: sans-serif;
  font-size: var(--fontsize);
  background: var(--bg);
  color: var(--fg);
}
main {
  flex: 1;
  display: flex;
  flex-direction: column;
}
header {
  display: flex;
  justify-content: space-around;
  padding: 2em;
  font-size: calc(var(--fontsize) * 2);
  text-align: center;
  background: var(--accent);
  color: #fff;
}
section {
  flex: 1;
  padding: 2em;
  display: flex;
  justify-content: space-around;
  align-items: center;
  > div {
    padding: 2em;
  }
}
ul, ol {
  margin: 0;
  padding: 0 0 0 2em;
}
li {
  padding: .3em 0;
  white-space: nowrap;
}
h3 {
  border-bottom: .2em solid;
  margin: 0 0 .5em 0;
}
h4 {
  margin: 0;
}
.vs {
  flex: none;
  background: #fff;
  border-radius: 50%;
}

input {
  font-size: inherit;
}

// range slider
input[type="range"] {
  appearance: none;
  outline: none;
  padding: 0;
  border: 0;
  width: 25vmin;
  height: .25em;
  border-radius: 1em;
  cursor: pointer;
  // MOZILLA
  &::-moz-range-track {
    appearance: none;
    background: #fff;
    outline: none;
  }
  &::-moz-focus-outer {
    border: 0;
  }
  &::-moz-range-thumb {
    appearance: none;
    width: 1em;
    height: 1em;
    border: none;
    box-shadow: 0 0 0 .2em var(--accent);
    border-radius: 1em;
    background: #fff;
    transform: scale(.7);
    transition: .3s ease-out;
  }
  &::-moz-range-thumb:focus,
  &::-moz-range-thumb:active {
    appearance: none;
    transform: scale(1.5);
  }
  // BLINK/WEBKIT
  &::-webkit-slider-thumb {
    appearance: none;
    width: 1em;
    height: 1em;
    border: none;
    box-shadow: 0 0 0 .2em var(--accent);
    border-radius: 1em;
    background: #fff;
    transform: scale(.8);
    transition: .3s ease-out;
  }
  &::-webkit-slider-thumb:focus,
  &::-webkit-slider-thumb:active {
    appearance: none;
    transform: scale(1.1);
  }
}
View Compiled
Vue.component('css-arrow', {
  template: `
    <span class="css-arrow">
      <template v-for="n in segments">
          <span class="css-arrow__leg" :class="segmentClasses(n)"></span>
          <span class="css-arrow__stop" v-if="showStop(n)"></span>
      </template>
    </span>
  `,
  props: [
    'index',
    'segments'
  ],
  methods: {
    isActive: function(n){
      return n-1 === this.index
    },
    isLast: function(n){
      return n === this.segments
    },
    showStop: function(n) {
      return n < this.segments
    },
    segmentClasses: function(n) {
      let classes = []
      if(this.isActive(n)) {
        classes.push('css-arrow--active')
      }
      if(this.isLast(n)) {
        classes.push('css-arrow__leg--last')
      }
      return classes.join(' ')
    }
  }
})

Vue.component('svg-arrow', {
  template: `
    <span class="svg-arrow">
        <template v-if="segments == 1">
            <svg viewBox="0 0 150 50" :class="segmentClasses(1)">
                <line x1="5" y1="25" x2="140" y2="25"></line>
                <polyline points="125 7 143 25 125 43"></polyline>
            </svg>
        </template>
        <template v-else v-for="n in segments">
            <svg viewBox="0 0 50 50" :class="segmentClasses(n)">
                <line x1="7" y1="25" x2="43" y2="25"></line>
                <polyline points="28 7 43 25 28 43" v-if="isLast(n)"></polyline>
            </svg>
            <svg viewBox="0 0 50 50" v-if="showStop(n)">
                <circle cx="25" cy="25" r="16"></circle>
            </svg>
        </template>
    </span>
  `,
  props: [
    'index',
    'segments'
  ],
  methods: {
    isActive: function(n){
      return n-1 === this.index
    },
    isLast: function(n){
      return n === this.segments
    },
    showStop: function(n) {
      return n < this.segments
    },
    segmentClasses: function(n) {
      if(this.isActive(n)) {
        return 'svg-arrow--active'
      }
    }
  }
})

Vue.component('slider', {
  template: `
    <h4>
      {{label}} <br />
      <input type="range" :min="min" :max="max" :step="step" :value="value"
        @input="update($event.target.value)" />
    </h4>
  `,
  props: [
    'label',
    'min',
    'max',
    'step',
    'value'
  ],
  methods: {
    update: function (value) {
      this.$emit('input', value)
    }
  }
})

let vm = new Vue({
  el: 'main',
  data: {
    segments: 3,
    size: 3
  }
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/vue@2