Welcome to Half 2 of this three-part collection! We’re nonetheless adorning pictures with none additional parts and pseudo-elements. I hope you already took the time to digest Half 1 as a result of we’ll proceed working with lots of gradients to create superior visible results. We’re additionally going to introduce the CSS masks
property for extra complicated decorations and hover results.
Let’s flip to the primary instance we’re engaged on collectively…
The Postage Stamp
Consider or not, all it takes to make postage stamp CSS impact is 2 gradients and a filter:
img {
--r: 10px; /* management the radius of the circles */
padding: calc(2 * var(--r));
filter: grayscale(.4);
background:
radial-gradient(var(--r),#0000 98%,#fff) spherical
calc(-1.5 * var(--r)) calc(-1.5 * var(--r)) / calc(3 * var(--r)) calc(3 * var(--r)),
linear-gradient(#fff 0 0) no-repeat
50% / calc(100% - 3 * var(--r)) calc(100% - 3 * var(--r));
}
As we noticed within the earlier article, step one is to create space across the picture with padding
so we will draw a background gradient and see it there. Then we use a mixture of radial-gradient()
and linear-gradient()
to chop these circles across the picture.
Here’s a step-by-step illustration that exhibits how the gradients are configured:
Notice using the spherical
worth within the second step. It’s crucial for the trick because it ensures the dimensions of the gradient is adjusted to be completely aligned on all the edges, it doesn’t matter what the picture width or top is.
From the specification: The picture is repeated as typically as will match throughout the background positioning space. If it doesn’t match an entire variety of occasions, it’s rescaled in order that it does.
The Rounded Body
Let’s have a look at one other picture ornament that makes use of circles…
This instance additionally makes use of a radial-gradient()
, however this time I’ve created circles round the picture as a substitute of the cut-out impact. Discover that I’m additionally utilizing the spherical
worth once more. The trickiest half right here is the clear hole between the body and the picture, which is the place I attain for the CSS masks
property:
img {
--s: 20px; /* measurement of the body */
--g: 10px; /* the hole */
--c: #FA6900;
padding: calc(var(--g) + var(--s));
background:
radial-gradient(farthest-side, var(--c) 97%, #0000)
0 0 / calc(2 * var(--s)) calc(2 * var(--s)) spherical;
masks:
conic-gradient(from 90deg at calc(2 * var(--s)) calc(2 * var(--s)), #0000 25%, #000 0)
calc(-1 * var(--s)) calc(-1 * var(--s)),
linear-gradient(#000 0 0) content-box;
}
Masking permits us to point out the realm of the picture — due to the linear-gradient()
in there — in addition to 20px
round all sides of it — due to the conic-gradient()
. The 20px
is nothing however the variable --s
that defines the dimensions of the body. In different phrases, we have to cover the hole.
Right here’s what I imply:
The linear gradient is the blue a part of the background whereas the conic gradient is the pink a part of the background. That clear half between each gradients is what we minimize from our component to create the phantasm of an interior clear border.
The Interior Clear Border
For this one, we’re not going to create a body however reasonably attempt one thing completely different. We’re going to create a clear interior border inside our picture. In all probability not that helpful in a real-world situation, nevertheless it’s good observe with CSS masks.
Much like the earlier instance, we’re going to depend on two gradients: a linear-gradient()
for the interior half, and a conic-gradient()
for the outer half. We’ll go away an area between them to create the clear border impact.
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the gap from the sting */
--_g: calc(100% - 2 * (var(--d) + var(--b)));
masks:
conic-gradient(from 90deg at var(--d) var(--d), #0000 25%, #000 0)
0 0 / calc(100% - var(--d)) calc(100% - var(--d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
}

You’ll have seen that the conic gradient of this instance has a distinct syntax from the earlier instance. Each are purported to create the identical form, so why are they completely different? It’s as a result of we will attain the identical consequence utilizing completely different syntaxes. This will likely look complicated at first, nevertheless it’s a very good characteristic. You aren’t obliged to seek out the resolution to attain a specific form. You solely want to seek out one resolution that works for you out of the various prospects on the market.
Listed below are 4 methods to create the outer sq. utilizing gradients:
There are much more methods to tug this off, however you get the purpose.
There is no such thing as a Greatest™ strategy. Personally, I attempt to discover the one with the smallest and most optimized code. For me, any resolution that requires fewer gradients, fewer calculations, and fewer repeated values is essentially the most appropriate. Typically I select a extra verbose syntax as a result of it offers me extra flexibility to vary variables and modify issues. It comes with expertise and observe. The extra you play with gradients, the extra you already know what syntax to make use of and when.
Let’s get again to our interior clear border and dig into the hover impact. In case you didn’t discover, there’s a cool hover impact that strikes that clear border utilizing a font-size
trick. The thought is to outline the --d
variable with a worth of 1em
. This variables controls the gap of the border from the sting. We will rework like this:
--_d: calc(var(--d) + var(--s) * 1em)
…giving us the next up to date CSS:
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the gap from the sting */
--o: 15px; /* the offset on hover */
--s: 1; /* the path of the hover impact (+1 or -1)*/
--_d: calc(var(--d) + var(--s) * 1em);
--_g: calc(100% - 2 * (var(--_d) + var(--b)));
masks:
conic-gradient(from 90deg at var(--_d) var(--_d), #0000 25%, #000 0)
0 0 / calc(100% - var(--_d)) calc(100% - var(--_d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
font-size: 0;
transition: .35s;
}
img:hover {
font-size: var(--o);
}
The font-size
is initially equal to 0
,so 1em
can also be equal to 0
and --_d
is be equal to --d
. On hover, although, the font-size
is the same as a worth outlined by an --o
variable that units the border’s offset. This, in flip, updates the --_d
variable, shifting the border by the offset. Then I add one other variable, --s
, to manage the signal that decides whether or not the border strikes to the within or the surface.
The font-size
trick is de facto helpful if we wish to animate properties which might be in any other case unanimatable. Customized properties outlined with @property
can resolve this however support for it continues to be missing on the time I’m penning this.
The Body Reveal
We made the next reveal animation within the first a part of this collection:
We will take the identical concept, however as a substitute of a border with a strong coloration we’ll use a gradient like this:
For those who evaluate each codes you’ll discover the next modifications:
- I used the identical gradient configuration from the primary instance contained in the
masks
property. I merely moved the gradients from thebackground
property to themasks
property. - I added a
repeating-linear-gradient()
to create the gradient border.
That’s it! I re-used many of the similar code we already noticed — with tremendous small tweaks — and received one other cool picture ornament with a hover impact.
/* Strong coloration border */
img {
--c: #8A9B0F; /* the border coloration */
--b: 10px; /* the border thickness*/
--g: 5px; /* the hole on hover */
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, var(--c) 0;
background:
conic-gradient(from 180deg at high var(--b) proper var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at backside var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat;
transition: .3s, background-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, background-size .3s .3s;
}
/* Gradient coloration border */
img {
--b: 10px; /* the border thickness*/
--g: 5px; /* the hole on hover */
background: repeating-linear-gradient(135deg, #F8CA00 0 10px, #E97F02 0 20px, #BD1550 0 30px);
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, #000 0;
masks:
conic-gradient(from 180deg at high var(--b) proper var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at backside var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat,
linear-gradient(#000 0 0) content-box;
transition: .3s, mask-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, mask-size .3s .3s;
}
Let’s attempt one other body animation. This one is a bit tough because it has a three-step animation:
Step one of the animation is to make the underside edge greater. For this, we modify the background-size
of a linear-gradient()
:
You’re in all probability questioning why I’m additionally including the highest edge. We’d like it for the third step. I at all times attempt to optimize the code I write, so I’m utilizing one gradient to cowl each the highest and backside sides, however the high one is hidden and revealed later with a masks
.
For the second step, we add a second gradient to point out the left and proper edges. However this time, we do it utilizing background-position
:
We will cease right here as we have already got a pleasant impact with two gradients however we’re right here to push the boundaries so let’s add a contact of masks to attain the third step.
The trick is to make the highest edge hidden till we present the underside and the edges after which we replace the mask-size
(or mask-position
) to point out the highest half. As I mentioned beforehand, we will discover lots of gradient configurations to attain the identical impact.
Right here is an illustration of the gradients I will likely be utilizing:
I’m utilizing two conic gradients having a width equal to 200%
. Each gradients cowl the realm leaving solely the highest half uncovered (that half will likely be invisible later). On hover, I slide each gradients to cowl that half.
Here’s a higher illustration of one of many gradients to provide you a greater concept of what’s taking place:
Now we put this contained in the masks
property and we’re executed! Right here is the total code:
img {
--b: 6px; /* the border thickness*/
--g: 10px; /* the hole */
--c: #0E8D94;
padding: calc(var(--b) + var(--g));
--_l: var(--c) var(--b), #0000 0 calc(100% - var(--b)), var(--c) 0;
background:
linear-gradient(var(--_l)) 50%/calc(100% - var(--_i,80%)) 100% no-repeat,
linear-gradient(90deg, var(--_l)) 50% var(--_i,-100%)/100% 200% no-repeat;
masks:
conic-gradient(at 50% var(--b),#0000 25%, #000 0) calc(50% + var(--_i, 50%)) / 200%,
conic-gradient(at 50% var(--b),#000 75%, #0000 0) calc(50% - var(--_i, 50%)) / 200%;
transition:
.3s calc(.6s - var(--_t,.6s)) mask-position,
.3s .3s background-position,
.3s var(--_t,.6s) background-size,
.4s rework;
cursor: pointer;
}
img:hover {
--_i: 0%;
--_t: 0s;
rework: scale(1.2);
}
I’ve additionally launched some variables to optimize the code, however you need to be used to this proper now.
What a couple of four-step animation? Sure, it’s potential!
No clarification for this as a result of it’s your homework! Take all that you’ve got realized on this article to dissect the code and attempt to articulate what it’s doing. The logic is much like all of the earlier examples. The bottom line is to isolate every gradient to know every step of the animation. I saved the code un-optimized to make issues slightly simpler to learn. I do have an optimized version if you’re , however you too can attempt to optimize the code your self and evaluate it with my model for added observe.
Wrapping up
That’s it for Half 2 of this three-part collection on artistic picture decorations utilizing solely the <img>
component. We now have a very good deal with on how gradients and masks will be mixed to create superior visible results, and even animations — with out reaching for additional parts or pseudo-elements. Sure, a single <img>
tag is sufficient!
Now we have another article on this collection to go. Till then, here’s a bonus demo with a cool hover impact the place I exploit masks
to assemble a damaged picture.