Hello community,
first, thanks to all people contributing here, I’ve learned a lot in the past weeks.
I want to share a workaround for the missing box-shadow
feature.
Since I really would hate to do without it, I’ve written a tiny CSS utility helper, which roughly simulates a drop shadow on an element (actually, it’s just a handful of divs blending into each other).
Maybe it’s useful to someone.
Prerequisites:
- This works best with small / subtle drop shadows (unless You want to add hundreds of extra divs per element).
- You don’t mind having a few extra divs per element.
- Elements with a drop shadow must be positioned and have z-index (s. code comments).
- Works with
border-radius
.
If You’re fine with that, check out the code comments on how it works and play around with the modifiers, I’ve prepared three of them (–sm, --md, --go-nuts).
CSS-Utitility:
Import this somewhere in Your code.
/* @/css/utilities/box-shadow.css */
/**
* CSS utility helper to simulate shadows of DOM elements in a
* Photoshop UXP Plugin.
*
* @author: Cris | 2024 | https://cris.graphics
*
* As of August 2024 UXP doesn't support CSS `box-shadow`.
* This utility aims to simulate the property in a very rudimentary
* way, by styling a `.box-shadow` container with 5 nested children.
* You put the `.box-shadow` container as the last child into
* the main element, You want a drop shadow on.
* `.box-shadow` and `.box-shadow__bg` elements both inherit the
* background property of Your main element.
* The other four children inherit the size of the root element.
* Each child is larger in size, border-radius and is less opaque
* than it's previous sibling.
* So, with 4 'shadow' elements, we obviously can't have a real
* fading shadow, but for subtle shadows, it's enough to trick
* the eye.
*
* Important note: The `.box-shadow-el` must be positioned
* (e.g., relative, absolute, fixed) and must have a z-index
* of at least 0. Otherwise the shadow will disappear behind the
* container, that `.box-shadow-el` sits in.
*
* @usage:
* <div class="box-shadow-el">
* My Element Label
* <div class="box-shadow box-shadow--sm">
* <div class="box-shadow__bg"></div>
* <div class="box-shadow__shadow"></div>
* <div class="box-shadow__shadow"></div>
* <div class="box-shadow__shadow"></div>
* <div class="box-shadow__shadow"></div>
* </div>
* </div>
*/
/**
* Example modifier of how the shadow is applied.
* Add this modifier to the el containing the `.box-shadow` class.
*
* 1. Size in any supported unit.
* 2. HSL value.
* 3. Opacity value (0-1).
* 4. Push the shadow horizontally.
* 5. Push the shadow vertically.
* 6. Border-radius of the main element. Maybe set a variable on
* Your main element, like `--box-shadow__radius` and
* reference it here. Don't reference a variable to itself as
* PS might crash.
* 7. How far to spread the shadow. Offset must be > 0 to take
* effect. Can be any number.
* 8. Blending direction of each shadow layer.
* Check out https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient#syntax
* for possible values (deg, to top, to bottom, turn, etc.).
* If You don't want to blend the shadow layers,
* uncomment one of the other `background` props in every
* `:nth-child()` selector (s. below).
*/
/* Small size modifier example. */
.box-shadow--sm {
--box-shadow__size: 2px; /* 1 */
--box-shadow__color: 0, 0%, 0%; /* 2 */
--box-shadow__alpha: .075; /* 3 */
--box-shadow__offset-x: 1px; /* 4 */
--box-shadow__offset-y: 2px; /* 5 */
--box-shadow__rounded: var(--box-shadow__radius, 0px); /* 6 */
--box-shadow__spread-factor: .25; /* 7 */
--box-shadow__gradient-direction: to top; /* 8 */
}
/* Medium size modifier example. */
.box-shadow--md {
--box-shadow__size: 6px;
--box-shadow__color: 0, 0%, 0%;
--box-shadow__alpha: .075;
--box-shadow__offset-x: 2px;
--box-shadow__offset-y: 3px;
--box-shadow__rounded: var(--box-shadow__radius, 0px);
--box-shadow__spread-factor: .2;
--box-shadow__gradient-direction: -45deg;
}
/* Whatever-this-is modifier example. */
.box-shadow--go-nuts {
--box-shadow__size: .4vw;
--box-shadow__color: 270, 100%, 0%;
--box-shadow__alpha: .1;
--box-shadow__offset-x: .1vw;
--box-shadow__offset-y: .1vw;
--box-shadow__rounded: var(--box-shadow__radius, 0px);
--box-shadow__spread-factor: 15;
--box-shadow__gradient-direction: 120deg;
}
/**
* All the nasty code here, which You don't need to worry about,
* unless You're unhappy with the results ⬇.
*/
/* Container element of the `.box-shadow` item */
.box-shadow-el {
position: relative;
z-index: 0;
}
.box-shadow {
--box-shadow__z: -1;
}
/* Position the shadow and bg color elements. */
.box-shadow,
.box-shadow__bg {
position: absolute;
inset: 0;
width: inherit;
height: inherit;
border-radius: inherit;
background: inherit;
z-index: var(--box-shadow__z);
}
/* Rules that all shadow layers share. */
.box-shadow > .box-shadow__shadow {
--__box-shadow__gradient-direction: var(--box-shadow__gradient-direction, 0deg);
position: inherit;
top: calc(var(--__box-shadow-size) * -1.5);
left: calc(var(--__box-shadow-size) * -1.5);
width: calc(100% + var(--__box-shadow-size));
height: calc(100% + var(--__box-shadow-size));
border-radius: var(--__box-shadow__rounded);
transform: translate(
calc(var(--__box-shadow__offset-x) + var(--__box-shadow-size)),
calc(var(--__box-shadow__offset-y) + var(--__box-shadow-size))
);
z-index: calc(var(--box-shadow__z) - 1)
}
/* 1st shadow layer. */
.box-shadow > .box-shadow__shadow:nth-child(2) {
--__box-shadow-size: calc(var(--box-shadow__size) * .25);
--__box-shadow__offset-x: calc(var(--box-shadow__offset-x) * (var(--box-shadow__spread-factor)));
--__box-shadow__offset-y: calc(var(--box-shadow__offset-y) * (var(--box-shadow__spread-factor)));
--__box-shadow__rounded: calc(var(--box-shadow__rounded) + (var(--__box-shadow-size) * .25));
/* background: goldenrod; */
/* background: hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .75) ); */
background: linear-gradient(var(--__box-shadow__gradient-direction),
hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * 1)) 0%,
hsla(var(--box-shadow__color), 0) 100%,
);
z-index: calc(var(--box-shadow__z) - 2)
}
/* 2nd shadow layer. */
.box-shadow > .box-shadow__shadow:nth-child(3) {
--__box-shadow-size: calc(var(--box-shadow__size) * .5);
--__box-shadow__offset-x: calc(var(--box-shadow__offset-x) * (var(--box-shadow__spread-factor) * 2));
--__box-shadow__offset-y: calc(var(--box-shadow__offset-y) * (var(--box-shadow__spread-factor) * 2));
--__box-shadow__rounded: calc(var(--box-shadow__rounded) + (var(--__box-shadow-size) * .5));
/* background: lightseagreen; */
/* background: hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .5) ); */
background: linear-gradient(var(--__box-shadow__gradient-direction),
hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .75)) 0%,
hsla(var(--box-shadow__color), 0) 100%,
);
z-index: calc(var(--box-shadow__z) - 3)
}
/* 3rd shadow layer. */
.box-shadow > .box-shadow__shadow:nth-child(4) {
--__box-shadow-size: calc(var(--box-shadow__size) * .75);
--__box-shadow__offset-x: calc(var(--box-shadow__offset-x) * (var(--box-shadow__spread-factor) * 3));
--__box-shadow__offset-y: calc(var(--box-shadow__offset-y) * (var(--box-shadow__spread-factor) * 3));
--__box-shadow__rounded: calc(var(--box-shadow__rounded) + (var(--__box-shadow-size) * .75));
/* background: red; */
/* background: hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .25) ); */
background: linear-gradient(var(--__box-shadow__gradient-direction),
hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .5)) 0%,
hsla(var(--box-shadow__color), 0) 100%,
);
z-index: calc(var(--box-shadow__z) - 4)
}
/* 4th shadow layer. */
.box-shadow > .box-shadow__shadow:nth-child(5) {
--__box-shadow-size: calc(var(--box-shadow__size) * 1);
--__box-shadow__offset-x: calc(var(--box-shadow__offset-x) * (var(--box-shadow__spread-factor) * 4));
--__box-shadow__offset-y: calc(var(--box-shadow__offset-y) * (var(--box-shadow__spread-factor) * 4));
--__box-shadow__rounded: calc(var(--box-shadow__rounded) + (var(--__box-shadow-size) * 1 ));
/* background: blue; */
/* background: hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .1) ); */
background: linear-gradient(var(--__box-shadow__gradient-direction),
hsla(var(--box-shadow__color), calc(var(--box-shadow__alpha) * .25)) 0%,
hsla(var(--box-shadow__color), 0) 100%,
);
z-index: calc(var(--box-shadow__z) - 5)
}
A real world example
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>This title is shown nowhere anyway...</title>
<!-- Quick demo. ⬇ -->
<link rel="stylesheet" href="/src/css/utilities/box-shadow.css" />
<style>
.wrapper {
display: flex;
flex-direction: column;
width: 100%;
height: 300px;
background: var(--uxp-host-background-color);
padding: 1rem;
}
.item {
--box-shadow__radius: 4px;
flex: 1;
display: inline-flex;
justify-content: center;
align-items: center;
padding: .125em .875em;
color: #333;
background: #fff;
border-radius: var(--box-shadow__radius);
}
.item:nth-child(3) {
--box-shadow__radius: 10vw;
}
.item + .item {
margin-top: 1rem;
}
</style>
</head>
<body>
<main>
<div class="wrapper box-shadow-el">
<div class="item box-shadow-el">
Shadow SM
<div class="box-shadow box-shadow--sm">
<div class="box-shadow__bg"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
</div>
</div>
<div class="item box-shadow-el">
Shadow MD
<div class="box-shadow box-shadow--md">
<div class="box-shadow__bg"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
</div>
</div>
<div class="item box-shadow-el">
Go 🥜
<div class="box-shadow box-shadow--go-nuts">
<div class="box-shadow__bg"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
</div>
</div>
<!-- Put a shadow on the wrapper as well (don't forget
to add the `.box-shadow-el` class to it -->
<div class="box-shadow box-shadow--md">
<div class="box-shadow__bg"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
<div class="box-shadow__shadow"></div>
</div>
</div>
</main>
</body>
</html>
Best,
Cris
PS: Maybe You have already found a different solution. I’m happy to hear, what You’ve come up with.