2

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.

PeterTheLobster
  • 1,386
  • 16
  • 33
  • Designers... did they care to provide you with how it should look like when it has more than 2 lines and the 2nd line is either equal to, longer or shorter than the first? Probably not because that doesn't look good ;-) – René Aug 24 '18 at 14:20
  • I didn't get an example of that naturally :) – PeterTheLobster Aug 24 '18 at 14:25

1 Answers1

3

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>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Thanks this is really neat. I'll give it a try soon. Part of the problem is that some of the text is user submitted via text box but I guess I could try to break the strings by new line and wrap them in tags. – PeterTheLobster Aug 24 '18 at 14:23
  • Well this solution is correct and I will accept it. But unfortunately `wkhtmltopdf` doesn't like gradients and cannot interpret this correctly. I tried to convert it to webkit syntax as per [this](https://stackoverflow.com/questions/15642538/wkhtmltoimage-css3-gradient-rendering-in-snapshots) question but with no success. – PeterTheLobster Aug 24 '18 at 14:47
  • @PeterTheLobster probably they don't like multiple background ... keep the gradient and move the last color to `background-color` – Temani Afif Aug 24 '18 at 14:48
  • @PeterTheLobster I added another alternative, it's propably more supported – Temani Afif Aug 24 '18 at 15:04
  • Yeah I gave that a shot as well. I'm going to have to take a look it when I have more time but so far I've been unsuccessful :/ https://imgur.com/a/kakxFAY But I didn't get to mess with it too much. Tried to convert the gradient to `-webkit-gradient`, move some of the properties outside of the background and some other minor things. Oh well. Anyway, thanks for the help. – PeterTheLobster Aug 24 '18 at 15:17
  • @PeterTheLobster I am pretty sure my last attempt will work ... and even if the SVG is not supported simply create the triangle using paint then use it as a PNG, it should be supported – Temani Afif Aug 24 '18 at 15:18
  • I haven't tried to PNG approach but I don't think it will work. There are several issues with the way `wkhtmltopdf` renders this. I've managed to convert the original `linear-gradient` solution into `-webkit-gradient` syntax that the tool understands. Code [here](http://jsfiddle.net/tLwq3v8h/8/). However the resulting render produces [this](https://imgur.com/a/ixf4hQO). The background image is misaligned and keeps moving around at different zoom levels. The last line of the text also extends to the very end of the container. (don't think I override `display` prop). Simmilar with SVG. – PeterTheLobster Aug 28 '18 at 11:29
  • @PeterTheLobster because you need to pay attention to size .. it's very important to make the height of background equal to the line-height like I made in my code, so any change in the font-size, line-height,etc will screw it ... try to adjust the size of the background and it should work – Temani Afif Aug 28 '18 at 11:31
  • But the background size is equal to line-height. I'm using the same code I provided in the fiddle. I don't think the line-height is getting overriden anywhere. The position of the background also changes at varying zoom levels so I'm not sure where the issue lies. – PeterTheLobster Aug 28 '18 at 11:42
  • @PeterTheLobster what am seeing that there is a background repeat; are you sure the no-repeat is kept? – Temani Afif Aug 28 '18 at 11:43
  • Yea. But it seems like wkhtmltopdf has issues with background repeat as well - noted in [this issue](https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2500). And they also note that "the images scroll with zooming in pdf view".I think I'm just going to drop it at this point. – PeterTheLobster Aug 28 '18 at 11:49