skip to Main Content

Supposed that I have the following SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="237" height="129" viewBox="0 0 237 129" fill="none">
  <path d="M228 1H9C4.58172 1 1 4.58172 1 9V91V104V127L20 111.483L228 112C232.418 112 236 108.418 236 104V9C236 4.58172 232.418 1 228 1Z" fill="#F6F6F6" />
  <path d="M1 104V9C1 4.58172 4.58172 1 9 1H228C232.418 1 236 4.58172 236 9V104C236 108.418 232.418 112 228 112L20 111.483L1 127V91" stroke="#E8E8E8" />
  <foreignObject x="15" y="0" width="200" height="130">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fringilla quam eu faci lisis mollis. </p>
  </foreignObject>
 </svg>

<svg xmlns="http://www.w3.org/2000/svg" width="235" height="86" viewBox="0 0 235 86" fill="none">
  <path d="M8 0H227C231.418 0 235 3.58172 235 8V50V63V86L216 70.4828L8 71C3.58173 71 0 67.4183 0 63V8C0 3.58172 3.58173 0 8 0Z" fill="#5DB075"/>
  <foreignObject x="15" y="0" width="200" height="80">
    <p style="color: white">Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
  </foreignObject>
</svg>

I was thinking to make the height dynamic based on text length.

For example the first SVG would be something like:

<svg xmlns="http://www.w3.org/2000/svg" width="237" height={50 + (27 * text.length / 27)} viewBox={`0 0 237 ${50 + (27 * text.length / 27)}`} fill="none">
  <path d="M228 1H9C4.58172 1 1 4.58172 1 9V91V104V127L20 111.483L228 112C232.418 112 236 108.418 236 104V9C236 4.58172 232.418 1 228 1Z" fill="#F6F6F6" />
  <path d="M1 104V9C1 4.58172 4.58172 1 9 1H228C232.418 1 236 4.58172 236 9V104C236 108.418 232.418 112 228 112L20 111.483L1 127V91" stroke="#E8E8E8" />
  <foreignObject x="15" y="15" width="150" height={20 + (27 * text.length / 27)}>
    <p>{text}</p>
  </foreignObject>
</svg>

And the second SVG would be something like:

<svg xmlns="http://www.w3.org/2000/svg" width="235" height={50 + (27 * text.length / 27)} viewBox={`0 0 237 ${50 + (27 * text.length / 27)}`} fill="none">
  <path d="M8 0H227C231.418 0 235 3.58172 235 8V50V63V86L216 70.4828L8 71C3.58173 71 0 67.4183 0 63V8C0 3.58172 3.58173 0 8 0Z" fill="#5DB075" />
  <foreignObject x="15" y="15" width="150" height={20 + (27 * text.length / 27)}>
    <p style="color: white">{text}</p>
  </foreignObject>
</svg>

Current problem with this approach is, the path D wasn’t manipulated to be reflecting the actual height.

For example in snippet if text was short would look something like:

<svg xmlns="http://www.w3.org/2000/svg" width="237" height="50" viewBox="0 0 237 50" fill="none">
  <path d="M228 1H9C4.58172 1 1 4.58172 1 9V91V104V127L20 111.483L228 112C232.418 112 236 108.418 236 104V9C236 4.58172 232.418 1 228 1Z" fill="#F6F6F6" />
  <path d="M1 104V9C1 4.58172 4.58172 1 9 1H228C232.418 1 236 4.58172 236 9V104C236 108.418 232.418 112 228 112L20 111.483L1 127V91" stroke="#E8E8E8" />
  <foreignObject x="15" y="0" width="200" height="130">
    <p>test </p>
  </foreignObject>
 </svg>

<svg xmlns="http://www.w3.org/2000/svg" width="235" height="50" viewBox="0 0 235 50" fill="none">
  <path d="M8 0H227C231.418 0 235 3.58172 235 8V50V63V86L216 70.4828L8 71C3.58173 71 0 67.4183 0 63V8C0 3.58172 3.58173 0 8 0Z" fill="#5DB075"/>
  <foreignObject x="15" y="0" width="200" height="80">
    <p style="color: white">test </p>
  </foreignObject>
</svg>

