Search code examples
htmlcsswkhtmltopdf

Is there a way to decorate line ends with a wedge/triangle using CSS?


I am working on a HTML/CSS template for invoices that get converted to pdf using wkhtmltopdf. Part of the design is an element that looks the following way:

enter image description here

The text inside the element can be of variable length. The logic behind the element is fairly simple: whenever there is a line-break present decorate the end of the line with a wedge. I've added padding to each line using Matthew Pennell's Triple Element Method as featured on css-tricks.com. I've adjusted it according to my needs:

.padded-multiline {
    line-height: 1.4;
    padding: 0.005in 0;
    border-left: 0.16in solid #E7E7E9;
}
.padded-multiline p {
    background-color: #E7E7E9;
    padding: 0.02in 0;
    display: inline;
    margin: 0;
}
.padded-multiline p span {
    position: relative;
    left: -0.08in;
}

The problem is that I am not sure how to decorate the lines with the wedges. I would like a CSS solution but I'm not sure this can actually be achieved. Were the text single line I could fairly easily add a grey CSS triangle after the element. Or I could add a background image that would consist of a triangle on a white background which would achieve the same effect. But since the element is multiline I am running out of ideas.

Using background-repeat: repeat-y on the nested elements doesn't seem to work the way I would expect as it only adds the background to the last line it. I am aware that there is a ::first-line pseudo-selector but from what I understand there's no ::nth-line or other quantifiers of the same type.

At the moment I think the only viable solution might be using JavaScript to break the text into individual elements and treat them as multiple single-line elements rather than a multiline element. But I wanted to avoid using JavaScript as that adds more overhead to the PDF generation and also feels kind of hacky to me.

Any ideas?

Note:

wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine.


Solution

  • If we consider the fact that you will not manually insert line-break then only the last line will not be filled until the end and all the previous one will be. We can then consider the last edge alone and the other ones together.

    Here is an idea:

    p {
     line-height:20px;
     padding:0 30px;
     background:
      linear-gradient(to top left,#fff 49%,transparent 50%) top right/20px 20px repeat-y,
      grey;
      overflow:hidden;
    }
    span {
      position:relative;
      display:inline-block;
      vertical-align:bottom;
    }
    span:before {
      content:"";
      position:absolute;
      left:30px; /*equal to padding*/
      bottom:0px;
      height:20px; /*equal to line-height*/
      background:
        linear-gradient(to top left,#fff 49%,grey 50%) top left/20px 20px no-repeat,
        #fff;
      right:-100vw;
    }
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus ipsum, posuere a tincidunt non, consectetur et mi. Sed congue ornare lorem, et placerat velit tempus nec. Phasellus fringilla eleifend vestibulum. Nunc lobortis ipsum a nisi dignissim sollicitudin. Ut elit leo, ultrices mollis metus non,<span></span> </p>

    In case you will need some line break, then don't use <br> but use many p tags:

    p {
     line-height:20px;
     padding:0 30px;
     background:
      linear-gradient(to top left,#fff 49%,transparent 50%) top right/20px 20px repeat-y,
      grey;
      overflow:hidden;
      margin:0;
    }
    span {
      position:relative;
      display:inline-block;
      vertical-align:bottom;
    }
    span:before {
      content:"";
      position:absolute;
      left:30px; /*equal to padding*/
      bottom:0px;
      height:20px; /*equal to line-height*/
      background:
        linear-gradient(to top left,#fff 49%,grey 50%) top left/20px 20px no-repeat,
        #fff;
      right:-100vw;
    }
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus ipsum, posuere a tincidunt non,  Ut elit leo, ultrices mollis metus non,<span></span> </p>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus ipsum, posuere a tincidunt non, consectetur et mi. Sed congue ornare lorem, et placerat velit tempus nec. Ut elit leo, ultrices mollis metus non,<span></span> </p>

    UPDATE

    Instead of the gradient you can use a simple image or an SVG:

    p {
      line-height: 20px;
      padding: 0 30px;
      background: url('data:image/svg+xml;utf8,<svg viewBox="0 0 20 20" width="20" height="20" xmlns="http://www.w3.org/2000/svg"><polygon points="20 20,0 20, 20 0" fill="white" /></svg>') top right/20px 20px repeat-y;
      background-color: grey;
      overflow: hidden;
      margin: 0;
    }
    
    span {
      position: relative;
      display: inline-block;
      vertical-align: bottom;
    }
    
    span:before {
      content: "";
      position: absolute;
      left: 30px; /*equal to padding*/
      bottom: 0px;
      height: 20px; /*equal to line-height*/
      background: url('data:image/svg+xml;utf8,<svg viewBox="0 0 20 20" width="20" height="20" xmlns="http://www.w3.org/2000/svg"><polygon points="0 0,0 20, 20 0" fill="grey" /></svg>') top left/20px 20px no-repeat;
      background-color: #fff;
      right: -100vw;
    }
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus ipsum, posuere a tincidunt non, Ut elit leo, ultrices mollis metus non,<span></span> </p>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus ipsum, posuere a tincidunt non, consectetur et mi. Sed congue ornare lorem, et placerat velit tempus nec. Ut elit leo, ultrices mollis metus non,<span></span> </p>