Some time in the past, Geoff wrote an article a couple of cool hover impact. The impact depends on a mixture of CSS pseudo-elements, transforms, and transitions. A number of feedback have proven that the identical impact will be accomplished utilizing background properties. Geoff talked about that was his preliminary thought and that’s what I used to be pondering as effectively. I’m not saying the pseudo-element he landed on is dangerous, however realizing totally different strategies to attain the identical impact can solely be a superb factor.
On this publish, we are going to re-work that hover impact, but in addition increase it into different varieties of hover results that solely use CSS background properties.
You possibly can see the background properties at work in that demo, in addition to how we will use customized properties and the calc() operate to do much more. We’re going to learn to mix all of those so we’re left with properly optimized code!
Hover impact #1
Let’s begin with the primary impact which is the copy of the one detailed by Geoff in his article. The code used to attain that impact is the next:
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(–p, 0) / var(–p, 0) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
–p: 100%;
coloration: #fff;
}
If we omit the colour transition (which is non-obligatory), we solely want three CSS declarations to attain the impact. You’re in all probability stunned how small the code is, however you will notice how we bought there.
First, let’s begin with a easy background-size transition:
We’re animating the dimensions of a linear gradient from 0 100% to 100% 100%. Which means the width goes from 0 to 100% whereas the background itself stays at full top. Nothing advanced to this point.
Let’s begin our optimizations. We first rework our gradient to make use of the colour solely as soon as:
background-image: linear-gradient(#1095c1 0 0);
The syntax would possibly look a bit unusual, however we’re telling the browser that one coloration is utilized to 2 coloration stops, and that’s sufficient to outline a gradient in CSS. Each coloration stops are 0, so the browser robotically makes the final one 100% and fills our gradient with the identical coloration. Shortcuts, FTW!
With background-size, we will omit the peak as a result of gradients are full top by default. We are able to do a transition from background-size: 0 to background-size: 100%.
.hover-1 {
background-image: linear-gradient(#1095c1 0 0);
background-size: 0;
background-repeat: no-repeat;
transition: .4s;
}
.hover-1:hover {
background-size: 100%;
}
Let’s introduce a customized property to keep away from the repetition of background-size:
.hover-1 {
background-image: linear-gradient(#1095c1 0 0);
background-size: var(–p, 0%);
background-repeat: no-repeat;
transition: .4s;
}
.hover-1:hover {
–p: 100%;
}
We aren’t defining –p initially, so the fallback worth (0% in our case) will likely be used. On hover, we outline a worth that replaces the fallback one ( 100%).
Now, let’s mix all of the background properties utilizing the shorthand model to get:
.hover-1 {
background: linear-gradient(#1095c1 0 0) left / var(–p, 0%) no-repeat;
transition: .4s;
}
.hover-1:hover {
–p: 100%;
}
We’re getting nearer! Observe that I’ve launched a left worth (for the background-position) which is necessary when defining the dimensions within the background shorthand. Plus, we want it anyway to attain our hover impact.
We have to additionally replace the place on hover. We are able to try this in two steps:
Improve the dimensions from the best on mouse hover.Lower the dimensions from the left on mouse out.
To do that, we have to replace the background-position on hover as effectively:
We added two issues to our code:
A background-position worth of proper on hoverA transition-duration of 0s on the background-position
Which means that, on hover, we immediately change the background-position from left (see, we would have liked that worth!) to proper so the background’s dimension will improve from the best facet. Then, when the mouse cursor leaves the hyperlink, the transition performs in reverse, from proper to left, making it seem that we’re lowering the background’s dimension from the left facet. Our hover impact is finished!
However you stated we solely wanted three declarations and there are 4.
That’s true, good catch. The left and proper values will be modified to 0 0 and 100% 0, respectively; and since our gradient is already full top by default, we will get through the use of 0 and 100%.
.hover-1 {
background: linear-gradient(#1095c1 0 0) 0 / var(–p, 0%) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
–p: 100%;
background-position: 100%;
}
See how background-position and –p are utilizing the identical values? Now we will scale back the code down to 3 declarations:
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(–p, 0%) / var(–p,0%) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
–p: 100%;
}
The customized property –p is defining each the background place and dimension. On hover, It’ll replace each of them as effectively. It is a excellent use case displaying how customized properties may also help us scale back redundant code and keep away from writing properties greater than as soon as. We outline our setting utilizing customized properties and we solely replace the latter on hover.
However the impact Geoff described is doing the other, ranging from left and ending at proper. How will we try this when it appears we can’t depend on the identical variable?
We are able to nonetheless use one variable and replace our code barely to attain the other impact. What we would like is to go from 100% to 0% as an alternative of 0% to 100%. Now we have a distinction of 100% that we will categorical utilizing calc(), like this:
.hover-1 {
background: linear-gradient(#1095c1 0 0) calc(100% – var(–p,0%)) / var(–p,0%) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
–p: 100%;
}
–p will change from 0% to 100%, however the background’s place will change from 100% to 0%, due to calc().
We nonetheless have three declarations and one customized property, however a unique impact.
Earlier than we transfer to the subsequent hover impact, I wish to spotlight one thing essential that you’ve in all probability seen. When coping with customized properties, I’m utilizing 0% (with a unit) as an alternative of a unit-less 0. The unit-less zero may go when the customized property is alone, however will fail inside calc() the place we have to explicitly outline the unit. I may have one other article to clarify this quirk however all the time bear in mind so as to add the unit when coping with customized properties. I’ve two solutions on StackOverflow (right here and right here) that go into extra element.
Hover impact #2
We want a extra advanced transition for this impact. Let’s check out a step-by-step illustration to grasp what is going on.
Initially, a fixed-height, full-width gradient is outdoors of view. Then we transfer the gradient to the best to cowl the underside facet. Lastly, we improve the dimensions of the gradient from the fastened top to 100% to cowl the entire factor.
We first have a background-position transition adopted by a background-size one. Let’s translate this into code:
.hover-2 {
background-image: linear-gradient(#1095c1 0 0);
background-size: 100% .08em; /* .08em is our fastened top; modify as wanted. */
background-position: /* ??? */;
background-repeat: no-repeat;
transition: background-size .3s, background-position .3s .3s;
}
.hover-2:hover {
transition: background-size .3s .3s, background-position .3s;
background-size: 100% 100%;
background-position: /* ??? */;
}
Observe the usage of two transition values. On hover, we have to first change the place and later the dimensions, which is why we’re including a delay to the dimensions. On mouse out, we do the other.
The query now could be: what values will we use for background-position? We left these clean above. The background-size values are trivial, however the ones for background-position aren’t. And if we hold the precise configuration we’re unable to maneuver our gradient.
Our gradient has a width equal to 100%, so we can’t use share values on background-position to maneuver it.
Proportion values used with background-position are all the time a ache particularly whenever you use them for the primary time. Their habits is non-intuitive however effectively outlined and straightforward to grasp if we get the logic behind it. I believe it could take one other article for a full reason it really works this fashion, however right here’s one other “lengthy” rationalization I posted over at Stack Overflow. I like to recommend taking a couple of minutes to learn that reply and you’ll thank me later!
The trick is to vary the width to one thing totally different than 100%. Let’s use 200%. We’re not frightened in regards to the background exceeding the factor as a result of the overflow is hidden anyway.
.hover-2 {
background-image: linear-gradient(#1095c1 0 0);
background-size: 200% .08em;
background-position: 200% 100%;
background-repeat: no-repeat;
transition: background-size .3s, background-position .3s .3s;
}
.hover-2:hover {
transition: background-size .3s .3s, background-position .3s;
background-size: 200% 100%;
background-position: 100% 100%;
}
And right here’s what we get:
It’s time to optimize our code. If we take the concepts we realized from the primary hover impact, we will use shorthand properties and write fewer declarations to make this work:
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
var(–p, 200%) 100% / 200% var(–p, .08em);
transition: .3s var(–t, 0s), background-position .3s calc(.3s – var(–t, 0s));
}
.hover-2:hover {
–p: 100%;
–t: .3s;
}
We add all of the background properties collectively utilizing the shorthand model then we use –p to precise our values. The sizes change from .08em to 100% and the place from 200% to 100%
I’m additionally utilizing one other variable –t , to optimize the transition property. On mouse hover we’ve it set to a .3s worth, which provides us this:
transition: .3s .3s, background-position .3s 0s;
On mouse out, –t is undefined, so the fallback worth will likely be used:
transition: .3s 0s, background-position .3s .3s;
Shouldn’t we’ve background-size within the transition?
That’s certainly one other optimization we will make. If we don’t specify any property it means “all” the properties, so the transition is outlined for “all” the properties (together with background-size and background-position). Then it’s outlined once more for background-position which has similarities to defining it for background-size, then background-position.
“Comparable” is totally different than saying one thing is the “similar.” You will notice a distinction in the event you change extra properties on hover, so the final optimization is perhaps unsuitable in some circumstances.
Can we nonetheless optimize the code and use just one customized property?
Sure, we will! Ana Tudor shared a nice article explaining the best way to create DRY switching the place one customized property can replace a number of properties. I gained’t go into the small print right here, however our code will be revised like this:
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
calc(200% – var(–i, 0) * 100%) 100% / 200% calc(100% * var(–i, 0) + .08em);
transition: .3s calc(var(–i, 0) * .3s), background-position .3s calc(.3s – calc(var(–i, 0) * .3s));
}
.hover-2:hover {
–i: 1;
}
The –i customized property is initially undefined, so the fallback worth, 0, is used. On hover although, we substitute 0 with 1. You are able to do the mathematics for each circumstances and get the values for every one. You possibly can see that variable as a “swap” that replace all our values directly on hover.
Once more, we’re again to solely three declarations for a fairly cool hover impact!
Hover impact #3
We’re going to use two gradients as an alternative of 1 for this impact. We are going to see that combining a number of gradients is one other strategy to create fancy hover results.
Right here’s a diagram of what we’re doing:
We initially have two gradients that overflow the factor in order that they’re out of view. Every one has a hard and fast top and toes up half of the factor’s width. Then we slide them into view to make them seen. The primary gradient is positioned on the bottom-left and the second on the top-right. Lastly, we improve the peak to cowl the entire factor.
Right here’s how that appears in CSS:
.hover-3 {
background-image:
linear-gradient(#1095c1 0 0),
linear-gradient(#1095c1 0 0);
background-repeat: no-repeat;
background-size: 50% .08em;
background-position:
-100% 100%,
200% 0;
transition: background-size .3s, background-position .3s .3s;
}
.hover-3:hover {
background-size: 50% 100%;
background-position:
0 100%,
100% 0;
transition: background-size .3s .3s, background-position .3s;
}
The code is sort of the identical as the opposite hover results we’ve coated. The one distinction is that we’ve two gradients with two totally different positions. The place values could look unusual however, once more, that’s associated to how percentages work with the background-position property in CSS, so I extremely advocate studying my Stack Overflow reply if you wish to get into the gritty particulars.
Now let’s optimize! You get the thought by now — we’re utilizing shorthand properties, customized properties, and calc() to tidy issues up.
.hover-3 {
–c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(–c) calc(-100% + var(–p, 0%)) 100% / 50% var(–p, .08em),
var(–c) calc( 200% – var(–p, 0%)) 0 / 50% var(–p, .08em);
transition: .3s var(–t, 0s), background-position .3s calc(.3s – var(–t, 0s));
}
.hover-3:hover {
–p: 100%;
–t: 0.3s;
}
I’ve added an additional customized property, –c, that defines the gradient for the reason that similar gradient is utilized in each locations.
I’m utilizing 50.1% in that demo as an alternative of fifty% for the background dimension as a result of it prevents a spot from displaying between the gradients. I additionally added 1% to the positions for comparable causes.
Let’s do the second optimization through the use of the swap variable:
.hover-3 {
–c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(–c) calc(-100% + var(–i, 0) * 100%) 100% / 50% calc(100% * var(–i, 0) + .08em),
var(–c) calc( 200% – var(–i, 0) * 100%) 0 / 50% calc(100% * var(–i, 0) + .08em);
transition: .3s calc(var(–i, 0) * .3s), background-position .3s calc(.3s – var(–i, 0) * .3s);
}
.hover-3:hover {
–i: 1;
}
Are you began to see the patterns right here? It’s not a lot that the consequences we’re making are tough. It’s extra the “ultimate step” of code optimization. We begin by writing verbose code with a variety of properties, then scale back it following easy guidelines (e.g. utilizing shorthand, eradicating default values, avoiding redundant values, and so on) to simplify issues down as a lot as doable.
Hover impact #4
I’ll elevate the issue degree for this final impact, however you recognize sufficient from the opposite examples that I doubt you’ll have any points with this one.
This hover impact depends on two conic gradients and extra calculations.
Initially, we’ve each gradients with zero dimensions in Step 1. We improve the dimensions of every one in Step 2. We hold rising their widths till they absolutely cowl the factor, as proven in Step 3. After that, we slide them to the underside to replace their place. That is the “magic” a part of the hover impact. Since each gradients will use the identical coloration, altering their place in Step 4 will make no visible distinction — however we are going to see a distinction as soon as we scale back the dimensions on mouse out throughout Step 5.
In case you evaluate Step 2 and Step 5, you may see that we’ve a unique inclination. Let’s translate that into code:
.hover-4 {
background-image:
conic-gradient(/* ??? */),
conic-gradient(/* ??? */);
background-position:
0 0,
100% 0;
background-size: 0% 200%;
background-repeat: no-repeat;
transition: background-size .4s, background-position 0s;
}
.hover-4:hover {
background-size: /* ??? */ 200%;
background-position:
0 100%,
100% 100%;
}
The positions are fairly clear. One gradient begins at prime left (0 0) and ends at backside left (0 100%) whereas the opposite begins at prime proper (100% 0) and ends at backside proper (100% 100%).
We’re utilizing a transition on the background positions and sizes to disclose them. We solely want a transition worth for the background-size. And like earlier than, background-position wants to vary immediately, so we’re assigning a 0s worth for the transition’s period.
For the sizes, each gradient have to have 0 width and twice the factor top (0% 200%). We are going to see later how their sizes change on hover. Let’s first outline the gradient configuration.
The diagram beneath illustrates the configuration of every gradient:
Observe that for the second gradient (indicated in inexperienced), we have to know the peak to make use of it contained in the conic-gradient we’re creating. For that reason, I’m going so as to add a line-height that units the factor’s top after which attempt that very same worth for the conic gradient values we neglected.
.hover-4 {
–c: #1095c1;
line-height: 1.2em;
background-image:
conic-gradient(from -135deg at 100% 50%, var(–c) 90deg, #0000 0),
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(–c) 0);
background-position:
0 0,
100% 0;
background-size: 0% 200%;
background-repeat: no-repeat;
transition: background-size .4s, background-position 0s;
}
.hover-4:hover {
background-size: /* ??? */ 200%;
background-position:
0 100%,
100% 100%;
}
The very last thing we’ve left is to determine the background’s dimension. Intuitively, we might imagine that every gradient must take up half of the factor’s width however that’s truly not sufficient.
We’re left with a big hole if we use 50% because the background-size worth for each gradients.
We get a spot equal to the peak, so we truly have to do is improve the dimensions of every gradient by half the peak on hover for them to cowl the entire factor.
.hover-4:hover {
background-size: calc(50% + .6em) 200%;
background-position:
0 100%,
100% 100%;
}
Right here’s what we get after optimizing them just like the earlier examples:
.hover-4 {
–c: #1095c1;
line-height: 1.2em;
background:
conic-gradient(from -135deg at 100% 50%, var(–c) 90deg, #0000 0)
0 var(–p, 0%) / var(–s, 0%) 200% no-repeat,
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(–c) 0)
100% var(–p, 0%) / var(–s, 0%) 200% no-repeat;
transition: .4s, background-position 0s;
}
.hover-4:hover {
–p: 100%;
–s: calc(50% + .6em);
}
What in regards to the model with just one customized property?
I’ll depart that for you! After 4 comparable hover results, you need to have the ability to get the ultimate optimization right down to a single customized property. Share your work within the remark part! There’s no prize, however we could find yourself with totally different implementations and concepts that profit everybody!
Earlier than we finish, let me share a model of that final hover impact that Ana Tudor cooked up. It’s an enchancment! However observe that it lacks Firefox helps attributable to a identified bug. Nonetheless, it’s an important concept that reveals the best way to mix gradients with mix modes to create even cooler hover results.
Wrapping up
We made 4 tremendous cool hover results! And although they’re totally different results, all of them take the identical strategy of utilizing CSS background properties, customized properties, and calc(). Completely different mixtures allowed us to make totally different variations, all utilizing the identical methods that depart us with clear, maintainable code.
If you wish to get some concepts, I made a assortment of 500 (sure, 500!) hover results, 400 of that are accomplished with out pseudo-elements. The 4 we coated on this article are simply the tip of the iceberg!
Cool Hover Results That Use Background Properties initially printed on CSS-Methods. It is best to get the e-newsletter.
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!