Search code examples
htmlcsscss-shapescurve

transparent shape with arrow in upper corner


Please see the image below.

Desired result

I want to add an arrow to the top right of a div which I am treating as editable input box. Please help me how I can achieve this using CSS. I cannot use a SVG since I need this as a div to show emoticons as images over it.

<div placeholder="Your message" id="Message">
...
</div>

Solution

  • You can do it like in the below snippet. The method used to achieve the shape is as given below:

    • The main div element only has a top, bottom and left border. The right border is nullified because the element and its arrows needs to be transparent. With a transparent arrow, if a right border is present that would also get displayed.
    • The arrow on the right is achieved using a skewed element placed with respect to the right edge of the shape.
    • The right border of the shape is achieved by using another pseudo-element whose size is the same as the height of the whole container - height of the arrow pseudo-element. This element is positioned with respect to the bottom right of the shape.

    You can adjust the height and border-radius as required. I have set the positioning such that even a change in height/width of parent would not affect it.

    div.shape {
      position: relative;
      width: 300px;
      height: 100px;
      padding: 4px;
      margin-top: 20px;
      border: 2px solid gray;
      border-right: none; /* not required as the shape needs to be transparent */
      border-radius: 8px; /* not required as the right border is done through pseudo element */
      border-top-right-radius: 0px;
      border-bottom-right-radius: 0px;
    }
    div.shape:before {
      position: absolute;
      content: '';
      top: -2px; /* equal to border top of parent - no need to change*/
      right: -6px; /* for positioning - no need to change*/
      height: 15%; /* should be changed depending on height of arrow */
      width: 10%; /* should be changed depending on width of arrow */
      border-top: 2px solid gray;
      border-right: 3px solid gray; /* thicker border because skew makes it thin */
    
      /* to achieve the arrow like shape */ 
      -webkit-transform-origin: bottom right;
      -webkit-transform: skew(-45deg);
      -moz-transform: skew(-45deg);
      transform: skew(-45deg);
    }
    div.shape:after {
      position: absolute;
      content: '';
      right: -6px; /* for positioning - no need to change*/
      height: 85%; /* height of parent - height of arrow */
      width: 2%; /* no need to change */
      bottom: -2px; /* equal to border bottom of parent - no need to change*/
      border-right: 2px solid gray;
      border-bottom: 2px solid gray;
      border-bottom-right-radius: 8px; /* for producing curve on bottom right */
    }
    
    /* Just for demo */
    
    body {
      background: -webkit-linear-gradient(0deg, crimson, indianred, purple);
      background: -moz-linear-gradient(90deg, crimson, indianred, purple);
      background: linear-gradient(90deg, crimson, indianred, purple);
    }
    <div class="shape">
      Lorem Ipsum Dolor Sit Amet...
    </div>


    The arrow can be added to the left side by changing the positioning attributes and the skew direction (from positive angle to negative angle) like in the below snippet.

    div.shape {
      position: relative;
      width: 300px;
      height: 100px;
      padding: 4px;
      margin-top: 20px;
      margin-left: 20px;
      border: 2px solid gray;
      border-left: none; /* not required as the shape needs to be transparent */
      border-radius: 8px; /* not required as the right border is done through pseudo element */
      border-top-left-radius: 0px;
      border-bottom-left-radius: 0px;
    }
    div.shape:before {
      position: absolute;
      content: '';
      top: -2px; /* equal to border top of parent - no need to change*/
      left: -6px; /* for positioning - no need to change*/
      height: 15%; /* should be changed depending on height of arrow */
      width: 10%; /* should be changed depending on width of arrow */
      border-top: 2px solid gray;
      border-left: 3px solid gray; /* thicker border because skew makes it thin */
    
      /* to achieve the arrow like shape */ 
      -webkit-transform-origin: bottom right;
      -webkit-transform: skew(45deg);
      -moz-transform: skew(45deg);
      transform: skew(45deg);
    }
    div.shape:after {
      position: absolute;
      content: '';
      left: -6px; /* for positioning - no need to change*/
      height: 85%; /* height of parent - height of arrow */
      width: 2%; /* no need to change */
      bottom: -2px; /* equal to border bottom of parent - no need to change*/
      border-left: 2px solid gray;
      border-bottom: 2px solid gray;
      border-bottom-left-radius: 8px; /* for producing curve on bottom right */
    }
    
    /* Just for demo */
    
    body {
      background: -webkit-linear-gradient(0deg, crimson, indianred, purple);
      background: -moz-linear-gradient(90deg, crimson, indianred, purple);
      background: linear-gradient(90deg, crimson, indianred, purple);
    }
    <div class="shape">
      Lorem Ipsum Dolor Sit Amet...
    </div>