Home > Enterprise >  Add a horizontal line between elements with a rounded border-radius using before:/after:selectors
Add a horizontal line between elements with a rounded border-radius using before:/after:selectors

Time:11-18

Here's a fun CSS challenge: I want ol list items spaced horizontally across a 100% screen width (i.e. dynamic/flex), with a horizontal line of border-radius 2px connecting each list item without introducing html in between <li> items (introducing other html elements would be an accessibility violation as <ol> must only contain <li> children).

<ol >
  <li >One</li>
  <li >Two</li>
  <li >Three</li>
  <li >Four</li>
</ol>

How would I implement this?

Playground snippet: https://jsfiddle.net/L5to7rsj/19/

Starting CSS:

.list {
  list-style: none;
  padding-inline: 0;
  display: flex;
  width: 100%;
  justify-content: space-between;
}

.listItem {
  position: relative;
  padding: 1rem;
  border: 1px solid;
}

.listItem:not(:last-child):after {
  content: "";
  display: block;
  height: 4px;
  border-radius: 2px;
  background: blue;
  top: 50%;
  position: absolute;
  width: 100%;
}
<ol >
  <li >One</li>
  <li >Two</li>
  <li >Three</li>
  <li >Four</li>
</ol>

CodePudding user response:

You can get a solid blue line between the elements by drawing one as the background on a before pseudo element to the ol and having background of white on the li elements.

You can then 'paint over' the part touching each li element by using the li element's before and after pseudo elements with radial gradient backgrounds to give the rounded effect.

This snippet has the rounded ends touching the edge of each li element - if you wanted a little gap this would be possible by extending the pseudo elements, but this is not specified in the question.

.list {
  list-style: none;
  padding-inline: 0;
  display: flex;
  width: 100%;
  height: fit-content;
  justify-content: space-between;
  position: relative;
}

.list::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: -1;
  background-image: linear-gradient(white 0 calc(50% - 2px), blue calc(50% - 2px) calc(50%   2px), white calc(50%   2px) 100%);
  background-repeat: no-repeat;
}

.listItem {
  position: relative;
  padding: 1rem;
  border: 1px solid;
  background: white;
  box-sizing: border-box;
}

.listItem:not(:first-child)::before,
.listItem:not(:last-child)::after {
  content: "";
  position: absolute;
  height: 4px;
  width: 4px;
  top: calc(50% - 2px);
  z-index: -1;
}

.listItem:not(:first-child)::before {
  background-image: radial-gradient(blue 0 70%, transparent 70% 100%), linear-gradient(to right, transparent 0 50%, white 50% 100%);
  right: calc(100%   1px);
}

.listItem:not(:last-child)::after {
  background-image: radial-gradient(blue 0 70%, transparent 70% 100%), linear-gradient(to left, transparent 0 50%, white 50% 100%);
  left: calc(100%   1px);
}
<ol >
  <li >One</li>
  <li >Two</li>
  <li >Three</li>
  <li >Four</li>
</ol>

CodePudding user response:

You can add left: 150%; CSS property for .listItem class except for the last element as following example:

.list {
  list-style: none;
  padding-inline: 0;
  display: flex;
  width: 100%;
  justify-content: space-between;
}

.listItem {
  position: relative;
  padding: 1rem;
  border: 1px solid;
}

.listItem:not(:last-child):after {
  content: "";
  display: block;
  height: 4px;
  border-radius: 2px;
  background: blue;
  top: 50%;
  left: 150%;
  position: absolute;
  width: 100%;
}
<ol >
  <li >One</li>
  <li >Two</li>
  <li >Three</li>
  <li >Four</li>
</ol>

  •  Tags:  
  • css
  • Related