惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
AWS News Blog
AWS News Blog
P
Privacy & Cybersecurity Law Blog
H
Help Net Security
云风的 BLOG
云风的 BLOG
G
GRAHAM CLULEY
Spread Privacy
Spread Privacy
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
Project Zero
Project Zero
Engineering at Meta
Engineering at Meta
P
Privacy International News Feed
Blog — PlanetScale
Blog — PlanetScale
Stack Overflow Blog
Stack Overflow Blog
M
MIT News - Artificial intelligence
The Register - Security
The Register - Security
Recorded Future
Recorded Future
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
PCI Perspectives
PCI Perspectives
Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
A
About on SuperTechFans
W
WeLiveSecurity
GbyAI
GbyAI
V
Vulnerabilities – Threatpost
The GitHub Blog
The GitHub Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Check Point Blog
Y
Y Combinator Blog
月光博客
月光博客
Scott Helme
Scott Helme
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
U
Unit 42
G
Google Developers Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Threatpost
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
博客园 - 司徒正美

CSS Articles by Temani Afif

Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks Let’s Play With Gap Decorations! How to Control Infinite CSS Animations (Part 2 of 2) How to Control Infinite CSS Animations (Part 1 of 2) Two Circles, One Arrow, and Anchor Positioning Making a Responsive Pyramidal Grid With Modern CSS | CSS-Tricks How to Create a CSS-only Elastic Text Effect Making Complex CSS Shapes Using shape() | CSS-Tricks Responsive Hexagon Grid Using Modern CSS | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 2) | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 1) | CSS-Tricks Perfectly Pointed Tooltips: To The Corners Perfectly Pointed Tooltips: All Four Sides Perfectly Pointed Tooltips: A Foundation Sequential linear() Animation With N Elements | CSS-Tricks Infinite Marquee Animation using Modern CSS Better CSS Shapes Using shape() — Part 4: Close and Move | CSS-Tricks Drawing CSS Shapes using corner-shape Better CSS Shapes Using shape() — Part 3: Curves | CSS-Tricks Better CSS Shapes Using shape() — Part 2: More on Arcs | CSS-Tricks Better CSS Shapes Using shape() — Part 1: Lines and Arcs | CSS-Tricks Creating Blob Shapes using clip-path: shape() Creating Flower Shapes using clip-path: shape() Custom progress element using the attr() function A CSS-Only Star Rating Component and More! (Part 2) | CSS-Tricks A CSS-Only Star Rating Component and More! (Part 1) | CSS-Tricks How to Create Wavy Boxes Using CSS Full-Bleed Layout with Modern CSS Fancy Menu Navigation Using Anchor Positioning | CSS-Tricks How to Create a Zig-Zag Box Using CSS How to Create Zig-Zag CSS Loaders Using One Element Custom Progress Element Using Anchor Positioning & Scroll-Driven Animations How to Create Filling CSS Loaders Using One Element How to Create Curved-Edge and Rounded-Edge Shapes Using CSS CSS Tricks That Use Only One Gradient | CSS-Tricks How to create Shapes with Inner Curves using CSS Mask Custom Range Slider Using Anchor Positioning & Scroll-Driven Animations How to Get the Width/Height of Any Element in Only CSS How Keyboard Navigation Works in a CSS Game How To Create Cut-Out Shapes using The clip-path property The Modern Guide For Making CSS Shapes — Smashing Magazine css-shape.com: The Ultimate Collection of CSS-only Shapes ⚡️ Sliding 3D Image Frames In CSS — Smashing Magazine CSS Tricks To Master The clip-path Property Creating Wavy Circles with Fancy Animations in CSS Modern CSS Tooltips And Speech Bubbles (Part 2) — Smashing Magazine Do you need a Tooltip or a Speech Bubble? I have created 100 using CSS 😲 Modern CSS Tooltips And Speech Bubbles (Part 1) — Smashing Magazine CSS Shapes: The Triangle The Complex But Awesome CSS border-image Property — Smashing Magazine CSS Tricks to add 3D Effects to your Text CSS Responsive Multi-Line Ribbon Shapes (Part 2) — Smashing Magazine CSS Responsive Multi-Line Ribbon Shapes (Part 1) — Smashing Magazine I have made 100+ CSS-only Ribbon Shapes | The Perfect Collection 🎀 How to create a CSS-only infinite scroll animation Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 2) — Smashing Magazine Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 1) — Smashing Magazine How to Create CSS Ribbon Shapes with a Single Element CSS Shapes: The Ribbon Revealing Images With CSS Mask Animations — Smashing Magazine css-loaders.com: The Biggest Collection of Loading Animations (more than 500 🤯) How To Define An Array Of Colors With CSS — Smashing Magazine CSS effects on images II Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images — Smashing Magazine What's your Lucky CSS Pattern? Check It Now! How to Add a CSS Reveal Animation to Your Images Modern Layouts using CSS Grid I created 100+ unique CSS patterns | The best collection 🤩 How to Create a Custom Range Slider Using CSS CSS Shapes: The Heart CSS Shapes: Polygon & Starburst A Text Reveal Animation using CSS CSS Tip: learn CSS the easy way! How to build a CSS-only accordion How to create Breadcrumb Navigation with CSS Different Ways to Get CSS Gradient Shadows | CSS-Tricks A CSS-only responsive Stepper component A Fancy Hover Effect For Your Avatar | CSS-Tricks How to make a zoom effect using CSS Creating a Custom Cursor using CSS CSS Infinite 3D Sliders | CSS-Tricks CSS Infinite Slider Flipping Through Polaroid Images | CSS-Tricks How to create a responsive sidebar menu using CSS CSS Infinite and Circular Rotating Image Slider | CSS-Tricks Making Static Noise From a Weird CSS Gradient Bug | CSS-Tricks CSS Grid and Custom Shapes, Part 3 | CSS-Tricks Fancy Image Decorations: Outlines and Complex Animations | CSS-Tricks Fancy Image Decorations: Masks and Advanced Hover Effects | CSS-Tricks Fancy Image Decorations: Single Element Magic | CSS-Tricks How to create an infinite image slider using CSS How to Create Wavy Shapes & Patterns in CSS | CSS-Tricks How I Made a Pure CSS Puzzle Game | CSS-Tricks How to create a Tooltip/Speech Bubble using CSS CSS Grid and Custom Shapes, Part 2 | CSS-Tricks CSS Grid and Custom Shapes, Part 1 | CSS-Tricks Zooming Images in a Grid Layout | CSS-Tricks How to create a CSS-only loader with one element Exploring CSS Grid’s Implicit Grid and Auto-Placement Powers | CSS-Tricks How to create background pattern using CSS & conic-gradient Single Element Loaders: The Bars | CSS-Tricks
Creating Flower Shapes using CSS Mask & Trigonometric Functions
Temani Afif on February 29, 2024 · 2024-02-29 · via CSS Articles by Temani Afif

