htmlcssarrows

Creating road sign style outline for a tag cloud


I would like to create a tag cloud display with a slightly rounded arrow pointing right as the outline for each tag using just CSS3. My current effort is shown below.

body,html{margin:0;padding:0;}
  body
  {
   padding:1em;
   background-color:#23232f;
   font-family:arial;
  }
  div
  {
   display:inline-block;
   position:relative;
   margin-right:2em;
   margin-bottom:1em;
  }

  

  .tag
  {
   display:inline-block;
   position:relative;
   text-align:center;
   
   height:1.5em;
   z-index:100;
   background-color:transparent;
   color:white;
  }

  .tag > span
  {
   position:relative;
   display:flex; 
   align-items:center;
   justify-content:center;
   height:1.5em;
   border-radius:2px;
   border-top-right-radius:0;
   border-bottom-right-radius:0;
   padding-left:1em;
   padding-right:1em;
   border:1px solid silver;
   border-right-style:none;
   
  }

  .tag > span::after
  {
   content:' ';
   position:absolute;
   top:-0.17em;
   left:calc(100% - 1px);
   width:1.25em;
   height:1.25em;
   border:1px solid silver;
   border-left-style:none;
   
   border-bottom-style:none;
   border-radius:4px;
   transform:rotate(45deg);
   transform-origin:top left;
   z-index:-10;
  }
<div class='tag'>
 <span>Stack Exchange</span>
</div>
<div class='tag'>
 <span>Ask Ubuntu</span>
</div>
<div class='tag'>
 <span>Stack Overflow</span>
</div>

While this works I have got some of the things right by pure trial and error. In particular it is not clear to me

Pure geometry suggests that in order to get a height of 1.5em the sides of the pseudo element should be 1.067em. Is this caused by

Or more generally is there quite simply a better way to do this - bearing in mind that I want the result to always be responsive.


Solution

  • To have more accurate result you need to use top:-1px because you have 1px of border on the main element and position:absolute consider the padding-box then for the size you have to use calc(1.5em/1.41) which is the height of the main element divided by sqrt(2). You can also keep left:100%

    body {
      padding: 1em;
      background-color: #23232f;
      font-family: arial;
    }
    
    div {
      display: inline-block;
      position: relative;
      margin-right: 2em;
      margin-bottom: 1em;
    }
    
    .tag {
      display: inline-block;
      position: relative;
      text-align: center;
      height: 1.5em;
      z-index: 100;
      background-color: transparent;
      color: white;
    }
    
    .tag>span {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 1.5em;
      border-radius: 2px;
      border-top-right-radius: 0;
      border-bottom-right-radius: 0;
      padding-left: 1em;
      padding-right: 1em;
      border: 1px solid silver;
      border-right-style: none;
    }
    
    .tag>span::after {
      content: ' ';
      position: absolute;
      top: -1px; /* equal to border width */
      left: 100%;
      width: calc(1.5em/1.41);
      height: calc(1.5em/1.41);
      border: 1px solid silver;
      border-left-style: none;
      border-bottom-style: none;
      border-radius: 0 4px 0 0;
      transform: rotate(45deg);
      transform-origin: top left;
      z-index: -10;
    }
    <div class='tag'>
      <span>Stack Exchange</span>
    </div>
    <div class='tag'>
      <span>Ask Ubuntu</span>
    </div>
    <div class='tag'>
      <span>Stack Overflow</span>
    </div>