Is there any better way to update the SVG shape dynamically based on text length?

2

Answers


  1. So, here one solution to mimic the style in html/css. You can adjust the css to match your liking: colors and bubble shapes and so on…

    .buble {
      padding: 0;
      margin: 0.5rem 0;
      min-width: min-content;
      clear: both;
      hyphens: auto;
    }
    
    .recv {
      background: whitesmoke;
      border: 2px solid silver;
      border-radius: 0.5rem;
      padding: 0 1rem;
      float: left;
    }
    
    .recv.handle:after {
      content: "";
      background: whitesmoke;
      border: 2px solid silver;
      border-top: none;
      border-right: none;
      position: absolute;
      width: 1rem;
      height: 1rem;
      left: 1rem;
      z-index: 1;
      transform: skewY(-45deg) translate(0, -0.5rem);
    }
    
    .send {
      text-align: right;
      float: right;
      background: #99dd99;
      border: 2px solid green;
      border-radius: 0.5rem;
    }
    
    .send.handle:after {
      content: "";
      background: #99dd99;
      border: 2px solid green;
      border-top: none;
      border-left: none;
      position: absolute;
      height: 1rem;
      width: 1rem;
      z-index: 1;
      right: 1rem;
      transform: skewY(45deg) translate(0, -0.5rem);
    }
    
    p {
      padding: 0;
      margin: 0.25rem 0.5rem;
      position: relative;
      z-index: 2;
      min-height: 1rem;
    }
    
    #container {
      position: relative;
      width: 400px;
      margin: 0 auto;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Simple Chat using css</title>
    </head>
    
    <body>
      <div id="container">
        <div class="buble recv handle">
          <p>Received extra long message with handle and some content that should span to next line automatically if so.</p>
        </div>
    
        <div class="buble send">
          <p>Sent short message without handle</p>
        </div>
    
        <div class="buble recv">
          <p>Received message</p>
        </div>
    
        <div class="buble send handle">
          <p>Multilines <br />works nicely.<br />Long sent message with handle.</p>
        </div>
    
        <div class="buble recv handle">
          <p>Received message</p>
        </div>
    
        <div class="buble recv handle">
          <p>Received message</p>
        </div>
      </div>
    </body>
    
    </html>
    Login or Signup to reply.
  2. Standard HTML/CSS way:

    .container {
      display: flex;
      flex-direction: column;
      margin: 16px auto;
      padding: 0 16px;
      overflow: hidden;
      box-shadow: 0 0 0 100vw #fff;
      font-family: sans-serif;
    }
    
    .receive,
    .send {
      margin: 40px;
      width: 200px;
      height: auto;
      position: relative;
    }
    
    .receive {
      background-color: #F6F6F6;
      border-radius: 10px 10px 10px 0;
      border: 1px solid #E8E8E8;
    }
    
    .send {
      background-color: #5DB075;
      border-radius: 10px 10px 0 10px;
      color: white;
      align-self: flex-end;
    }
    
    .talktext {
      padding: 1em;
      text-align: left;
      line-height: 1.5em;
    }
    
    .talktext p {
      -webkit-margin-before: 0em;
      -webkit-margin-after: 0em;
    }
    
    .receive:after {
      content: ' ';
      position: absolute;
      background: #F6F6F6;
      border: 1px solid #E8E8E8;
      border-top: none;
      border-right: none;
      width: 1rem;
      height: 1rem;
      left: -1px;
      bottom: -18px;
      z-index: 1;
      transform: skewY(-45deg) translate(0, -0.5rem);
    }
    
    .send:after {
      content: ' ';
      position: absolute;
      width: 0;
      height: 0;
      left: auto;
      right: 0px;
      bottom: -20px;
      border: 12px solid;
      border-color: #5DB075 #5DB075 transparent transparent;
    }
    <div class="container">
      <div class="receive talktext">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fringilla quam eu faci lisis mollis.</p>
      </div>
    
      <div class="send talktext">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
      </div>
    
      <div class="receive talktext">
        <p>Lorem ipsum dolor sit amet</p>
      </div>
    
      <div class="send talktext">
        <p>Lorem ipsum dolor sit amet</p>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search