CSS - Vertical line between bullets in an unordered list

39,707

Solution 1

I doubt that this is achievable using just borders and "fiddling with margins" as others have suggested, at least I've had no luck in doing so.

This solution uses CSS-generated content (:before and :after) to draw bullets and lines. It allows for a high degree of customization and it keeps the markup clean, but note the browser support.

JSFiddle (scroll through CSS until the /* BORDERS AND BULLETS */ comment)

ul.experiences li {
    position:relative; /* so that pseudoelements are positioned relatively to their "li"s*/
    /* use padding-bottom instead of margin-bottom.*/ 
    margin-bottom: 0; /* This overrides previously specified margin-bottom */
    padding-bottom: 2.5em;
}

ul.experiences li:after {
    /* bullets */
    content: url('http://upload.wikimedia.org/wikipedia/commons/thumb/3/30/RedDisc.svg/20px-RedDisc.svg.png');
    position: absolute;
    left: -26px; /*adjust manually*/
    top: 0px;
}

ul.experiences li:before {
    /* lines */
    content:"";
    position: absolute;
    left: -16px; /* adjust manually */
    border-left: 1px solid black;
    height: 100%;
    width: 1px;
}

ul.experiences li:first-child:before {
   /* first li's line */
   top: 6px; /* moves the line down so that it disappears under the bullet. Adjust manually */
}

ul.experiences li:last-child:before {
    /* last li's line */
   height: 6px; /* shorten the line so it goes only up to the bullet. Is equal to first-child:before's top */
}

NOTE: if the line's border-color has an alpha-channel specified, the overlap between first and second elements' borders will be noticeable.

Solution 2

Since there aren't many good answers here, I figured I'd add my solution:

I take advantage of position relative and include a white mask on the last item to hide the overflow. Works in mobile view and variation of the item heights.

example of line through bullet points

HTML

<div class="list-wrapper">

    <div class="red-line"></div>

    <div class="list-item-wrapper">
        <div class="list-bullet">1</div>
        <div class="list-item">
            <div class="list-title">ITEM</div>
            <div class="list-text">Text</div>
        </div>
    </div>

    <div class="list-item-wrapper">
        <div class="list-bullet">2</div>
        <div class="list-item">
            <div class="list-title">ITEM</div>
            <div class="list-text">Text</div>
        </div>
    </div>

    <div class="list-item-wrapper">
        <div class="list-bullet">3</div>
        <div class="list-item">
            <div class="list-title">ITEM</div>
            <div class="list-text">Text</div>
        </div>
        <div class="white-line"></div>
    </div>

</div>

CSS

.list-wrapper {
  position:relative;
}
.list-item-wrapper {
  margin-top:10px;
  position:relative;
}
.list-bullet {
  float:left;
  margin-right:20px;
  background:#FF4949;
  height:30px;
  width:30px;
  line-height:30px;
  border-radius:100px;
  font-weight:700;
  color:white;
  text-align:center;
}
.list-item {
  display:table-row;
  vertical-align:middle;
}
.list-title {
    font-weight:700;
}
.list-text {
    font-weight:400;
}
.red-line {
  background:#FF4949;
  z-index:-1;
  width:1px;
  height:100%;
  position:absolute;
  left:15px;
}
.white-line {
  background:#FFF;
  z-index:-1;
  top:0px;
  width:1px;
  height:100%;
  position:absolute;
  left:15px;
}

DEMO http://jsfiddle.net/cfzsgkyn/

Solution 3

Probably a bit old now but here is a way you can do this. It requires a bit more markup to create styles and control the heights of elements (I used spans but you can use tags ):

ol,
ul {
  list-style: none;
}
li {
  display: flex;
  flex-flow: row;
  min-height: 100px;
  position: relative;
}
span.number {
  margin-right: 100px;
  text-align: center;
  width: 1em;
  height: 1em;
  background-color: red;
  border-radius: 50%;
  z-index: 1;
}
span.line {
  position: absolute;
  height: 100%;
  border: solid black 0.1em;
  top: 0.5em;
  left: 0.45em;
}
li:last-child span.line {
  display: none;
}
}
span.blob {}
<ul>
  <li><span class='line'></span><span class='number'>1</span>
    <div class='blob'>Hello</div>
  </li>
  <li><span class='number'>2</span>
    <div class='blob'>Goodbye</div>
  </li>
</ul>

http://jsfiddle.net/efava0je/

Share:
39,707
transbetacism
Author by

transbetacism

Updated on November 01, 2020

