I am trying to set up a frame for <img> elements that automatically sizes itself to the inner image and takes its colors from the webpage's CSS variables, consisting of several parts:
- an inner shadow on all edges of the image,
- an outer border with rounded corners and variable-color
--Theme_Outline, - an offset border
2.25remoutside the image on all four sides with square corners and variable-color--Theme_Decor(with the page background visible through the gap), and - four SVG decorations (one at each corner of the offset border) with variable-color
--Theme_Decor.
Here's an example of what I want it to look like that I made in an art program, with a textured background and with pure cyan for variable-color --Theme_Outline and pure red for variable-color --Theme_Decor so they stand out:
Example image made in an art program
The only way I can find to do an inner shadow effect is with a CSS box-shadow with the inset attribute, but that gets rendered beneath the content of whatever element it is attached to (meaning beneath the image in an <img> element, for example), so to make it visible above the image the only option seems to be wrapping the image in a <div> with an ::after pseudo element.
With that constraint (wrapping every <img> in a <div class="bordered">) in mind, the best CSS code I've been able to come up with so far is:
:root{
--Theme_Decor: #ff0000;
--Theme_Outline: #00ffff;
}
html{
position: relative;
box-sizing: border-box;
font-size: 16px;
line-height: 1.5rem;
background-image: url(https://i.sstatic.net/gfRXmBIz.png);
background-size: cover;
background-attachment: fixed;
}
.bordered{
display: inline-block;
position: relative;
padding: 2.25rem;
outline: 0.25rem solid var(--Theme_Outline);
outline-offset: -2.25rem;
border-radius: 2.25rem;
line-height: 0;
}
.bordered::after{
content: "";
position: absolute;
width: calc(100% - 4.5rem);
height: calc(100% - 4.5rem);
inset: 2.25rem;
box-shadow: inset 0 0 0.375rem 0.25rem rgba(0, 0, 0, 0.5);
outline: 0.0625rem solid var(--Theme_Decor);
outline-offset: 2.1875rem;
}
<html>
<div class="bordered">
<img src="https://i.sstatic.net/2fkv9L8M.png">
</div>
</html>
That does what I want for the first three of the four parts of my goal, missing only the corner decorations. Here's a screenshot from Firefox showing the result:
Image captured from browser with everything except the corner decorations
However, I can't figure out a way to insert the corner decorations within the CSS.
If I use url() to link static SVG files inside the content property, I can't find a way to position them at every corner and I can't use stroke="currentColor" or stroke="var(--Theme_Decor)" to get the desired color.
I also experimented with adding the ::before pseudo-element so I could apply the border-image property to it without disrupting the other three parts of the frame, but again couldn't figure out a way to make it pull the desired color.
Is my goal achievable purely with CSS? Or do I need to settle for adding extra HTML elements around every <img> that I want to be framed?
-
1I've tried to rebuild what you say you have, and start finding a solution from there, but I cannot get what you already have. That makes it hard to help you. Please see: How to create a Minimal, Reproducible Example. Try to make a code snippet. People here on Stack Overflow really like clear, concise, to the point, and complete questions.KIKO Software– KIKO Software2025年10月23日 21:36:23 +00:00Commented 11 hours ago
-
For the corner decoration, look at stackoverflow.com/questions/51402532/…. As long as the SVG is part of the DOM, you can style whatever you position in the corners with CSS. Having it in a separate file or a data URL blocks the styling. Does that answer your question?ccprog– ccprog2025年10月23日 22:14:28 +00:00Commented 11 hours ago
-
@KIKOSoftware Adding the color variables to your CodePen makes it match what I've got. I added them to the code in my question for clarity.Lawton– Lawton2025年10月23日 22:34:20 +00:00Commented 10 hours ago
-
@ccprog My question is, is there a way to insert the decorations with CSS in a way that doesn't block the styling?Lawton– Lawton2025年10月24日 00:42:14 +00:00Commented 8 hours ago
-
can you share the SVG part?Temani Afif– Temani Afif2025年10月24日 07:21:18 +00:00Commented 2 hours ago
1 Answer 1
You can achieve a combination of inner shadow, rounded borders, and offset borders using a combination of box-shadow, border-radius, and pseudo-elements in pure CSS.
Here’s an approach that works across browsers without visual glitches:
<div class="fancy-box">
<div class="fancy-inner"></div>
</div>
.fancy-box {
position: relative;
width: 200px;
height: 120px;
border-radius: 20px;
border: 3px solid #4CAF50; /* outer rounded border */
background: #fff;
box-shadow: 0 4px 8px rgba(0,0,0,0.15); /* outer drop shadow */
overflow: hidden;
}
/* Inner shadow via pseudo-element */
.fancy-box::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: inset 0 4px 8px rgba(0,0,0,0.2); /* inner shadow */
pointer-events: none;
}
/* Optional offset border effect */
.fancy-box::after {
content: "";
position: absolute;
inset: -6px; /* adjust for ‘offset’ effect */
border-radius: calc(20px + 6px);
border: 2px solid rgba(76, 175, 80, 0.4);
pointer-events: none;
}
Explanation
border-radiusensures smooth, rounded edges.The
::beforepseudo-element creates an inner shadow usinginset box-shadowand matches the same radius.The
::afterpseudo-element is an offset border, visually sitting outside the main box without overlapping.pointer-events: noneensures these layers don’t block interactions.
Notes
This method avoids "ugly corner" artifacts that happen when combining
border-radiusandinset box-shadowdirectly on the same element.If you need multiple shadow layers (both inner and outer), you can list them:
box-shadow: inset 0 2px 5px rgba(0,0,0,0.15), 0 4px 8px rgba(0,0,0,0.25);.Works well on modern browsers and scales responsively.
This layered pseudo-element method allows you to simulate Photoshop-like combinations of rounded borders, inner shadows, and offset outlines using pure CSS.