Tag: Gradients

Grainy Gradients

Browse through Dribbble or Behance, and you’ll find designers using a simple technique to add texture to an image: noise. Adding noise makes otherwise solid colors or smooth gradients, such as shadows, more realistic. But despite designers’ affinity for texture, noise is rarely used in web design.

In this article, we’ll generate colorful noise to add texture to a gradient with only a small amount of CSS and SVG. Alright, let’s make some noise!

Illustration by Hank Washington on Behance

Illustration by Jordan Kay on Dribbble

Interactive playground

Check it out here. The quickest way to understand what’s happening is to play with the parameters that make up the layers.

The trick: SVG noise and CSS gradients

The core technique in this article is built on top of a Stack Overflow answer by Chris Pachl to the question: Can you add noise to a CSS gradient?

The trick is to use an SVG filter to create the noise, then apply that noise as a background. Layer it underneath a gradient, boost the brightness and contrast, and that’s it — you have gradient that gradually dithers away.

The key ingredients

Here’s what we’re working with under the hood:

  • SVG turbulence: This is our noise filter.
  • Background with gradient and SVG: Next, we drop that filter into CSS as a background image that combines the filter with a CSS gradient.
  • Boost brightness and contrast: Then we turn to CSS filter to increase the brightness and contrast of the noise.
  • Blend gradients: Finally, we optionally use mix-blend-mode to further filter out colors and blend gradients together.

Let’s go into detail on each of these parts.

Using SVG turbulence

Within the realm of SVG, we can define filters, and one such filter lets us create Perlin noise. It’s called <feTurbulence> and we can define attributes, such as whether it is “turbulence” or “noise” and how fine or coarse it is. Bence Szabó explains it in much more detail as he demonstrates how it can be used to create patterns.

<svg viewBox="0 0 200 200" xmlns='http://www.w3.org/2000/svg'>   <filter id='noiseFilter'>     <feTurbulence        type='fractalNoise'        baseFrequency='0.65'        numOctaves='3'        stitchTiles='stitch' />   </filter>    <rect width='100%' height='100%' filter='url(#noiseFilter)' /> </svg>

This SVG example creates a filter and renders a <rect> element that we can use for our grainy gradients. Notice that the SVG <filter> is defined separately from the <rect>, and the <rect> simply references it.

Play around with changing some of the properties of <feTurbulence>

We’re going to save this SVG as a separate file. We reference an external link to grab the SVG in the demos throughout in this article. In practice, though, you would reference a local file or your own CDN. It doesn’t work to reference the SVG by its id in CSS, for some quirky reason, but you can inline the SVG, as we show in the playground demo. We don’t do this in the demos for legibility reasons.

Creating a CSS background with SVG and a gradient

After we have the SVG file stored somewhere we can reference it by a URL or path, we can now use it in a CSS background, combined with a gradient.

