Shadows and opacity are the two CSS tools that express depth: a card shadow lifts content off the background, watermark transparency warns without obstructing reading, and rgba overlays create natural visual transitions between blocks. In dompdf.js, box-shadow, text-shadow, opacity, and rgba are all supported, and because the renderer works in vectors, shadow edges come out smooth and transparency transitions come out natural, with output quality close to a design tool. This article walks through the four core box-shadow parameters, horizontal and vertical offsets, blur radius, spread radius, and color, plus the inset keyword for inner shadows. You will learn the two levels of transparency, element-level opacity versus color-level rgba, and when to reach for each. Complete code examples demonstrate card projection, semi-transparent watermarks, and badges, followed by an honest look at how shadow counts affect rendering performance and file size, and a fallback playbook for environments where shadow support is partial. By the end you will be able to build layered, textured PDFs that feel closer to professional design output than to a default browser print, without sacrificing performance on large batches.The guidance here is grounded in how the renderer actually draws: shadows as vector fills, transparency as alpha compositing, and the trade-offs that follow for file size and render time. You will also learn how to layer shadows for realism, how to keep watermarks effective without obstructing content, and how to test whether a shadow-heavy design still performs in batch export. Keep the fallback table handy, because the difference between a template that degrades gracefully and one that falls apart is usually a few lines of defensive CSS applied up front.
Transparency exists at two levels. Element-level opacity applies to the entire element, background, border, and text alike, with values from 0 to 1, which suits watermarks, overlays, and whole-block fading. Color-level rgba applies only to the one color it decorates: background-color: rgba(0,0,0,0.3) tints the background while leaving the text fully opaque, giving you much finer control.
The semantic difference decides which one you use: fade the whole unit with opacity, fade just one surface with rgba. Watermarks favor opacity paired with a low-saturation gray so the mark stays visible without competing with body text; alternating table rows favor rgba or a light tinted color for a softer look that also prints lighter than a solid fill.
Transparency is implemented through the alpha channel, and dompdf.js handles nested stacking: when a semi-transparent parent contains a semi-transparent child, the final result follows the standard compositing rules, matching the browser. One caution: alpha stacking darkens what is underneath, so a translucent block over a dark background looks noticeably deeper. Always validate the design against the real base color instead of assuming the preview is accurate.
Element-level opacity has a side effect worth remembering: it creates a stacking context, so a semi-transparent parent confines the z-index of everything inside it. This is usually harmless, but if a child needs to float above unrelated page elements, the parent's opacity quietly blocks it. Either move the child outside the translucent parent or accept the confinement, and you avoid the classic my-z-index-is-huge-but-does-nothing mystery.
Opacity also affects perceived weight: a 0.5-opacity block looks like a lighter version of the same color, which is a cheap way to build visual hierarchy without adding new palette entries. Use it for secondary information, disabled states, and background layers, and keep full opacity for anything the reader must act on. The result is a calmer document where importance is communicated by contrast rather than by shouting.
The full box-shadow syntax is box-shadow: offset-x offset-y blur spread color. The first two values position the shadow, the blur radius softens its edge, the spread radius expands it outward, and the color determines the tint. dompdf.js renders these with standard semantics, and omitted parameters fall back to their specification defaults, so browser-tested shadows behave predictably in the PDF.
A canonical card configuration is box-shadow: 0 2px 8px rgba(0,0,0,0.15): a 2px downward offset creates the hover feel, an 8px blur softens the edge, and black at 15 percent opacity reads as a clean neutral shadow. For extra depth, layer two shadows, one close and darker, one farther and lighter, separated by commas, which produces the dimensional look that single shadows cannot achieve.
The inset keyword turns the shadow inward: box-shadow: inset 0 2px 4px rgba(0,0,0,0.1) makes the element's edges recede, ideal for pressed buttons and recessed input fields. Inner and outer shadows can coexist in one declaration list, and multiple layers of either kind are supported, so compound textures are a matter of composing comma-separated values.
Shadow realism comes from matching the light source: pick one direction, usually top-left light with shadows falling down and to the right, and keep every shadow in the document consistent with it. Inconsistent shadow directions make a layout feel physically wrong even when nothing else changes. A quick audit of your template's box-shadow values usually reveals a few reversed offsets, and normalizing them is a five-minute polish that noticeably improves the overall impression.
Multi-layer shadows are the standard technique for elevation: a tight shadow close to the element plus a wide soft shadow farther away reads as the element hovering above the page. The two layers should share the same offset direction and roughly the same color, with the far layer using more blur and less opacity. This two-layer recipe is what most design systems call elevation, and it transfers directly to PDF cards and panels.
text-shadow adds a projection to glyphs with a shorter syntax than box-shadow: horizontal offset, vertical offset, blur radius, and color. dompdf.js supports text-shadow rendering, which is handy for dimensional titles and for boosting readability when light text sits on a busy background, a common need in report covers and section headers.
Use text shadows sparingly. Shadowed body text loses legibility and prints poorly; titles and key figures can take an extremely subtle shadow like 0 1px 2px rgba(0,0,0,0.2) to gain depth, but avoid multi-layer or heavy shadows that introduce dirty edges on paper. When in doubt, no shadow is the safer choice for body copy.
The alternative to shadows is contrast: dark text on a light surface or light text on a dark surface needs no shadow at all when the contrast ratio is sufficient. Treat shadows as a supplement for cases where contrast alone cannot carry the design, and prefer contrast-first thinking in templates, which keeps both screen and print output clean.
Text shadows are most useful where contrast is genuinely low: light text over a busy image or a patterned header band. In those cases a subtle shadow improves legibility without redesigning the background. The trick is restraint: one layer, a small blur, and an alpha around 0.2-0.3, because anything heavier looks smudged on paper and cheap on screen.
A stronger alternative to text shadows is a background treatment: put the text on a translucent strip or a solid chip instead of fighting the background with shadows. This is more robust in print, where shadows can render inconsistently, and it often looks more modern. Use shadows for depth accents on headings and reserve the chip-and-strip technique for body copy that must remain readable at small sizes.
The example combines the three techniques from this article: a fixed watermark at 0.12 opacity that repeats on every page, a card with the two-layer elevation shadow, and an inset shadow that recesses the inner panel. Note the z-index on the watermark, which keeps it above content, and the rgba shadows, which stay neutral against any background. Render it, then experiment with the opacity and blur values to see how quickly the mood of the page changes.
Try the measurement exercise next: export the page twice, once with all shadows and once with the shadow declarations commented out, and compare the file sizes. The difference is usually modest for a single page, but it previews exactly what happens across a hundred-page batch. Then remove the watermark's opacity and re-export to see how much a fully opaque overlay intrudes on the content, which makes the case for keeping transparency in the design rather than treating it as optional polish.
import { DomPDF } from 'dompdf.js';
const html = `
<style>
.watermark {
position: fixed;
top: 40%; left: 0; right: 0;
text-align: center;
font-size: 48px;
color: #999;
opacity: 0.12;
transform: rotate(-45deg);
z-index: 999;
}
.card {
background-color: #fff;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15), 0 8px 24px rgba(0,0,0,0.08);
padding: 24px;
margin: 32px auto;
width: 70%;
}
.inset {
background-color: #f4f6f8;
border-radius: 6px;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.08);
padding: 12px;
}
h1 { text-shadow: 0 1px 2px rgba(0,0,0,0.15); }
</style>
<div class='watermark'>Internal Only - Do Not Distribute</div>
<div class='card'>
<h1>Quarterly Business Analysis</h1>
<p>Two-layer card shadow: near shadow plus far soft shadow</p>
<div class='inset'>Inset shadow area simulating a recessed field</div>
</div>`;
const pdf = new DomPDF({ format: 'A4', margin: '20mm' });
pdf.addPage(html, { format: 'A4' });
pdf.save('shadow-demo.pdf');
Card projection is the standard treatment for dashboards, quotes, and product cards: one close shadow plus one far soft shadow reads as natural suspension. Tables and body text should stay flat for readability. Watermarks use low-opacity diagonal text, between 0.1 and 0.2, balancing warning effect against readability: too light and the mark is useless, too dark and it fights the content.
Shadow colors should be black with an alpha value between roughly 0.1 and 0.25, which looks far more natural than a flat gray. Avoid saturated shadow colors, which read as cheap. Match the blur radius to the element size: small elements take small blurs and large elements take large blurs, and a mismatched ratio is immediately noticeable even to untrained eyes.
Keep the shadow system consistent across one document: either one parameter set for every card, or a graded hierarchy, plain cards one layer, elevated panels two. A unified shadow language makes the document look as if it came from a single design system, strengthens the professional impression, and makes global adjustments later a one-line change.
Watermarks deserve a small design system of their own: pick one opacity for all watermarks, one font size relative to the page, and one rotation angle, usually 30-45 degrees, and reuse them across every document. A consistent watermark style makes the security posture legible at a glance, and reviewers learn to recognize the mark without reading it. Rotating the text slightly is worth the effort, because horizontal watermarks are easier to crop out of a screenshot.
Opacity is also your tool for de-emphasizing non-essential page furniture: page numbers, revision dates, and legal footnotes at 0.6-0.7 opacity stay readable while receding behind the main content. This creates a clear visual hierarchy where the reader's eye lands on the data first. Combined with a consistent type scale, it is the difference between a document that feels engineered and one that feels assembled.
Shadows are essentially gradient-filled vector shapes, so a single shadow has a small impact on file size, and dompdf.js draws them as vectors. However, many elements with complex multi-layer shadows increase render computation, so limit shadows to key elements and differentiate secondary elements with borders and background tints instead.
Combining shadows with transparency generates extra graphics instructions, so pages that stack multiple translucent layers with shadows grow slightly larger. When batch-exporting many shadowed pages, export a sample first and compare sizes before deciding whether to trim layers, balancing visual richness against file weight for delivery channels like email attachments.
Fallback plan: if a target environment has partial shadow support, approximate a soft projection with a 1px light border plus a 2px light bottom margin on a tinted background; the effect is similar while the implementation is simpler. Never let critical information depend on shadows: shadows are a decorative layer, and the document must remain complete and readable with them removed entirely.
A practical performance rule for batch export: keep shadowed elements under roughly a dozen per page and prefer single-layer shadows in bulk templates. The renderer draws shadows as vector fills, so the cost is computation rather than file size, but a thousand shadowed elements across a hundred pages still adds up. For bulk exports, consider a reduced style variant that swaps shadows for borders and tints, and keep the full shadow treatment for single-document exports.
File size deserves the same discipline: shadows add graphics instructions, and stacking many translucent shadow layers grows the file faster than equivalent flat styling. Before shipping a template, export a sample document and compare sizes with shadows enabled and disabled; if the difference matters for your delivery channel, tune the shadow budget accordingly. This measurement-first approach beats guessing, and it catches runaway growth before users complain about slow downloads.
下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:
这是由 dompdf.js 渲染的示例 PDF 内容。