I wanted to apply a fancy border with concave corners, so I used SVG. Everything looks fine on screen, but on the print dialog, the border is cut off by the right edge of the page. The border doesn’t get cut off if I give the card a max-width less than the width of the paper, but I don’t want to do that. I tried on Chrome and Edge.
I thought the div’s bounding box wasn’t fully calculated, so I tried requestAnimationFrame()
during the print trigger, but no luck.
Below is a minimal example. I gave comments for code changes I tried.
function applyCardBorders() {
let oldCardBorders = document.getElementsByClassName('card-border');
Array.from(oldCardBorders).forEach(cardBorder => cardBorder.remove());
let maxCornerRadius = 12;
let cards = document.getElementsByClassName('card');
Array.from(cards).forEach(card => {
drawBorder(card, maxCornerRadius);
});
}
function drawBorder(card, maxCornerRadius) {
// tried it this way too
// let w = card.offsetWidth;
// let h = card.offsetHeight;
let w = card.getBoundingClientRect().width;
let h = card.getBoundingClientRect().height;
let cornerRadius = Math.min(h / 3, maxCornerRadius);
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.style.position = "absolute";
svg.style.left = "0px";
svg.style.top = "0px";
svg.style.pointerEvents = "none";
svg.classList.add('card-border');
// tried it this way too
// svg.setAttribute("width", "100%");
// svg.setAttribute("height", "100%");
svg.setAttribute("width", w);
svg.setAttribute("height", h);
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", `M ${w-cornerRadius},${1}
A ${cornerRadius+2},${cornerRadius+2} 0 0 0 ${w-1},${cornerRadius}
L ${w-1},${h-cornerRadius}
A ${cornerRadius+2},${cornerRadius+2} 0 0 0 ${w-cornerRadius},${h-1}
L ${cornerRadius},${h-1}
A ${cornerRadius+2},${cornerRadius+2} 0 0 0 ${1},${h-cornerRadius}
L ${1},${cornerRadius}
A ${cornerRadius+2},${cornerRadius+2} 0 0 0 ${cornerRadius},${1}
Z`);
path.setAttribute("stroke", "#666461");
path.setAttribute("stroke-width", "2");
path.setAttribute("fill", "none");
svg.appendChild(path);
card.appendChild(svg);
}
window.addEventListener('load', async () => {
requestAnimationFrame(() => {
applyCardBorders();
});
});
window.addEventListener('resize', () => {
applyCardBorders();
});
// tried it this way too
// const mediaQueryList = window.matchMedia("print");
// mediaQueryList.addEventListener("change", (mql) => {
// requestAnimationFrame(() => {
// applyCardBorders();
// });
// });
window.addEventListener("beforeprint", () => {
applyCardBorders();
});
window.addEventListener("afterprint", () => {
applyCardBorders();
});
.card {
/* don't want to do this because it is paper size dependent, but it works */
/* max-width: 6in; */
background-color: #b7cece;
padding: 8px;
position: relative;
}
<div class="card">
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</div>