Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a right outer curved layer for paragraph with CSS

Tags:

html

css

I am trying to make a list of paragraphs, and one of them should be selected, just like the image below, but it seems I just cannot succeed.

enter image description here

I have tried something at: http://jsfiddle.net/bmj2j2wd/ but the end just just does not curve the way I would like it to... ie outwards, not inwards.

This is the css from there:

.active{
    border:2px solid dodgerblue;
    border-bottom:0;
    width:80px;
    height:32px;
    margin:10px;
    position:relative;
    border-radius:16px 16px 0 0;
}
.active:after,
.active:before{
    content:'';
    width:80px;
    height:32px;
    border:2px solid dodgerblue;
    position:absolute;
    bottom:-8px;
    border-top:0;
}
.active:after{
    border-left:0;
    border-radius:0 0 16px 0;
    down:-16px;
}
.active:before{
    border-right:0;
    border-radius:0 0 0 16px;
    up:-16px;
}

but it looks totally not right.

Very important would be that the two right lines after the curvature would go all the way up and down till the top and bottom of the page.

So, I'd like to ask for some help from the community in order to get this working.

like image 330
Ferenc Deak Avatar asked Oct 24 '17 09:10

Ferenc Deak


4 Answers

You can basically use :before and :after to create a box on top and a box on bottom of your active <p> element (p.active). With these two boxes you can change the direction of the border. The following shows an example with a dynamic length based on the elements (Code on JSFiddle):

See the following solution (the original answer before edit):

.container :not(.active) {
  border-right:1px solid dodgerblue;
  margin:0;
  padding:10px 10px 10px 20px;
  width:72px;
}
.active {
  border:1px solid dodgerblue;
  border-radius:5px 0 0 5px;
  border-right:0;
  height:32px;
  line-height:32px;
  margin:10px;
  padding-left:10px;
  position:relative;
  width:80px;
}
.active:after, .active:before {
  border-right:1px solid dodgerblue;
  content:'';
  height:32px;
  right:-2px;
  position:absolute;
  width:80px;
}
.active:after {
  border-bottom-right-radius: 5px;
  transform:translateY(-100%);
}
.active:before {
  border-top-right-radius:5px;
  transform:translateY(100%);
}
<div class="container">
  <p>item1</p>
  <p>item2</p>
  <p>item3</p>
  <p class="active">item4</p>
  <p>item5</p>
  <p>item6</p>
</div>

You want to set vertical border on the full height of the page. This is a very difficult thing but you can use the following solution using a container which hides the overflow (the too long borders) (Code on JSFiddle):

body, html {
  margin:0;
  padding:0;
}
.container {
  height:100vh;
  margin:0;
  overflow:hidden;
  padding:0;
}
p {
  display:block;
  height:32px;
  line-height:32px;
  margin:10px;
  padding:0;
  padding-left:10px;
}
.active {
  border:1px solid dodgerblue;
  border-radius:5px 0 0 5px;
  border-right:0;
  position:relative;
  width:80px;
}
.active:after, .active:before {
  border-right:1px solid dodgerblue;
  content:'';
  height:100vh; /** same height like container */
  position:absolute;
  right:-2px;
  width:80px;
}
.active:after {
  border-bottom-right-radius:5px;
  transform:translateY(-100%);
}
.active:before {
  border-top-right-radius:5px;
  transform:translateY(32px);
}
<div class="container">
  <p>item1</p>
  <p>item2</p>
  <p>item3</p>
  <p class="active">item4</p>
  <p>item5</p>
  <p>item6</p>
  <p>item7</p>
</div>

An additional, maybe useful, example using :hover instead of .active to set the active element. This is useful for tests too (Code on JSFiddle):

body, html {
  margin:0;
  padding:0;
}
.container {
  height:80vh;
  margin:0;
  overflow:hidden;
  padding:0;
}
p {
  border:1px solid transparent;
  display:block;
  height:32px;
  line-height:32px;
  margin:10px;
  padding:0;
  padding-left:10px;
}
p:hover {
  border:1px solid dodgerblue;
  border-radius:5px 0 0 5px;
  border-right:0;
  position:relative;
  width:80px;
}
p:hover:before, p:hover:after {
  border-right:1px solid dodgerblue;
  content:'';
  height:100vh;  /** same height like container */
  position:absolute;
  right:-2px;
  width:80px;
  z-index:-1;
}
p:hover:after {
  border-bottom-right-radius:5px;
  transform:translateY(-100%);
}
p:hover:before {
  border-top-right-radius:5px;
  transform:translateY(32px);
}
<div class="container">
  <p>item1</p>
  <p>item2</p>
  <p>item3</p>
  <p class="active">item4</p>
  <p>item5</p>
  <p>item6</p>
  <p>item7</p>
</div>
like image 158
Sebastian Brosch Avatar answered Nov 02 '22 07:11

Sebastian Brosch


You could use :after and :before pseudo elements and add border-radius.

.active {
  padding: 15px;
  margin: 60px;
  border: 1px solid blue;
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
  padding-right: 0;
  display: inline-block;
  border-right: none;
  position: relative;
}
.active:before,
.active:after {
  content: '';
  position: absolute;
  width: 30px;
  height: 40px;
}
.active:before {
  border-right: 1px solid blue;
  border-bottom: 1px solid blue;
  border-bottom-right-radius: 50%;
  right: -30px;
  top: 0;
  transform: translateY(-100%);
}
.active:after {
  border-right: 1px solid blue;
  border-top: 1px solid blue;
  border-top-right-radius: 50%;
  right: -30px;
  bottom: 0;
  transform: translateY(100%);
}
<div class="active">Some selection</div>
like image 32
Nenad Vracar Avatar answered Nov 02 '22 07:11

Nenad Vracar


Another option that uses span elements for the curved lines, instead of pseudoelements

fiddle

body {
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.active {
  border: 1px solid red;
  border-right: 0;
  width: 80px;
  height: 32px;
  position: relative;
  border-radius: 5px 0 0 5px;
  display: flex;
  align-items: center;
  padding-left: 1em;
}

.curvy {
  flex: 1;
  width: 80px;
  margin-left: 30px;
  border: 1px solid red;
  border-left: 0;
  border-top: 0;
  border-radius: 0 0 5px 0;
  margin-bottom: -1px;
}

.active+.curvy {
  margin-bottom: 0;
  margin-top: -1px;
  border-top: 1px solid red;
  border-radius: 0 5px 0 0;
  border-bottom: 0;
}
<span class="curvy"></span>
<div class="active">hi</div>
<span class="curvy"></span>
like image 2
sol Avatar answered Nov 02 '22 07:11

sol


While the other two works but it was not all the way up & down. To make the line longer/shorter, change the height & top value.

height: 50vh;

top: calc(-50vh - 1px);

.active{
    border:1px solid red;
    border-right:0;
    width:80px;
    height:32px;
    margin: 150px auto 0;
    position:relative;
    border-radius: 10px 0px 0 10px;
    padding: 10px;
}
.active:after,
.active:before {
  content: '';
  position: absolute;
  width: 20px;
  height: 50vh;
}
.active:before {
  top: calc(-50vh - 1px);
  right: -20px;
  border-bottom-right-radius: 10px;
  border: 1px solid red;
  border-left: none;
  border-top: none;
}
.active:after{
  bottom: calc(-50vh - 1px);
  right: -20px;
  border-top-right-radius: 10px;
  border: 1px solid red;
  border-left: none;
  border-bottom: none;
}
<div class="active">hi</div>
like image 1
slashsharp Avatar answered Nov 02 '22 05:11

slashsharp