Original link:
Iamvdo. Me/en/blog/smo…
The original author has been obtained
Vincent De OliveiraThe license
Recently, I shared an article on Twitter about visual illusions in human-computer interfaces. I’ve always loved optical illusions, but this article made a new point: it’s possible for a fine-tuned circle to look rounder than a geometric perfect circle, and the same holds true for rounded rectangles. I was also surprised to see that Apple has been doing the same thing with the ICONS since iOS 7. In mathematics, we call this adjusted rounded rectangle a hyperellipse.
At the same time, in preparation for a presentation, I was experimenting with CSS Houdini’s Paint API. This API defines a new way to add content to CSS images during the browser’s rendering phase. Simply put, browsers give us the ability to programmatically draw a CSS image and use it as a background. Therefore, we should be able to draw a hyperellipse very easily. A few weeks later, Sketch added a smooth corners feature. As far as I know, smooth rounded corners are actually hyperellipses. I like the name “smooth rounded Corners”, so I’m going to show you how to draw smooth rounded corners using CSS
First, we add a drawing module to paintWorkle [1]
(CSS.paintWorklet || paintWorklet).addModule('smooth-corners.js')
Copy the code
Then, in this module, we register a paint process called smooth-Corners, which must provide a paint method to draw the hyperellipse.
RegisterPaint ('smooth-corners', class {paint(CTX, size) {ctx.fillstyle = 'black' // n=4, Const n = 4 let m = n if (n > 100) m = 100 if (n < 0.00000000001) m = 0.00000000001 const r = size.width / 2 const w = size.width / 2 const h = size.height / 2 ctx.beginPath(); for (let i = 0; i < (2*r+1); i++) { const x = (i-r) + w const y = (Math.pow(Math.abs(Math.pow(r,m)-Math.pow(Math.abs(i-r),m)),1/m)) + h if (i == 0) ctx.moveTo(x, y) else ctx.lineTo(x, y) } for (let i = (2*r); i < (4*r+1); i++) { const x = (3*r-i) + w const y = (-Math.pow(Math.abs(Math.pow(r,m)-Math.pow(Math.abs(3*r-i),m)),1/m)) + h ctx.lineTo(x, y) } ctx.closePath() ctx.fill() } })Copy the code
The paint method takes two arguments:
ctx
Is aPaintRenderingContext2D
Object, which implementsCanvasRenderingContext2D
So in most cases you can draw any graph with itsize
Is aPaintSize
Object that specifies the size of the graph to be drawn
Now we can call the paint() function in the CSS. Executing this function will result in a smooth, rounded black rectangle.
.el {
background: paint(smooth-corners);
}
Copy the code
For simplicity, we use the generated image as a layer mask [2] so that we can easily set the desired background color, gradient, or image through background.
.el {
background: linear-gradient(deeppink, orangered);
mask-image: paint(smooth-corners);
}
Copy the code
The visuals are good, but the program isn’t flexible enough. For now, we have just drawn a special kind of hyperellipse, the fangyuan [3] (note n = 4 in the code). So, how do we draw a hyperellipse of any exponential? For example, iOS uses n = 5. We can use CSS custom properties to do this.
First, define the custom property — smooth-Corners
.el {
--smooth-corners: 4;
background: linear-gradient(deeppink, orangered);
mask-image: paint(smooth-corners);
}
Copy the code
Then get it from the registerPaint method
registerPaint('smooth-corners', class {
static get inputProperties() {
return [
'--smooth-corners'
]
}
paint(ctx, size, styleMap) {
const exp = styleMap.get('--smooth-corners').toString()
const n = exp
}
})
Copy the code
Notice that the paint() method takes a third argument, styleMap, which is a StylePropertyMapReadOnly object, essentially a Map object that gets the calculated values of the properties defined in inputProperties. Here we get the –smooth-corners attribute value and pass it to ‘n’. At this point, we can use the –smooth-corners property in CSS, which can even be adjusted dynamically by CSS animation, as long as we register it with css.registerProperty (for example, see the CSS Properties and Values API).
As of press time, only Chrome supports Houdini’s Paint API, so we provide it using progressive enhancement
Draw smooth rounded corners
.el { border-radius: 60px; background: linear-gradient(deeppink, orangered) } @supports (mask-image: paint(smooth-corners)) { .el.is-loaded { border-radius: 0; mask-image: paint(smooth-corners); --smooth-corners: 5; }}Copy the code
In addition, since Houdini is a JS-in-CSS scheme, it is best to wait until JavaScript loads before applying CSS properties. Therefore, I decided to add the.is-loaded class to the element to ensure that the style was applied after loading. In a production environment, we should use the PostCSS plug-in to automatically add the — Smooth-Corners CSS implementation. (translator note: as of when no corresponding PostCSS plug-in) you can use to support the features of the browser to lab. The iamvdo. Me/Houdini/smo… Experience the end result.
Postscript To put it simply, using a CSS mask is to hide elements outside the path (this is the purpose of the mask 😁). If necessary, you can also use registerPaint to draw gradients or images directly (images seem to have limited support at the moment and you have to work with the images yourself). If you want to do it yourself, there are other examples of drawing images: create your own background property, such as’ background-opacity ‘, or pass drawing parameters in a way other than the property: draw gradients starting from the four corners. I’d be happy to share your examples.
footnotes
- Chrome needs to turn on the ‘#enable-experimental-web-platform-features’ flag. The’ PaintWorklet ‘is either under’ CSS ‘(for stable versions) or’ Window ‘(for Canary versions). In Chrome 61 and below, ‘PaintWorklet’ is under ‘Window’; in Chrome 62 and above, ‘PaintWorklet’ is under ‘CSS’
- Don’t forget to use ‘Autoprefixer’ to automatically generate browser prefixes
- The word squircle is a combination of square and circle
This article has been reprinted in full with great effort from using CSS Houdini to draw smooth rounded corners, but it is still impossible to reprint all the reading experience. It was reprinted with the permission of the owner of the book, i. e., me.