How usually to do you attain for the CSS background-size
property? For those who’re like me — and doubtless plenty of different front-end people — then it’s often once you background-size: cowl
a picture to fill the area of a whole component.
Nicely, I used to be introduced with an fascinating problem that required extra superior background sizing: background stripes that transition on hover. Verify this out and hover it together with your cursor:
There’s much more happening there than the scale of the background, however that was the trick I wanted to get the stripes to transition. I believed I’d present you the way I arrived there, not solely as a result of I feel it’s a very nice visible impact, however as a result of it required me to get inventive with gradients and mix modes that I feel you may get pleasure from.
Let’s begin with a really fundamental setup to maintain issues easy. I’m speaking a few single <div>
within the HTML that’s styled as a inexperienced sq.:
<div></div>
div {
width: 500px;
peak: 500px;
background: palegreen;
}
Establishing the background stripes
In case your thoughts went straight to a CSS linear gradient once you noticed these stripes, then we’re already on the identical web page. We will’t precisely do a repeating gradient on this case since we would like the stripes to occupy uneven quantities of area and transition them, however we are able to create 5 stripes by chaining 5 backgrounds on high of our current background shade and putting them to the top-right of the container:
div {
width: 500px;
peak: 500px;
background:
linear-gradient(black, black) high proper,
linear-gradient(black, black) high 100px proper,
linear-gradient(black, black) high 200px proper,
linear-gradient(black, black) high 300px proper,
linear-gradient(black, black) high 400px proper,
palegreen;
}
I made horizontal stripes, however we might additionally go vertical with the method we’re masking right here. And we are able to simplify this fairly a bit with customized properties:
div {
--gt: linear-gradient(black, black);
--n: 100px;
width: 500px;
peak: 500px;
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
palegreen;
}
So, the --gt
worth is the gradient and --n
is a continuing we’re utilizing to nudge the stripes downward so they’re offset vertically. And you could have observed that I haven’t set a real gradient, however relatively strong black stripes within the linear-gradient()
perform — that’s intentional and we’ll get to why I did that in a bit.
Yet another factor we should do earlier than shifting on is stop our backgrounds from repeating; in any other case, they’ll tile and fill your entire area:
div {
--gt: linear-gradient(black, black);
--n: 100px;
width: 500px;
peak: 500px;
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
palegreen;
background-repeat: no-repeat;
}
We might have set background-repeat
within the background
shorthand, however I made a decision to interrupt it out right here to maintain issues simple to learn.
Offsetting the stripes
We technically have stripes, however it’s fairly robust to inform as a result of there’s no spacing between them and so they cowl your entire container. It’s extra like we now have a strong black sq..
That is the place we get to make use of the background-size
property. We need to set each the peak and the width of the stripes and the property helps a two-value syntax that enables us to do precisely that. And, we are able to chain these sizes by comma separating them the identical method we did on background
.
Let’s begin easy by setting the widths first. Utilizing the single-value syntax for background-size
units the width and defaults the peak to auto
. I’m utilizing completely arbitrary values right here, so set the values to what works finest in your design:
div {
--gt: linear-gradient(black, black);
--n: 100px;
width: 500px;
peak: 500px;
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
palegreen;
background-repeat: no-repeat;
background-size: 60%, 90%, 70%, 40%, 10%;
}
For those who’re utilizing the identical values that I’m, you’ll get this:
Doesn’t precisely appear to be we set the width for all of the stripes, does it? That’s due to the auto
peak habits of the single-value syntax. The second stripe is wider than the others beneath it, and it’s masking them. We should set the heights so we are able to see our work. They need to all be the identical peak and we are able to truly re-use our --n
variable, once more, to maintain issues easy:
div {
--gt: linear-gradient(black, black);
--n: 100px;
width: 500px;
peak: 500px;
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
palegreen;
background-repeat: no-repeat;
background-size: 60% var(--n), 90% var(--n), 70% var(--n), 40% var(--n), 10% var(--n); // HIGHLIGHT 15
}
Ah, a lot better!
Including gaps between the stripes
This can be a completely non-compulsory step in case your design doesn’t require gaps between the stripes, however mine did and it’s not overly difficult. We modify the peak of every stripe’s background-size
a smidge, reducing the worth in order that they fall wanting filling the total vertical area.
We will proceed to make use of our --n
variable, however subtract a small quantity, say 5px
, utilizing calc()
to get what we would like.
background-size: 60% calc(var(--n) - 5px), 90% calc(var(--n) - 5px), 70% calc(var(--n) - 5px), 40% calc(var(--n) - 5px), 10% calc(var(--n) - 5px);
That’s quite a lot of repetition we are able to eradicate with one other variable:
div {
--h: calc(var(--n) - 5px);
/* and so on. */
background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
}
Masking and mixing
Now let’s swap the palegreen
background shade we’ve been utilizing for visible functions up thus far for white.
div {
/* and so on. */
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
#fff;
/* and so on. */
}
A black and white sample like that is excellent for masking and mixing. To do this, we’re first going to wrap our <div>
in a brand new guardian container and introduce a second <div>
below it:
<part>
<div></div>
<div></div>
</part>
We’re going to do some CSS re-factoring right here. Now that we now have a brand new guardian container, we are able to cross the mounted width
and peak
properties we have been utilizing on our <div>
over there:
part {
width: 500px;
peak: 500px;
}
I’m additionally going to make use of CSS Grid to place the 2 <div>
parts on high of each other. This is similar trick Temani Afif makes use of to create his tremendous cool picture galleries. The thought is that we place each divs over the total container utilizing the grid-area
property and align the whole lot towards the middle:
part {
show: grid;
align-items: heart;
justify-items: heart;
width: 500px;
peak: 500px;
}
part > div {
width: inherit;
peak: inherit;
grid-area: 1 / 1;
}
Now, test this out. The rationale I used a strong gradient that goes from black to black earlier is to set us up for masking and mixing the 2 <div>
layers. This isn’t true masking within the sense that we’re calling the masks
property, however the distinction between the layers controls what colours are seen. The world coated by white will stay white, and the world coated by black leaks by way of. MDN’s documentation on mix modes has a pleasant rationalization of how this works.
To get that working, I’ll apply the actual gradient we need to see on the primary <div>
whereas making use of the model guidelines from our preliminary <div>
on the brand new one, utilizing the :nth-child()
pseudo-selector:
div:nth-child(1) {
background: linear-gradient(to proper, purple, orange);
}
div:nth-child(2) {
--gt: linear-gradient(black, black);
--n: 100px;
--h: calc(var(--n) - 5px);
background:
var(--gt) high proper,
var(--gt) high var(--n) proper,
var(--gt) high calc(var(--n) * 2) proper,
var(--gt) high calc(var(--n) * 3) proper,
var(--gt) high calc(var(--n) * 4) proper,
white;
background-repeat: no-repeat;
background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
}
If we cease right here, we truly gained’t see any visible distinction from what we had earlier than. That’s as a result of we haven’t carried out the precise mixing but. So, let’s try this now utilizing the display
mix mode:
div:nth-child(2) {
/* and so on. */
mix-blend-mode: display;
}
I used a beige background shade within the demo I confirmed originally of this text. That barely darker type of off-white coloring permits a little bit shade to bleed by way of the remainder of the background:
The hover impact
The final piece of this puzzle is the hover impact that widens the stripes to full width. First, let’s write out our selector for it. We would like this to occur when the guardian container (<part>
in our case) is hovered. When it’s hovered, we’ll change the background dimension of the stripes contained within the second <div>
:
/* When <part> is hovered, change the second div's types */
part:hover > div:nth-child(2){
/* types go right here */
}
We’ll need to change the background-size
of the stripes to the total width of the container whereas sustaining the identical peak:
part:hover > div:nth-child(2){
background-size: 100% var(--h);
}
That “snaps” the background to full-width. If we add a little bit transition
to this, then we see the stripes increase on hover:
part:hover > div:nth-child(2){
background-size: 100% var(--h);
transition: background-size 1s;
}
Right here’s that ultimate demo as soon as once more:
I solely added textual content in there to indicate what it’d appear to be to make use of this in a unique context. For those who do the identical, then it’s value ensuring there’s sufficient distinction between the textual content shade and the colours used within the gradient to adjust to WCAG pointers. And whereas we’re touching briefly on accessibility, it’s value contemplating person preferences for lowered movement in terms of the hover impact.
That’s a wrap!
Fairly neat, proper? I actually suppose so. What I like about this, too, is that it’s fairly maintainable and customizable. For instance, we are able to alter the peak, colours, and path of the stripes by altering just a few values. You may even variablize just a few extra issues in there — like the colours and widths — to make it much more configurable.
I’m actually in the event you would have approached this a unique method. If that’s the case, please share within the feedback! It’d be neat to see what number of variations we are able to gather.