Creating unusual shapes is always a fun exercise and a good way to practice your CSS skills. One might argue that SVG is better for this job, but nowadays we have a lot of new CSS tricks that allow us to create shapes with a clean and optimized code. Through this two-article series, we will explore what can be done with CSS nowadays.

Article Series

In this article, we are going to create flower-like shapes. We are going to rely on modern features like mask, trigonometric functions, CSS variables, etc.

four flower-like shapes with purple to pink gradients. two of them have petals and two of them have spikes. two of them are filled and two of them are outlined.

Before we start, you can take a look at my online generator for flower shapes to get an overview of what we are building here. You can easily define your settings and get the CSS code in no time. Some of the code we will be writing can be complex so it’s always good to have a generator to make our life easy. That said I invite you to keep reading to understand the logic behind the code you are copying and be able to tweak it if needed. 

The Geometry of A Flower Shape

The structure of the flower shape can be seen as small circles placed around a bigger one. 

final shape showing it is built from one large circle and many smaller ones.

Consider that the small circles touch each other without overlapping each other. This will make the calculation a bit challenging as we will need accurate formulas. Turns out this is a perfect use case for trigonometric functions in CSS.

The shape can be controlled using 2 variables; the number of small circles (N) and their radius (R). From there we can identify the size of the whole shape and the radius of the big circle.

Here is a figure to illustrate some of the values and from where we can extract the different formulas.

geometry of the circles showing the radius comparisons.

I won’t start a boring geometry course so I will jump straight to the formulas we need to use. The size of the element is equal to

2 * (X + R) = 2 * (R/sin(180deg/N) + R) = 2 * R * (1 + 1/sin(180deg/N))Code language: CSS (css)

and the radius of the big circle is equal to

C  = R/tan(180deg/N)Code language: CSS (css)

We have all that we need to start writing some code.

Coding The Shape

The main challenge is to rely on a single element. We are not going to consider a complex HTML structure where each circle is a different element. Instead, we will only use one element (and no pseudo-elements either!)

I mentioned mask, we’ll be using that, and gradients will allow us to do the shape drawing we want to do. Since it’s all about circles we are going to use radial-gradient(). We will also use a bit of Sass (for the looping feature) to control the number of circles. The number of gradients will depend on the number of circles and with Sass we can write a loop to generate the needed gradients.

Let’s start by setting the different variables and the shape size:

$n: 12; /* the number of circles/petals */