Comments

  • transbetacism
    transbetacism over 3 years

    How would I go about drawing a vertical line between the bullets in an unordered list, like so:

    enter image description here

    Notice that the line stops at the last list bullet. I'm using list-style:none; and images as bullets. The HTML looks like this:

    <ul class="experiences">
    
      <!-- Experience -->
      <li class="green">
        <div class="where">New York Times</div>
        <h3 class="what green">Senior Online Editor</h3>
        <div class="when">2012 - Present</div>
    
        <p class="description">Jelly-o pie chocolate cake...</p>
       </li>
    
       ...
    

    CSS code as requested:

    /* Experiences */
    ul.experiences {
        padding-left: 15px;
        margin-top: -1px;
    }
    ul.experiences li {
        padding-left: 33px;
        margin-bottom: 2.5em;
        list-style: none;
        background: url('../img/misc/list-bullet-darkgray.png') no-repeat;
    }
    ul.experiences li.green {
        background: url('../img/misc/list-bullet-green.png') no-repeat;
    }
    ul.experiences li.blue {
        background: url('../img/misc/list-bullet-blue.png') no-repeat;
    }
    ul.experiences li.pink {
        background: url('../img/misc/list-bullet-pink.png') no-repeat;
    }
    .where {
        font-size: 1.2857em; /* 18/16 -> 18px */
        font-weight: 300;
        display: inline;
        margin-right: 0.5em;
    }
    .what {
        font-size: 0.75em; /* 12/16 -> 12px */
        font-weight: 700;
        text-transform: uppercase;
        color: #fff;
        background-color: #444444;
        display: inline-block;
        padding: 0 12px;
        margin: -5px 0.5em 0 0 !important;
        -webkit-border-radius: 3px;
        -moz-border-radius: 3px;
        border-radius: 3px;
    }
    .what.green {
        background-color: #c4df9b;
    }
    .what.blue {
        background-color: #6dcff6;
    }
    .what.pink {
        background-color: #f06eaa;
    }
    .when {
        float: right;
        color: #b9b9b9;
        font-style: italic;
    }
    .description {
        display: block;
        margin-top: 0.5em;
    }
    
    • Sumurai8
      Sumurai8 almost 11 years
      I believe you can use .experiences li:last-child to -not- display a left-border while you can use .experiences li to display a border on the left side of the rest
    • sbichenko
      sbichenko almost 11 years
      @Sumurai8 This way, the border won't go down to the last bullet.
    • sbichenko
      sbichenko almost 11 years
      So, did you solve this problem? If you used a solution provided on this page, consider marking it as an accepted answer.
    • transbetacism
      transbetacism over 10 years
      Sorry for the delay, I haven't had time to look at this for a while. See my comment of your answer.
  • transbetacism
    transbetacism almost 11 years
    Currently that solution looks like this: s18.postimg.org/jok2ljwzd/line.png As you can see, there are a couple of issues. The white space between the list items might be possible to fix by using padding instead of margin, but I'm not sure if that's optimal... Also, I don't want the line to extend even one pixel above the first bullet or below the last one...
  • 1321941
    1321941 almost 11 years
    @graphic_dev then you need to play around with paddings, margins and offsetting the background image of the bullet point so it all lines up. Its fiddly but using a border is the best solution.
  • transbetacism
    transbetacism over 10 years
    I don't think this will work. You're using a negative bottom-margin to make sure that the line doesn't extend below the last bullet, but there is no way of knowing what the height of the last li item will be. See this example where I have two lines of content for the last li item: jsfiddle.net/N9svF/3
  • transbetacism
    transbetacism over 10 years
    This seems to be working great - except for IE8 which shows the line for the last item as well... Is there any way around this? I will accept this answer if I get it to work with IE8. Look at this example with IE8: graphic-dev.com/stuff/vcard
  • sbichenko
    sbichenko over 10 years
    I haven't found a way to support IE8 here purely with CSS. The best workaround is to use jQuery (since you'll probably use it on the page anyway). It has a :last-child selector, which can be used to assign a specific class to the last child, e.g. experiences-last-li. Then change the last rule's selector from ul.experiences li:last-child:before to ul.experiences li.experiences-last-li:before. Don't forget to add a comment in the source explaining the need for this workaround!
  • transbetacism
    transbetacism over 10 years
    EDIT: Works like a charm! Why didn't I think of that...? :) Thanks a lot!
  • Renee Rose-Perry
    Renee Rose-Perry over 10 years
    THIS WORKS. However, you have to add a negative left margin to the list items. Like this: li {margin-left:-5px;}
  • Uyghur Lives Matter
    Uyghur Lives Matter over 8 years
    You should include your css from the jsfiddle.
  • Max
    Max over 8 years
    Thanks dude. It saved me half working day. Cheers :+1: