Because the title says, we’re going to beautify photos! There’s a bunch of different articles on the market that discuss this, however what we’re overlaying right here is sort of a bit completely different as a result of it’s extra of a problem. The problem? Beautify a picture utilizing solely the <img>
tag and nothing extra.
That proper, no additional markup, no divs, and no pseudo-elements. Simply the one tag.
Sounds tough, proper? However by the tip of this text — and the others that make up this little sequence — I’ll show that CSS is highly effective sufficient to provide us nice and beautiful outcomes regardless of the limitation of working with a single aspect.
Fancy Picture Decorations sequence
- Single Component Magic — you might be right here
- Masks and Superior Hover Results (coming October 21 )
- Outlines and Complicated Animations (coming October 28 )
Let’s begin with our first instance
Earlier than digging into the code let’s enumerate the chances for styling an <img>
with none additional components or pseudo-elements. We are able to use border
, box-shadow
, define
, and, after all, background
. It could look unusual so as to add a background to a picture as a result of we can not see it as it is going to be behind the picture — however the trick is to create house round the picture utilizing padding
and/or border
after which draw our background inside that house.
I feel you realize what comes subsequent since I talked about background
, proper? Sure, gradients! All of the decorations we’re going to make depend on a whole lot of gradients. For those who’ve adopted me for some time, I feel this most likely comes as no shock to you in any respect. 😁
Let’s get again to our first instance:
img {
--s: 10px; /* management the dimensions */
padding: var(--s);
border: calc(2 * var(--s)) stable #0000;
define: 1px stable #000;
outline-offset: calc(-1 * var(--s));
background: conic-gradient(from 90deg at 1px 1px, #0000 25%, #000 0);
}
We’re defining padding
and a clear border
utilizing the variable --s
to create an area round our picture equal to a few occasions that variable.
Why are we utilizing each padding
and border
as an alternative of 1 or the opposite? We are able to get by utilizing solely one among them however I want this mix for my gradient as a result of, by default, the preliminary worth of background-clip
is border-box
and background-origin
is the same as padding-box
.
Here’s a step-by-step illustration to know the logic:
Initially, we don’t have any borders on the picture, so our gradient will create two segments with 1px
of thickness. (I’m utilizing 3px
on this particular demo so it’s simpler to see.) We add a coloured border and the gradient nonetheless provides us the identical consequence contained in the padding space (because of background-origin
) nevertheless it repeats behind the border. If we make the colour of the border clear, we are able to use the repetition and we get the body we would like.
The define
within the demo has a detrimental offset. That creates a sq. form on the prime of the gradient. That’s it! We added a pleasant ornament to our picture utilizing one gradient and an define
. We might have used extra gradients! However I all the time attempt to maintain my code so simple as attainable and I discovered that including an define
is best that method.
Here’s a gradient-only resolution the place I’m utilizing solely padding
to outline the house. Nonetheless the identical consequence however with a extra advanced syntax.
Let’s attempt one other concept:
For this one, I took the earlier instance eliminated the define
, and utilized a clip-path
to chop the gradient on either side. The clip-path
worth is a bit verbose and complicated however right here is an illustration to higher see its factors:
I feel you get the principle concept. We’re going to mix backgrounds, outlines, clipping, and a few masking to realize completely different sorts of decorations. We’re additionally going to think about some cool hover animations as an added bonus! What we’ve checked out up to now is merely a small overview of what’s coming!
The Nook-Solely Body
This one takes 4 gradients. Every gradient covers one nook and, on hover, we develop them to create a full body across the picture. Let’s dissect the code for one of many gradients:
--b: 5px; /* border thickness */
background: conic-gradient(from 90deg at prime var(--b) left var(--b), #0000 90deg, darkblue 0) 0 0;
background-size: 50px 50px;
background-repeat: no-repeat;
We’re going to draw a gradient with a measurement equal to 50px 50px
and place it on the top-left nook (0 0
). For the gradient’s configuration, right here’s a step-by-step illustration displaying how I reached that consequence.
We are likely to assume that gradients are solely good for transitioning between two colours. However in actuality, we are able to accomplish that rather more with them! They’re particularly helpful in relation to creating completely different shapes. The trick is to ensure we now have arduous stops between colours — like within the instance above — moderately than clean transitions:
#0000 25%, darkblue 0
That is mainly saying: “fill the gradient with a clear shade till 25%
of the world, then fill the remaining space with darkblue
.
You is likely to be scratching your head over the 0
worth. It’s a bit of hack to simplify the syntax. In actuality, we should always use this to make a tough cease between colours:
#0000 25%, darkblue 25%
That’s extra logical! The clear shade ends at 25%
and darkblue
begins precisely the place the transparency ends, making a tough cease. If we exchange the second with 0
, the browser will do the job for us, so it’s a barely extra environment friendly solution to go about it.
Someplace in the specification, it says:
if a shade cease or transition trace has a place that’s lower than the desired place of any shade cease or transition trace earlier than it within the listing, set its place to be equal to the most important specified place of any shade cease or transition trace earlier than it.
0
is all the time smaller than some other worth, so the browser will all the time convert it to the most important worth that comes earlier than it within the declaration. In our case, that quantity is 25%
.
Now, we apply the identical logic to all of the corners and we finish with the next code:
img {
--b: 5px; /* border thickness */
--c: #0000 90deg, darkblue 0; /* outline the colour right here */
padding: 10px;
background:
conic-gradient(from 90deg at prime var(--b) left var(--b), var(--c)) 0 0,
conic-gradient(from 180deg at prime var(--b) proper var(--b), var(--c)) 100% 0,
conic-gradient(from 0deg at backside var(--b) left var(--b), var(--c)) 0 100%,
conic-gradient(from -90deg at backside var(--b) proper var(--b), var(--c)) 100% 100%;
background-size: 50px 50px; /* alter border size right here */
background-repeat: no-repeat;
}
I’ve launched CSS variables to keep away from some redundancy as all of the gradients use the identical shade configuration.
For the hover impact, all I’m doing is growing the dimensions of the gradients to create the complete body:
img:hover {
background-size: 51% 51%;
}
Sure, it’s 51%
as an alternative of 50%
— that creates a small overlap and avoids attainable gaps.
Let’s attempt one other concept utilizing the identical approach:
This time we’re utilizing solely two gradients, however with a extra advanced animation. First, we replace the place of every gradient, then enhance their sizes to create the complete body. I additionally launched extra variables for higher management over the colour, measurement, thickness, and even the hole between the picture and the body.
img {
--b: 8px; /* border thickness*/
--s: 60px; /* measurement of the nook*/
--g: 14px; /* the hole*/
--c: #EDC951;
padding: calc(var(--b) + var(--g));
background-image:
conic-gradient(from 90deg at prime var(--b) left var(--b), #0000 25%, var(--c) 0),
conic-gradient(from -90deg at backside var(--b) proper var(--b), #0000 25%, var(--c) 0);
background-position:
var(--_p, 0%) var(--_p, 0%),
calc(100% - var(--_p, 0%)) calc(100% - var(--_p, 0%));
background-size: var(--s) var(--s);
background-repeat: no-repeat;
transition:
background-position .3s var(--_i,.3s),
background-size .3s calc(.3s - var(--_i, .3s));
}
img:hover {
background-size: calc(100% - var(--g)) calc(100% - var(--g));
--_p: calc(var(--g) / 2);
--_i: 0s;
}
Why do the --_i
and --_p
variables have an underscore of their title? The underscores are a part of a naming conference I take advantage of to think about “inside” variables used to optimize the code. They’re nothing particular however I need to make a distinction between the variables we alter to regulate the body (like --b
, --c
, and so on.) and those I take advantage of to make the code shorter.
The code could look complicated and never straightforward to know however I wrote a three-part sequence the place I element such approach. I extremely suggest studying a minimum of the primary article to know how I reached the above code.
Right here is an illustration to higher perceive the completely different values:
The Body Reveal
Let’s attempt one other kind of animation the place we reveal the complete body on hover:
Cool, proper? And also you in case you look intently, you’ll discover that the traces disappear in the wrong way on mouse out which makes the impact much more fancy! I used an identical impact in a earlier article.
However this time, as an alternative of overlaying all of the aspect, I cowl solely a small portion by defining a peak
to get one thing like this:
That is the highest border of our body. We repeat the identical course of on either side of the picture and we now have our hover impact:
img {
--b: 10px; /* the border thickness*/
--g: 5px; /* the hole on hover */
--c: #8A9B0F;
padding: calc(var(--g) + var(--b));
--_g: no-repeat linear-gradient(var(--c) 0 0);
background:
var(--_g) var(--_i, 0%) 0,
var(--_g) 100% var(--_i, 0%),
var(--_g) calc(100% - var(--_i, 0%)) 100%,
var(--_g) 0 calc(100% - var(--_i, 0%));
background-size: var(--_i, 0%) var(--b),var(--b) var(--_i, 0%);
transition: .4s, background-position 0s;
cursor: pointer;
}
img:hover {
--_i: 100%;
}
As you’ll be able to see, I’m making use of the identical gradient 4 occasions and each has a unique place to cowl just one facet at a time.
One other one? Let’s go!
This one appears a bit tough and it certainly does require some creativeness to know how two conic gradients are pulling off this type of magic. Here’s a demo for example one of many gradients:
The pseudo-element simulates the gradient. It’s initially out of sight and, on hover, we first change its place to get the highest fringe of the body. Then we enhance the peak to get the correct edge. The gradient form is much like those we used within the final part: two segments to cowl two sides.
However why did I make the gradient’s width 200%
? You’d assume 100%
could be sufficient, proper?
100%
must be sufficient however I gained’t be capable to transfer the gradient like I would like if I maintain its width equal to 100%
. That’s one other little quirk associated to how background-position
works. I cowl this in a earlier article. I additionally posted a solution over at Stack Overflow coping with this. I do know it’s a whole lot of studying, nevertheless it’s actually price your time.
Now that we now have defined the logic for one gradient, the second is simple as a result of it’s doing precisely the identical factor, however overlaying the left and backside edges as an alternative. All we now have to do is to swap a couple of values and we’re achieved:
img {
--c: #8A9B0F; /* the border shade */
--b: 10px; /* the border thickness*/
--g: 5px; /* the hole */
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, var(--c) 0;
background:
conic-gradient(from 180deg at prime 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;
}
As you’ll be able to see, each gradients are nearly similar. I’m merely swapping the values of the dimensions and place.
The Body Rotation
This time we’re not going to attract a body round our picture, however moderately alter the look of an current one.
You’re most likely asking how on earth I’m able to remodel a straight line into an angled line. No, the magic is completely different than that. That’s simply the phantasm we get after combining easy animations for 4 gradients.
Let’s see how the animation for the highest gradient is made:
I’m merely updating the place of a repeating gradient. Nothing fancy but! Let’s do the identical for the correct facet:
Are you beginning to see the trick? Each gradients intersect on the nook to create the phantasm the place the straight line is modified to an angled one. Let’s take away the define and conceal the overflow to higher see it:
Now, we add two extra gradients to cowl the remaining edges and we’re achieved:
img {
--g: 4px; /* the hole */
--b: 12px; /* border thickness*/
--c: #669706; /* the colour */
padding: calc(var(--g) + var(--b));
--_c: #0000 0 25%, var(--c) 0 50%;
--_g1: repeating-linear-gradient(90deg ,var(--_c)) repeat-x;
--_g2: repeating-linear-gradient(180deg,var(--_c)) repeat-y;
background:
var(--_g1) var(--_p, 25%) 0,
var(--_g2) 0 var(--_p, 125%),
var(--_g1) var(--_p, 125%) 100%,
var(--_g2) 100% var(--_p, 25%);
background-size: 200% var(--b), var(--b) 200%;
transition: .3s;
}
img:hover {
--_p: 75%;
}
If we take this code and barely alter it, we are able to get one other cool animation:
Can you determine the logic on this instance? That’s your homework! The code could look scary nevertheless it makes use of the identical logic because the earlier examples we checked out. Attempt to isolate every gradient and picture the way it animates.
Wrapping up
That’s a whole lot of gradients in a single article!
It certain is and I warned you! But when the problem is to embellish a picture with out an additional components and pseudo-elements, we’re left with only some potentialities and gradients are essentially the most highly effective choice.
Don’t fear if you’re a bit misplaced in among the explanations. I all the time suggest a few of my previous articles the place I’m going into larger element with among the ideas we recycled for this problem.
I’m gonna go away with one final demo to carry you over till the subsequent article on this sequence. This time, I’m utilizing radial-gradient()
to create one other humorous hover impact. I’ll allow you to dissect the code to grok the way it works. Ask me questions within the feedback in case you get caught!
Fancy Picture Decorations sequence
- Single Component Magic — you might be right here
- Masks and Superior Hover Results (coming October 21 )
- Outlines and Complicated Animations (coming October 28 )