.flower {
  --r: 30px; /* the radius of the small circles */
  width: calc(2*var(--r)*(1 + 1/sin(180deg/#{$n})));
  aspect-ratio: 1;
  mask: radial-gradient(#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0);
  background: /* you background coloration */
}
Code language: CSS (css)

Nothing fancy so far, we simply translated the previous formulas using code. I also added the big circle so all that we are missing is the small ones. The Sass code to generate them will look like this:

$m: (); /* empty variable */
@for $i from 1 through ($n) { /* loop through the number of circles*/
  $m: append($m, 
    radial-gradient(50% 50%,#000 100%,#0000) no-repeat
    x y / calc(2*var(--r)) calc(2*var(--r)), 
  comma);
}
Code language: SCSS (scss)

--r defines the radius so the size of each gradient will be equal to calc(2*var(--r)). Then we need to identify the position of each gradient (the x y).

Here as well, we need to consider some geometry formulas

x = calc(50% + 50%*cos(360deg*#{$i/$n})) 
y = calc(50% + 50%*sin(360deg*#{$i/$n}))Code language: SCSS (scss)

The final code will be:

$n: 6; /* the number of circles/petals */

.flower {
  --r: 30px; /* the radius of the small circles */
  width: calc(2*var(--r)*(1 + 1/sin(180deg/#{$n})));
  aspect-ratio: 1;
  $m: (); /* empty variable */
  @for $i from 1 through ($n) { /* loop through the number of circles*/
    $m: append($m, 
      radial-gradient(50% 50%,#000 100%,#0000) no-repeat
      calc(50% + 50%*cos(360deg*#{$i/$n})) 
      calc(50% + 50%*sin(360deg*#{$i/$n}))
     / calc(2*var(--r)) calc(2*var(--r)), 
    comma);
  }
  mask: radial-gradient(#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0),{$m};
  background: /* you background coloration */
}Code language: SCSS (scss)

Note how the mask property takes the value generated using Sass in addition to the gradient that creates the big circle.

Our shape is done!

The size of the shape is controlled by the radius of the small circles but we can do the opposite which is probably more convenient since we generally want to control the width/height of our element.

.flower {
  --w: 200px; /* the size */
  --r: calc(var(--w)/(2*(1 + 1/sin(180deg/#{$n}))));
  width: var(--w);
  /* same as before */
}Code language: CSS (css)

We can even optimize the previous code a little and get rid the of --w variable. The latter is defining the width/height of the element and gradients can access such value using percentages we can write the code like below:

$n: 12; /* the number of circles/petals */

.flower {  
  width: 300px; /* the size */
  --r: calc(50%/(1 + 1/sin(180deg/#{$n}))); /* using percentage instead of --w */
  aspect-ratio: 1;
  $m: (); /* empty variable */
  @for $i from 1 through ($n) { /* loop through the number of circles*/
    $m: append($m, 
      radial-gradient(50% 50%,#000 100%,#0000) no-repeat
      calc(50% + 50%*cos(360deg*#{$i/$n})) 
      calc(50% + 50%*sin(360deg*#{$i/$n}))
     / calc(2*var(--r)) calc(2*var(--r)), 
    comma);
  }
  mask: radial-gradient(100% 100%,#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0),#{$m};
}Code language: SCSS (scss)

Now by adjusting the width you control the size of the whole shape. Here is an interactive demo where you can resize the element and see how the shape adjusts automatically. Try it below with the resizer handle on the bottom right of the box:

Voilà! We did a nice flower shape without hack or complex code and you can easily control it by adjusting a few variables. You either use the above code or you consider my online generator to get the generated CSS without the variables and Sass.

Inverting the shape

Let’s try a different shape this time. It’s somehow the invert of the previous one where the circular part is going inside instead of outside. Well, a figure worth a thousand words.

spiky flower shape with purple to orange coloring

​​The code to get the above shape is the same as the previous one, but we are going to introduce mask-composite​. The idea is to cut the small circles from the bigger one which translates to a “subtract” composition.

Here is a figure to illustrate the process:

The code of mask will look like this:


mask: 
 radial-gradient(100% 100%,#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0) subtract,
 #{$m};Code language: CSS (css)

And here is the one of the previous shape to compare both:


mask: 
 radial-gradient(100% 100%,#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0),
 #{$m};Code language: CSS (css)

The only difference is the value of composition “subtract”. And since the remaining code is also the same, we can introduce a variable to control which one to use:


$n: 12; /* the number of circles/petals */

.flower {
  width: 300px;
  aspect-ratio: 1;
  --r: calc(50%/(1 + 1/sin(180deg/#{$n})));
  $m: (); /* empty variable */
  @for $i from 1 through ($n) { /* loop through the number of circles*/
    $m: append($m, 
      radial-gradient(50% 50%,#000 100%,#0000) no-repeat
      calc(50% + 50%*cos(360deg*#{$i/$n})) 
      calc(50% + 50%*sin(360deg*#{$i/$n}))
     / calc(2*var(--r)) calc(2*var(--r)), 
    comma);
  }
  mask: radial-gradient(100% 100%,#000 calc(var(--r)/tan(180deg/#{$n})),#0000 0) var(--alt,),#{$m};
}
.alt {
  --alt: subtract;
}Code language: CSS (css)

The var(--alt,) will default to nothing when the variable is not specified and we get the code of the first shape. By adding the composition value, we get the second shape. Two different shapes with the same code.

Why not simply add mask-composite: subtract?

This won’t work because it will apply a “subtract” composition between all the gradient layers whereas we want the composition to happen only between the big circle and the small ones. If you want to use mask-composite it should have the following value:

mask-composite: subtract, add, add, ..., add;

We perform and “add” composition between the small circles (the default composition) then we “subtract” the result from the big circle. It’s clear that adding one value inside the shorthand version is easier.

The Border-Only Version

Now let’s tackle the border-only version of the previous shapes. We are also going to rely on mask-composite and the same code structure.

First of all, let’s introduce a new variable to control the border thickness and update the code that generates the small circles.

$n: 12; /* the number of circles/petals */

.flower {
  --b: 10px; /* the border thickness*/

  width: 300px;
  aspect-ratio: 1;
  --r: calc(50%/(1 + 1/sin(180deg/#{$n})));
  $m: (); /* empty variable */
  @for $i from 1 through ($n) { /* loop through the number of circles*/
    $m: append($m, 
      radial-gradient(50% 50%,#0000 calc(100% - var(--b)),#000 0 100%,#0000) no-repeat
      calc(50% + 50%*cos(360deg*#{$i/$n})) 
      calc(50% + 50%*sin(360deg*#{$i/$n}))
     / calc(2*var(--r)) calc(2*var(--r)), 
    comma);
  }
  mask: #{$m};
}Code language: SCSS (scss)

Nothing complex so far. Instead of full circles, we are getting a border-only version. This time we don’t want them to touch each other but rather overlap a bit to have a continuous shape.

We need to increase the radius a little from this

--r: calc(50%/(1 + 1/sin(180deg/#{$n})));Code language: SCSS (scss)

To this:

--r:calc((50% + var(--b)/(2*sin(180deg/#{$n})))/(1 + 1/sin(180deg/#{$n})));Code language: SCSS (scss)

Again some geometry stuff but you don’t really need to accurately understand all the formulas. I did the hard work to identify them and you only need to understand the main trick. In the end, all you have to do is update a few variables to control the shape or get the code from my generator.

The result so far:

Now, we use mask-composite with another gradient to hide some parts and get our final shapes. Here is a figure to illustrate the process for both shapes.

For the first shape:

And for the second one:

In both cases, I am introducing an extra gradient that will intersect with the small circles. The difference between each shape is the coloration of the extra gradient. In the first case, we have transparent inside and filling outside and for the second case, we have the opposite.

/* first shape */
mask:
 radial-gradient(100% 100%,#0000 calc(var(--r)/tan(180deg/#{$n}) - var(--b)/(2*tan(180deg/#{$n}))),#000 0) intersect, 
 #{$m};
/* second shape */
mask:
 radial-gradient(100% 100%,#000 calc(var(--r)/tan(180deg/#{$n}) - var(--b)/(2*tan(180deg/#{$n}))),#0000 0) intersect, 
 #{$m};
Code language: SCSS (scss)

And here is the full code with both variations:

If you have some trouble visualizing how mask-composite works, I invite you to read the crash course written by Ana Tudor where you will find a more in-depth exploration.

One More Shape

Another flower? Let’s go!

blob like shape, sort of like a gear with smoothed over cogs.

This time, it’s your turn to figure out the code. Consider this as a small piece of homework to practice what we have learned together. As a hint, here is a figure that illustrates the mask-composite you need to perform, or maybe you will figure out another idea! If so don’t hesitate to share it in the comment section

Here is the code of my implementation but make a try before checking it so you can compare your method with mine. Take the time to study this last example because it will be the starting point of our second article.

Conclusion

I hope you enjoyed this little experimentation using CSS mask and trigonometric functions. You are probably not going to use such shapes in a real project but creating them is a good way to learn new features. If you have to remember one thing from this article it’s the use of mask-composite. It’s a powerful property that can help you create complex shapes.

It is worth noting that since we are using mask, we can easily apply our shape to image elements.

Don’t forget to bookmark my flower shapes generator so you can easily grab the code whenever you need it. I also have more CSS generators that invite you to check. Most of them rely on CSS mask as well and I have a detailed article linked to each one.

I will close this article with a few mesmerizing animations involving some flower shapes.

Article Series