.noise {   /* ... */   background:     linear-gradient(to right, blue, transparent),     url(https://grainy-gradients.vercel.app/noise.svg); }

Order matters here. In this particular example, we want a solid color (i.e. no noise) to transition into noise and then into another color. We also want one end of the gradient to be transparent so that the noise shows through.

Like this:

However, this isn’t particularly nice because the noise is too muddled. We need to fray it and make it grainier. We can do that by…

Boosting the brightness and contrast

Adding a CSS filter makes the noise more stark, pushing the most faded colors towards white or black. The filter applies to the entire <div>, so the leftmost blue is a different blue than the pure blue we started with.

.noise {   /* ... */   background:      linear-gradient(to right, blue, transparent),      url(https://grainy-gradients.vercel.app/noise.svg);   filter: contrast(170%) brightness(1000%);   }

You can play around with how contrast and brightness affect the gradient. Boosting the brightness and contrast pushes out the muddled grays in the follow demo.

The noise is not uniform in color

If you zoom in, you’ll notice that the noise is made up of many colors. The SVG filter was colorful to begin with, and increasing the brightness and contrast emphasized certain colors. Although hardly noticeable, if this confetti is unwelcome, we can continue to filter out colors with CSS blending (i.e. mix-blend-mode and background-blend-mode ).

CSS blending

Let’s make a grainy gradient that transitions between two colors. CSS blending allows us to stack layers of color. In the next example, we’re adding another <div> to the markup, positioning it over the original gradient, then applying mix-blend-mode: multiply; to smooth things out.

<section>   <div class="isolate">     <div class="noise"></div>     <div class="overlay"></div>   </div> </section>
.noise {   /* ... */   background:      linear-gradient(20deg, rebeccapurple, transparent),      url(https://grainy-gradients.vercel.app/noise.svg);    contrast(170%) brightness(1000%); } .overlay {   /* ... */   background: moccasin;   mix-blend-mode: multiply; }

We can use the CSS isolation property to create a new stacking context and choose what gets blended. If we were to leave out isolation in the next example, the gradient and overlay would blend with the background color. Try it in the Pen and comment out that line!

/* Same as before */  .isolate {   isolation: isolate;   /* ... */ }

Some use cases

We’ve looked at a pretty simple example of how to make a noisy gradient, but where might you use one? Let’s consider several use cases.

Light and shadows, with grain

Where do gradients naturally occur? Light and shadows, for one. We can take advantage of the CSS property mix-blend-mode to smoothly blend gradients and selectively filter the colors we want to see in the noise.

In the “shadow” example, we create a dark gradient, and invert it to create the effect in the “light” example. In both cases, mix-blend-mode allows us to blend it with other gradients.

Holographic foil

The drastic brightness and contrast boost creates a rainbow effect that’s reminiscent of holographic foil.

Taking things further

Try the playground and mess around with the different parameters to see how they affect the texture.

Beyond that, here are some ways to continue fiddling with this technique:

  • Use a different SVG: All of the gradients in this article use the same SVG, but you can toy with the parameters that generates the noise to adjust the coarseness as well as the look and feel in the playground.
  • Try different gradients: Besides linear-gradient, CSS offers four more types of gradients. Can you name them? (Here’s one.)
  • Add more layers: With CSS blending, you can stack as many any layers as you’d like and blend them down.
  • Apply different SVG filters: There are all kinds of filters, including Gaussian blur and different types of lighting. Plus, they can be referenced in a CSS filter and applied to any element in addition to SVG.

What else can you think of? Please let us know what you discover in the comments.

Browser support

We can’t escape talking about browser support here. The core of this technique is supported by all modern browsers. As you might expect, it does not work in Internet Explorer. That said, Internet Explorer does support SVG as a background in CSS (just not with the actual CSS filter property).

SVG as a CSS background image

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
5 24 9 16 5

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
93 92 3 4.2-4.3

CSS filter effects

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
18* 35 No 79 6*

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
93 92 4.4* 6.0-6.1*

I’ve also noticed that Blink-based browsers (e.g. Safari) and WebKit-based one (e.g. Chrome) implement mix-blend-mode slightly differently, so please be sure to test across browsers if using CSS blending. In my own projects, I’ve used browser-specific media queries to manually reconcile the visual differences with small tweaks to CSS.

That’s it! Now that you have a grasp of SVG filters and how to combine them with CSS filters as a background, you have yet another neat visual effect to add depth and texture to a design.

The post Grainy Gradients appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



Variable Aspect Ratio Card With Conic Gradients Meeting Along the Diagonal

I recently came across an interesting problem. I had to implement a grid of cards with a variable (user-set) aspect ratio that was stored in a --ratio custom property. Boxes with a certain aspect ratio are a classic problem in CSS and one that got easier to solve in recent years, especially since we got aspect-ratio, but the tricky part here was that each of the cards needed to have two conic gradients at opposite corners meeting along the diagonal. Something like this:

A 3 by 3 grid of square cards with color backgrounds made from conic gradients. The gradients appear like stripes that extend from opposite corners of the card. Each card reads Hello Gorgeous in a fancy script font.
User set aspect ratio cards.

The challenge here is that, while it’s easy to make an abrupt change in a linear-gradient() along the diagonal of a variable aspect ratio box using for example a direction like to top left which changes with the aspect ratio, a conic-gradient() needs either an angle or a percentage representing how far it has gone around a full circle.

Check out this guide for a refresher on how conic gradients work.

The simple solution

The spec now includes trigonometric and inverse trigonometric functions, which could help us here — the angle of the diagonal with the vertical is the arctangent of the aspect ratio atan(var(--ratio)) (the left and top edges of the rectangle and the diagonal form a right triangle where the tangent of the angle formed by the diagonal with the vertical is the width over the height — precisely our aspect ratio).

Illustration. Shows a rectangle of width w and height h with a diagonal drawn from the bottom left corner to the top right one. This diagonal is the hypotenuse of the right triangle whose catheti are the left and top edges of the rectangle. In this right triangle, the tangent of the angle between the hypotenuse (diagonal of original rectangle) with the vertical (left edge of original rectangle) is the top edge (w) over the left edge (h).
The angle of the diagonal with the vertical (edge).

Putting it into code, we have:

--ratio: 3/ 2; aspect-ratio: var(--ratio); --angle: atan(var(--ratio)); background:    /* below the diagonal */   conic-gradient(from var(--angle) at 0 100%,        #319197, #ff7a18, #af002d  calc(90deg - var(--angle)), transparent 0%),    /* above the diagonal */   conic-gradient(from calc(.5turn + var(--angle)) at 100% 0,        #ff7a18, #af002d, #319197 calc(90deg - var(--angle)));

However, no browser currently implements trigonometric and inverse trigonometric functions, so the simple solution is just a future one and not one that would actually work anywhere today.

The JavaScript solution

We can of course compute the --angle in the JavaScript from the --ratio value.

let angle = Math.atan(1/ratio.split('/').map(c => +c.trim()).reduce((a, c) => c/a, 1)); document.body.style.setProperty('--angle', `$ {+(180*angle/Math.PI).toFixed(2)}deg`)

But what if using JavaScript won’t do? What if we really need a pure CSS solution? Well, it’s a bit hacky, but it can be done!

The hacky CSS solution

This is an idea I got from a peculiarity of SVG gradients that I honestly found very frustrating when I first encountered.

Let’s say we have a gradient with a sharp transition at 50% going from bottom to top since in CSS, that’s a gradient at a angle. Now let’s say we have the same gradient in SVG and we change the angle of both gradients to the same value.

In CSS, that’s:

linear-gradient(45deg, var(--stop-list));

In SVG, we have:

<linearGradient id='g' y1='100%' x2='0%' y2='0%'                  gradientTransform='rotate(45 .5 .5)'>   <!-- the gradient stops --> </linearGradient>

As it can be seen below, these two don’t give us the same result. While the CSS gradient really is at 45°, the SVG gradient rotated by the same 45° has that sharp transition between orange and red along the diagonal, even though our box isn’t square, so the diagonal isn’t at 45°!

Screenshot. Shows a rectangle with a CSS gradient at 45° (left) vs. a rectangle with a bottom to top SVG gradient rotated by 45° (right). This angle is adjustable via the slider at the bottom. The CSS gradient is really at 45°, but the line of the SVG gradient is perpendicular onto the rectangle's diagonal.
45° CSS vs. SVG gradient (live demo).

This is because our SVG gradient gets drawn within a 1x1 square box, rotated by 45°, which puts the abrupt change from orange to red along the square diagonal. Then this square is stretched to fit the rectangle, which basically changes the diagonal angle.

Note that this SVG gradient distortion happens only if we don’t change the gradientUnits attribute of the linearGradient from its default value of objectBoundingBox to userSpaceOnUse.

Basic idea

We cannot use SVG here since it only has linear and radial gradients, but not conic ones. However, we can put our CSS conic gradients in a square box and use the 45° angle to make them meet along the diagonal:

aspect-ratio: 1/ 1; width: 19em; background:    /* below the diagonal */   conic-gradient(from 45deg at 0 100%,        #319197, #ff7a18, #af002d 45deg, transparent 0%),    /* above the diagonal */   conic-gradient(from calc(.5turn + 45deg) at 100% 0,        #ff7a18, #af002d, #319197 45deg);

Then we can stretch this square box using a scaling transform – the trick is that the ‘/’ in the 3/ 2 is a separator when used as an aspect-ratio value, but gets parsed as division inside a calc():

--ratio: 3/ 2; transform: scaley(calc(1/(var(--ratio))));

You can play with changing the value of --ratio in the editable code embed below to see that, this way, the two conic gradients always meet along the diagonal:

Note that this demo will only work in a browser that supports aspect-ratio. This property is supported out of the box in Chrome 88+ (current version is 90), but Firefox still needs the layout.css.aspect-ratio.enabled flag to be set to true in about:config. And if you’re using Safari… well, I’m sorry!

Screenshot showing how to enable the Firefox flag. Go to about:config (type that in the address bar - you may be asked if you're sure you want to mess with that stuff before you're allowed to enter). Use the search bar to look for 'aspect' - this should be enough to bring up the flag. Set its value to true.
Enabling the flag in Firefox.

Issues with this approach and how to get around them

Scaling the actual .card element would rarely be a good idea though. For my use case, the cards are on a grid and setting a directional scale on them messes up the layout (the grid cells are still square, even though we’ve scaled the .card elements in them). They also have text content which gets weirdly stretched by the scaley() function.

Screenshot. Shows how the card elements are scaled down vertically, yet the grid cells they're occupying have remained square, just like the cards before the directional scaling.

The solution is to give the actual cards the desired aspect-ratio and use an absolutely positioned ::before placed behind the text content (using z-index: -1) in order to create our background. This pseudo-element gets the width of its .card parent and is initially square. We also set the directional scaling and conic gradients from earlier on it. Note that since our absolutely positioned ::before is top-aligned with the top edge of its .card parent, we should also scale it relative to this edge as well (the transform-origin needs to have a value of 0 along the y axis, while the x axis value doesn’t matter and can be anything).

body {   --ratio: 3/ 2;   /* other layout and prettifying styles */ }  .card {   position: relative;   aspect-ratio: var(--ratio);    &::before {     position: absolute;     z-index: -1; /* place it behind text content */      aspect-ratio: 1/ 1; /* make card square */     width: 100%;     	     /* make it scale relative to the top edge it's aligned to */     transform-origin: 0 0;     /* give it desired aspect ratio with transforms */     transform: scaley(calc(1/(var(--ratio))));     /* set background */     background:        /* below the diagonal */       conic-gradient(from 45deg at 0 100%,        #319197, #af002d, #ff7a18 45deg, transparent 0%),        /* above the diagonal */       conic-gradient(from calc(.5turn + 45deg) at 100% 0,        #ff7a18, #af002d, #319197 45deg);     content: '';   } }

Note that we’ve moved from CSS to SCSS in this example.

This is much better, as it can be seen in the embed below, which is also editable so you can play with the --ratio and see how everything adapts nicely as you change its value.

Padding problems

Since we haven’t set a padding on the card, the text may go all the way to the edge and even slightly out of bounds given it’s a bit slanted.

Screenshot. Shows a case where the text goes all the way to the edge of the card and even goes out a tiny little bit creating an ugly result.
Lack of padding causing problems.

That shouldn’t be too difficult to fix, right? We just add a padding, right? Well, when we do that, we discover the layout breaks!

Animated gif. Shows the dev tools grid overlay t highlight that, while the background (created with the scaled pseudo) still has the desired aspect ratio, the grid cell and the actual card in it are taller.
Adding a padding breaks the layout. (Demo)

This is because the aspect-ratio we’ve set on our .card elements is that of the .card box specified by box-sizing. Since we haven’t explicitly set any box-sizing value, its current value is the default one, content-box. Adding a padding of the same value around this box gives us a padding-box of a different aspect ratio that doesn’t coincide with that of its ::before pseudo-element anymore.

In order to better understand this, let’s say our aspect-ratio is 4/ 1 and the width of the content-box is 16rem (256px). This means the height of the content-box is a quarter of this width, which computes to 4rem (64px). So the content-box is a 16rem×4rem (256px×64px) rectangle.

Now let’s say we add a padding of 1rem (16px) along every edge. The width of the padding-box is therefore 18rem (288px, as it can be seen in the animated GIF above) — computed as the width of the content-box, which is 16rem (256px) plus 1rem (16px) on the left and 1rem on the right from the padding. Similarly, the height of the padding-box is 6rem (96px) — computed as the height of the content-box, which is 4rem (64px), plus 1rem (16px) at the top and 1rem at the bottom from the padding).

This means the padding-box is a 18rem×6rem (288px×96px) rectangle and, since 18 = 3⋅6, it has a 3/ 1 aspect ratio which is different from the 4/ 1 value we’ve set for the aspect-ratio property! At the same time, the ::before pseudo-element has a width equal to that of its parent’s padding-box (which we’ve computed to be 18rem or 288px) and its aspect ratio (set by scaling) is still 4/ 1, so its visual height computes to 4.5rem (72px). This explains why the background created with this pseudo — scaled down vertically to a 18rem×4.5rem (288px×72px) rectangle — is now shorter than the actual card — a 18rem×6rem (288px×96px) rectangle now with the padding.

So, it looks like the solution is pretty straightforward — we need to set box-sizing to border-box to fix our problem as this applied the aspect-ratio on this box (identical to the padding-box when we don’t have a border).

Sure enough, this fixes things… but only in Firefox!

Screenshot collage. Shows how the text is not middle aligned in Chromium browsers (top), while Firefox (bottom) gets this right.
Showing the difference between Chromium (top) and Firefox (bottom).

The text should be middle-aligned vertically as we’ve given our .card elements a grid layout and set place-content: center on them. However, this doesn’t happen in Chromium browsers and it becomes a bit more obvious why when we take out this last declaration — somehow, the cell in the card’s grid gets the 3/ 1 aspect ratio too and overflows the card’s content-box:

Animated gif. For some reason, the grid cell inside the card gets the set aspect ratio and overflows the card's content-box.
Checking the card’s grid with vs. without place-content: center.

Fortunately, this is a known Chromium bug that should probably get fixed in the coming months.

In the meantime, what we can do to get around this is remove the box-sizing, padding and place-content declarations from the .card element, move the text in a child element (or in the ::after pseudo if it’s just a one-liner and we’re lazy, though an actual child is the better idea if we want the text to stay selectable) and make that a grid with a padding.

.card {   /* same as before,       minus the box-sizing, place-content and padding declarations       the last two of which which we move on the child element */      &__content {     place-content: center;     padding: 1em   } }

Rounded corners

Let’s say we also want our cards to have rounded corners. Since a directional transform like the scaley on the ::before pseudo-element that creates our background also distorts corner rounding, it results that the simplest way to achieve this is to set a border-radius on the actual .card element and cut out everything outside that rounding with overflow: hidden.

Screenshot. Shows an element that's not scaled at all on the left. This has a perfectly circular border-radius. In the right, there's a non-uniform scaled element - its border-radius is not perfectly circular anymore, but instead distorted by the scaling.
Non-uniform scaling distorts corner rounding. (Demo)

However, this becomes problematic if at some point we want some other descendant of our .card to be visible outside of it. So, what we’re going to do is set the border-radius directly on the ::before pseudo that creates the card background and reverse the directional scaling transform along the y axis on the y component of this border-radius:

$ r: .5rem;  .card {   /* same as before */      &::before {     border-radius: #{$ r}/ calc(#{$ r}*var(--ratio));     transform: scaley(calc(1/(var(--ratio))));     /* same as before */   } }

Final result

Putting it all together, here’s an interactive demo that allows changing the aspect ratio by dragging a slider – every time the slider value changes, the --ratio variable is updated:

The post Variable Aspect Ratio Card With Conic Gradients Meeting Along the Diagonal appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , , , , ,

The “Gray Dead Zone” of Gradients

Erik D. Kennedy notes an interesting phenomenon of color gradients. If you have a gradient between two colors where the line between them in the color space goes through the zero-saturation middle, you get this “gray dead zone” in the middle.

It’s a real thing. See the gray middle here:

You can also see how colors might not do that, like red and blue here shooting right through purple instead, which you can visualize on that color circle above.

Erik says one solution can be taking a little detour instead of going straight through the gray zone:

His updated gradient tool deals with this by using different “interpolation modes” and easing the gradient with a choice of precision stops. Don’t miss the radial and conic options as well, with the ability to place the centers “offscreen” which can yield pretty cool looks you can’t do any other way.

Oh and speaking of conic gradients, Adam Argyle has a little gallery of possibilities that is pretty unique.

The post The “Gray Dead Zone” of Gradients appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , ,

A Complete Guide to CSS Gradients

The background-size property in CSS is one of the most useful — and most complex — of the background properties. There are many variations and different syntaxes you can use for this property, all of which have different use cases. Here’s a basic example:

html {   background: url(greatimage.jpg);   background-size: 300px 100px;  }

That’s an example of the two-value syntax for background size. There are four different syntaxes you can use with this property: the keyword syntax, the one-value syntax, the two-value syntax, and the multiple background syntax.


In addition to the default value (auto), there are two keywords you can use with background-size: cover and contain

The difference

cover tells the browser to make sure the image always covers the entire container, even if it has to stretch the image or cut a little bit off one of the edges. contain, on the other hand, says to always show the whole image, even if that leaves a little space to the sides or bottom.

The default keyword — auto — tells the browser to automatically calculate the size based on the actual size of the image and the aspect ratio.

One Value

If you only provide one value (e.g. background-size: 400px) it counts for the width, and the height is set to auto. You can use any CSS size units you like, including pixels, percentages, ems, viewport units, etc.

Two Values

If you provide two values, the first sets the background image’s width and the second sets the height. Like the single value syntax, you can use whatever measurement units you like.

Multiple Images

You can also combine any of the above methods and apply them to multiple images, simply by adding commas between each syntax. Example:

html {   background: url(greatimage.jpg), url(wonderfulimage.jpg);   background-size: 300px 100px, cover;   /* first image is 300x100, second image covers the whole area */ }

Keep background image stacking order in mind when using multiple images.


This demo shows examples of cover, contain, and multiple background images with a mix of pixel and keyword values.

See the Pen background-size by CSS-Tricks (@css-tricks) on CodePen.


More Resources

Browser Support

Chrome Safari Firefox Opera IE Android iOS
3+ 4.1+ 3.6+ 10+ 9+ 2.3+ 4.0+

The post A Complete Guide to CSS Gradients appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, ,

Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis

You can create stripes in CSS. That’s all I thought about in terms of CSS background patterns for a long time. There’s nothing wrong with stripes; stripes are cool. They can be customized into wide and narrow bands, criss-crossed into a checked pattern, and played with in other ways using the idea of hard stops. But stripes can be boring, too. Too conventional, out of fashion, and sometimes even unpleasant.

Thankfully, we can conjure up far more background patterns than you can even imagine with CSS, with code that is similar in spirit to stripes.

Background patterns are images repeated across a background. They can be done by referencing an external image, like a PNG file, or can be drawn with CSS, which is traditionally done using CSS gradients. 

Linear gradients (and repeating linear gradients) for instance, are typically used for stripes. But there are other ways to create cool background patterns. Let’s see how we can use gradients in other ways and toss in other things, like CSS shapes and emoji, to spice things up.

Gradient patterns

There are three types of CSS gradients.

Linear (left), radial (center) and conic (right) gradients
  1. linear-gradient(): Colors flow from left-to-right, top-to-bottom, or at any angle you choose in a single direction.
  2. radial-gradient(): Colors start at a single point and emanate outward
  3. conic-gradient(): Similar in concept to radial gradients, but the color stops are placed around the circle rather than emanating from the center point.

I recommend checking out the syntax for all the gradients to thoroughly understand how to start and end a color in a gradient.

Radial gradient patterns

Let’s look at radial gradients first because they give us very useful things: circles and ellipses. Both can be used for patterns that are very interesting and might unlock some ideas for you!

background: radial-gradient(<gradient values>)

Here’s a pattern of repeating watermelons using this technique:

background:  	radial-gradient(circle at 25px 9px, black 2px, transparent 2px),  	radial-gradient(circle at 49px 28px, black 2px, transparent 2px),  	radial-gradient(circle at 38px 1px, black 2px, transparent 2px),  	radial-gradient(circle at 20px 4px, black 2px, transparent 2px),  	radial-gradient(circle at 80px 4px, black 2px, transparent 2px),  	radial-gradient(circle at 50px 10px, black 2px, transparent 2px),  	radial-gradient(circle at 60px 16px, black 2px, transparent 2px),  	radial-gradient(circle at 70px 16px, black 2px, transparent 2px),  	radial-gradient(ellipse at 50px 0, red 33px, lime 33px, lime 38px, transparent 38px)  	white; background-size: 100px 50px;

We start by providing a background size on the element then stack up the gradients inside it. An ellipse forms the green and red parts. Black circles are scattered across to represent the watermelon seeds. 

The first two parameters for a radial gradient function determine whether the gradient shape is a circle or an ellipse and the starting position of the gradient. That’s followed by the gradient color values along with the start and ending positions within the gradient.

Conic gradient patterns

Conic gradients create ray-like shapes. Like linear and radial gradients, conic gradients can be used to create geometric patterns.

background: conic-gradient(<gradient values>)
background:    conic-gradient(yellow 40deg, blue 40deg, blue 45deg, transparent 45deg),    conic-gradient(transparent 135deg, blue 135deg, blue 140deg, transparent 140deg) ; background-size: 60px 60px; background-color: white;

The rub with conic gradient is that it’s not supported in Firefox, at least at the time of writing. It’s always worth keeping an eye out for deeper support.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
69 No No 79 12.1

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
81 No 81 12.2-12.4

Emoji icon patterns

This is where things begin to get interesting. Rather than just using geometric patterns (as in gradients), we now use the organic shapes of emojis to create background patterns. 🎉 

It starts with emoji icons. 

Solid-color emoji patterns

We can create emoji icons by giving emojis a transparent color and text shadow.

color: transparent; text-shadow: 0 0 black;

Those icons can then be turned into an image that can be used as a background, using SVG.

<svg>   <foreignObject>     <!-- The HTML code with emoji -->   </foreignObject> </svg>

The SVG can then be referred by the background property using data URL

background: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><!-- SVG code --></svg>");

And, voilá! We get something like this:

background:      url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><foreignObject width=%22100px%22 height=%22100px%22><div xmlns=%22http://www.w3.org/1999/xhtml%22 style=%22color:transparent;text-shadow: 0 0 %23e42100, -2px 2px 0 black;font-size:70px%22>🏄‍♀️</div></foreignObject></svg>"),      white;  background-size: 60px 60px; 

Other than emojis, it’s also possible to draw CSS shapes and use them as patterns. Emojis are less work, though. Just saying. 

Gradient-colored emoji patterns

Instead of using plain emoji icons, we can use gradient emoji icons. To do that, skip the text shadow on the emojis. Add a gradient background behind them and use background-clip to trim the gradient background to the shape of the emojis. 

color: transparent; background: linear-gradient(45deg, blue 20%, fuchsia); background-clip: text; /* Safari requires -webkit prefix */

Then, just as before, use the combination of SVG and data URL to create the background pattern.

Translucent-colored emoji patterns

This is same as using block colored emoji icons. This time, however, we take away the opaqueness of the colors by using rgba() or hsla() values for the text shadow. 

color: transparent; text-shadow: 20px 10px rgba(0, 255, 0, .3),               0 0 red;

SVG-text emoji patterns

We’ve already looked at all the working methods I could think of to create background patterns, but I feel like I should also mention this other technique I tried, which is not as widely supported as I’d hoped.

 I tried placing the emoji in an SVG <text> element instead of the HTML added using <foreignObject>. But I wasn’t able to create a solid shadow behind it in all the browsers.

background:    url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%221em%22 font-size=%2270%22 fill=%22transparent%22 style=%22text-shadow: 0 0 %23e42100, -2px 2px 5px black, 0 0 6px white; ;%22>🏄‍♀️</text></svg>") 

Just in case, I tried using CSS and SVG filters for the shadow as well, thinking that might work. It didn’t. I also tried using the stroke attribute, to at least create an outline for the emoji, but that didn’t work, either. 

CSS element() patterns

I didn’t think of SVG when I first thought of converting emoji icons or CSS shapes into background images. I tried CSS element(). It’s a function that directly converts an HTML element into an image that can be referenced and used. I really like this approach, but browser support is a huge caveat, which is why I’m mentioning it here at the end.

Basically, we can drop an element in the HTML like this:

<div id=snake >🐍</div>

…then pass it into the element() function to use like an image on other elements, like this:

background:    -moz-element(#snake), /* Firefox only */   linear-gradient(45deg, transparent 20px, blue 20px, blue 30px, transparent 30px)    white; background-size: 60px 60px; background-color: white;

Now that snake emoji is technically an image that we get to include in the pattern.

Again, browser support is spotty, making this approach super experimental.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
No 4* No No No

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
No 68* No No

In this method, the original emoji (or any CSS shape for that matter) used for the background pattern needs to render on screen for it to appear in the background pattern as well. To hide that original emoji, I used mix-blend-mode — it sort of masks out the original emoji in the HTML so it doesn’t show up on the page.

I hope you find the methods in this post useful in one way or another and learned something new in the process! Give them a try. Experiment with different emojis and CSS shapes because gradients, while cool and all, aren’t the only way to make patterns.. The background property takes multiple values, allowing us to think of creative ways to stack things.

The post Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis appeared first on CSS-Tricks.


, , , , , , ,

Background Patterns, Simplified by Conic Gradients

For those who have missed the big news, Firefox now supports conic gradients!

Starting with Firefox 75, released on the April 7, we can go to about:config, look for the layout.css.conic-gradient.enabled flag and set its value to true (it’s false by default and all it takes to switch is double-clicking it).

Screenshot. Shows the Firefox URL bar at `about:config`, a search for 'conic' giving the `layout.css.conic-gradient.enabled` flag as the sole result and its value set to `true`.
Enabling conic gradients in Firefox 75+

With that enabled, now we can test our CSS including conic gradients in Firefox as well.

While some of the demos in this article work just fine when using a polyfill, some use CSS variables inside the conic gradient and therefore require native support for this feature.

One thing I particularly like about conic gradients is just how much they can simplify background patterns. So let’s take a few linear-gradient() patterns from the gallery created by Lea Verou about a decade ago and see how we can now simplify them with conic-gradient!


Screenshot. Shows the original pyramid pattern with the code that was used to create it.
The pyramid pattern

The pattern above uses four linear gradients:

background:   linear-gradient(315deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(45deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(135deg, #a7332b 50%, transparent 0) 0 0,   linear-gradient(45deg, #6a201b 50%, #561a16 0) 0 0 #561a16; background-size: 20px 20px;

That’s quite a bit of CSS and perhaps even a bit intimidating. It’s not easy to just look at this and understand how it all adds up to give us the pyramid pattern. I certainly couldn’t do it. It took me a while to get it, even though gradients are one of the CSS features I’m most comfortable with. So don’t worry if you don’t understand how those gradients manage to create the pyramid pattern because, one, it is complicated and, two, you don’t even need to understand that!

Using conic-gradient(), we can now get the same result in a much simpler manner, with a single background layer instead of four!

What I like to do when coding repeating patterns is draw equidistant vertical and horizontal lines delimiting the rectangular boxes defined by the background-size. In this case, it’s pretty obvious we have square boxes and where their limits are, but it’s a really useful technique for more complex patterns.

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

By default, conic gradients start from 12 o’clock and go clockwise. However, in our case, we want to offset the start of the gradient by 45° in the clockwise direction and afterwards make every one of the four shades occupy a quarter (25%) of the available space around the midpoint of our square box.

SVG illustration. Shows how we place a conic gradient into a single pattern cell by rotating the gradient start point 45° in the clockwise (positive) direction.
A pattern cell with a conic gradient’s hard stops at every 25% starting from 45° w.r.t. the vertical axis (live).

This means our pyramid pattern can be reduced to:

$ s: 20px; background:   conic-gradient(from 45deg,      #561a16 25%,      #6a201b 0% 50%,      #a7332b 0% 75%,      #d45d55 0%)      50%/ #{$ s $ s};

Not only does the code look simpler, but we’ve also gone from 260 bytes to 103 bytes, reducing the code needed to get this pattern by more than half.

We’re using the double position syntax as that’s also well supported these days.

We can see it in action in the Pen below:


Screenshot. Shows the original checkerboard pattern with the code that was used to create it.
The checkerboard pattern

This pattern above is created with two linear gradients:

background-color: #eee; background-image:   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px; background-position: 0 0, 30px 30px;

Let’s see how we can simplify this CSS when replacing these linear gradients with a conic one!

Just like in the previous case, we draw vertical and horizontal lines in order to better see the rectangles defined by the background-size.

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

Looking at the square highlighted in deeppink in the illustration above, we see that, in this case, our conic gradient starts from the default position at 12 o’clock. A quarter of it is black, the next quarter is dirty white and then we have repetition (the same black and then dirty white quarter slices once more).

SVG illustration. Shows how we place a conic gradient into a single pattern cell and then make it repeat after the 50% point.
A pattern cell with a conic gradient’s hard stops at every 25%, starting from the default at 12 o’clock and repeating after 50% (demo).

This repetition in the second half of the [0%, 100%] interval means we can use a repeating-conic-gradient(), which gives us the following code (bringing the compiled CSS from 263 bytes down to only 73 bytes – that’s reducing it by over 70%):

$ s: 60px; background:   repeating-conic-gradient(#000 0% 25%, #eee 0% 50%)      50%/ #{$ s $ s};

The Pen below shows it in action:

Diagonal checkerboard

Screenshot. Shows the original diagonal checkerboard pattern with the code that was used to create it.
The diagonal checkerboard pattern

Again, we have a pattern created with two linear gradients:

background-color: #eee; background-image:    linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(-45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px;

We draw horizontal and vertical lines to split this pattern into identical rectangles:

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

What we now have is pretty much the same checkerbox pattern as before, with the sole difference that we don’t start from the default position at 12 o’clock, but from 45° in the clockwise direction.

If you’re having trouble visualising how simply changing the start angle can make us go from the previous pattern to this one, you can play with it in the interactive demo below:

Note that this demo does not work in browsers that have no native support for conic gradients.

This means our code looks as follows:

$ s: 60px; background:   repeating-conic-gradient(from 45deg,      #000 0% 25%, #eee 0% 50%)    50%/ #{$ s $ s};

We can see it in action below:

Again, not only is the code simpler to understand, but we’ve also gone from 229 bytes to only 83 bytes in the compiled CSS, reducing it by almost two-thirds!


Screenshot. Shows the original Half-Rombes pattern with the code that was used to create it.
The half-rombes pattern

This pattern was created with four linear gradients:

background: #36c; background:   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   #36c; background-size: 15px 30px;

Just like in the previous cases, we draw equidistant vertical and horizontal lines in order to better see the repeating unit:

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells.

What we have here is a pattern that’s made up of congruent isosceles triangles (the angled edges are equal and the dark blue triangles are a reflection of the light blue ones) formed by the intersection of equidistant parallel lines that are either horizontal, angled clockwise, or the other way. Each of these three types of parallel lines is highlighted in the illustration below:

Illustration. Shows the equidistant parallel lines which create the pattern of isosceles triangles.
Parallel guides

Every pattern cell contains a full triangle and two adjacent triangle halves in the upper part, then a reflection of this upper part in the lower part. This means we can identify a bunch of congruent right triangles that will help us get the angles we need for our conic-gradient():

SVG illustration. Shows how we place a conic gradient into a single pattern cell by rotating the gradient start point by an angle β in the clockwise (positive) direction such that the 0% line goes through the top right corner and then all the other hard stops are either horizontal or going through the cell corners.
A pattern cell with a conic gradient’s hard stops such that they’re either horizontal or go through the cell corners, all starting from β w.r.t. the vertical axis (demo)

This illustration shows us that the gradient starts from an angle, β, away from the default conic gradient start point at 12 o’clock. The first conic slice (the top right half triangle) goes up to α, the second one (the bottom right dark triangle) up to 2·α, and the third one (the bottom light triangle) goes halfway around the circle from the start (that’s 180°, or 50%). The fourth one (the bottom left dark triangle) goes to 180° + α and the fifth one (the top left light triangle) goes to 180° + 2·α, while the sixth one covers the rest.

SVG illustration. Highlights the right triangle from where we can get α knowing the catheti and shows how we can then compute β.
Getting α and β (demo)

From the highlighted right triangle we get that:

tan(α) = (.5·h)/(.5·w) = h/w

Knowing the width (w) and height (h) of a pattern cell, we can get the angles α and β:

α = atan(h/w) β = 90° - α

It results in the pattern that’s generated by the following code:

$ w: 15px; $ h: 30px; $ a: atan($ h/$ w)*180deg/pi(); $ b: 90deg - $ a; $ c0: #36c; $ c1: #d6e0f5;  html {   background:      conic-gradient(from $ b,        $ c1 0% $ a,        $ c0 0% 2*$ a,        $ c1 0% 50%,        $ c0 0% 180deg + $ a,        $ c1 0% 180deg + 2*$ a,        $ c0 0%)      0 0/ #{$ w $ h}; }

This means going from 343 bytes to only 157 bytes in the compiled CSS. The result can be seen below:

You can tweak the pattern width ($ w) and height ($ h) in the Sass code in order to see how the pattern gets squished and stretched for different aspect ratios.

In the particular case where the angle between 2*$ a and 50% (or 180deg) is also $ a, it results that $ a is 60deg, our isosceles triangles are equilateral, and our gradient can be reduced to a repeating one (and under 100 bytes in the compiled CSS):

$ a: 60deg; $ b: 90deg - $ a; $ w: 15px; $ h: $ w*tan($ a); $ c0: #36c; $ c1: #d6e0f5;  html {   background:      repeating-conic-gradient(from $ b,        $ c1 0% $ a, $ c0 0% 2*$ a)      0 0/ #{$ w $ h} }

The live result can be seen below:

Bonus: Intersecting line backgrounds!

Screenshot. Shows the original intersecting lines pattern with the code that was used to create it.
Intersecting line background examples

While these are not repeating patterns, they’re examples of a situation where a single conic gradient achieves an effect that would have previously needed a bunch of linear ones.

What we have here is a conic-gradient() created starting from two straight lines intersecting within the rectangular box where we set the background.

SVG illustration. Shows a rectangular box and two random lines intersecting inside it. This intersection point (x,y) is the point the conic gradient goes around, while the gradient's start is from the angle β formed by the line segment closest to the top right corner with the vertical. The hard stops are at α, the angle between the start segment and the next one in clockwise order, at 50% and at 180° + α.
Bonus pattern structure (ldemo)

The gradient goes around the point of coordinates, x,y, where the two straight lines intersect. It starts from an angle, β, which is the angle of the line segment that’s closest to the top-right corner, then has hard stops at α, 50% (or 180°) and 180° + α.

If we want to have multiple elements with similar such patterns created with the help of different intersecting lines and different palettes, we have the perfect use case for CSS variables:

.panel {   background:      conic-gradient(from var(--b) at var(--xy),        var(--c0) var(--a), var(--c1) 0% 50%,        var(--c2) 0% calc(180deg + var(--a)), var(--c3) 0%); }

All we have to do is set the position (--xy), the start angle (--b), the first angle (--a) and the palette (--c0 through --c3).

.panel {   /* same as before */      &:nth-child(1) {     --xy: 80% 65%;      --b: 31deg;     --a: 121deg;      --c0: #be5128;     --c1: #ce9248;     --c2: #e4c060;     --c3: #db9c4e   }      /* similarly for the other panels */ }

Instead of hardcoding, we could also generate these values randomly or extract them from a data object with the help of a CSS or HTML preprocessor. In this second case, we’d set these custom properties inline, which is precisely what I did in the Pen below:

Since we’re using custom properties inside the conic gradients, this demo does not work in browsers that don’t support them natively.

Well, that’s it! I hope you’ve enjoyed this article and that it gives you some ideas about how conic gradients can make your life easier.

The post Background Patterns, Simplified by Conic Gradients appeared first on CSS-Tricks.


, , , ,

While You Weren’t Looking, CSS Gradients Got Better

One thing that caught my eye on the list of features for Lea Verou’s conic-gradient() polyfill was the last item:

Supports double position syntax (two positions for the same color stop, as a shortcut for two consecutive color stops with the same color)

Surprisingly, I recently discovered most people aren’t even aware that double position for gradient stops is something that actually exists in the spec, so I decided to write about it.

According to the spec:

Specifying two locations makes it easier to create solid-color “stripes” in a gradient, without having to repeat the color twice.

I completely agree, this was the first thing I thought of when I became aware of this feature.

Let’s say we want to get the following result: a gradient with a bunch of equal width vertical stripes (which I picked up from an earlier post by Chris):

Screenshot. Shows 8 vertical rainbow stripes, from left to right: violet, magenta, red, orange, yellow, yellowish green, teal, blue.
Desired gradient result.

The hex values are: #5461c8, #c724b1, #e4002b, #ff6900, #f6be00, #97d700, #00ab84 and #00a3e0.

Let’s first see how we’d CSS this without using double stop positions!

We have eight stripes, which makes each of them one-eighth of the gradient width. One eighth of 100% is 12.5%, so we go from one to the next at multiples of this value.

This means our linear-gradient() looks as follows:

linear-gradient(90deg,               #5461c8 12.5% /* 1*12.5% */,    #c724b1 0, #c724b1 25%   /* 2*12.5% */,    #e4002b 0, #e4002b 37.5% /* 3*12.5% */,    #ff6900 0, #ff6900 50%   /* 4*12.5% */,    #f6be00 0, #f6be00 62.5% /* 5*12.5% */,    #97d700 0, #97d700 75%   /* 6*12.5% */,    #00ab84 0, #00ab84 87.5% /* 7*12.5% */,    #00a3e0 0)

Note that we don’t need to repeat stop position % values because, whenever a stop position is smaller than a previous one, we automatically have a sharp transition. That’s why it’s always safe to use 0 (which is always going to be smaller than any positive value) and have #c724b1 25%, #e4002b 0 instead of #c724b1 25%, #e4002b 25%, for example. This is something that can make our life easier in the future if, for example, we decide we want to add two more stripes and make the stop positions multiples of 10%.

Not too bad, especially compared to what gradient generators normally spit out. But if we decide one of those stripes in the middle doesn’t quite fit in with the others, then changing it to something else means updating in two places.

Again, not too bad and nothing we can’t get around with a little bit of help from a preprocessor:

$  c: #5461c8 #c724b1 #e4002b #ff6900 #f6be00 #97d700 #00ab84 #00a3e0;  @function get-stops($  c-list) {   $  s-list: ();   $  n: length($  c-list);   $  u: 100%/$  n; 	   @for $  i from 1 to $  n {     $  s-list: $  s-list,               nth($  c-list, $  i) $  i*$  u,               nth($  c-list, $  i + 1) 0   }    @return $  s-list }  .strip {   background: linear-gradient(90deg, get-stops($  c))) }

This generates the exact CSS gradient we saw a bit earlier and now we don’t have to modify anything in two places anymore.

See the Pen by thebabydino (@thebabydino) on CodePen.

However, even if a preprocessor can save us from typing the same thing twice, it doesn’t eliminate repetition from the generated code.

And we may not always want to use a preprocessor. Leaving aside the fact that some people are stubborn or have an irrational fear or hate towards preprocessors, it sometimes feels a bit silly to use a loop.

For example, when we barely have anything to loop over! Let’s say we want to get a much simpler background pattern, such as a diagonal hashes one, which I’d imagine is a much more common use case than an over-the-top rainbow one that’s probably not a good fit on most websites anyway.

Screenshot. Shows a pattern of diagonal light grey hashes on a white background.
Desired hashes result

This requires using repeating-linear-gradient() and this means a bit of repetition, even if we don’t have the same long list of hex values as we did before:

repeating-linear-gradient(-45deg,      #ccc /* can't skip this, repeating gradient won't work */,      #ccc 2px,      transparent 0,      transparent 9px /* can't skip this either, tells where gradient repetition starts */)

Here, we cannot ditch the first and last stops because those are precisely what indicate how the gradient repeats within the rectangle defined by the background-size.

If you want to understand why it’s better to use repeating-linear-gradient() instead of a plain old linear-gradient() combined with the proper background-size in order to create such hashes, check out this other article I wrote a while ago.

This is precisely where such feature comes to the rescue — it allows us to avoid repetition in the final CSS code.

For the rainbow stripes case, our CSS becomes:

linear-gradient(90deg,      #5461c8 12.5%,      #c724b1 0 25%,      #e4002b 0 37.5%,      #ff6900 0 50%,      #f6be00 0 62.5%,      #97d700 0 75%,      #00ab84 0 87.5%,      #00a3e0 0)

And to recreate the hashes, we only need:

repeating-linear-gradient(-45deg,      #ccc 0 2px,      transparent 0 9px)

See the Pen by thebabydino (@thebabydino) on CodePen.

What about support? Well, glad you asked! It actually happens to be pretty good! It works in Safari, Chromium browsers (which now includes Edge as well!) and Firefox. Pre-Chromium Edge and maybe some mobile browsers could still hold you back, but if you don’t have to worry about providing support for every browser under the sun or it’s fine to provide a fallback, go ahead and start using this!

The post While You Weren’t Looking, CSS Gradients Got Better appeared first on CSS-Tricks.


, , ,