The State of CSS 2020

The results for The State of CSS 2020 are in!

Forget everything you know about CSS. Or at least, be ready to reconsider a lot of it. If like me you’ve been writing CSS for over a decade, CSS in 2020 looks nothing like what you were used to.

Instead of breakpoints, we can now leverage CSS Grid to make dynamic, responsive layouts that adapt to any viewport size with fewer lines of code. Instead of relying on global stylesheets, CSS-in-JS lets us colocate our styles with our components to build themeable design systems

I personally find this a very pleasing site, both visually and content-wise. Check out this visualization for example, where the size of the outer opaque circle corresponds to the total number of users who know about a feature, while the inner (non-opaque) one represents those who have actually used it:

And oh, can you spot to link to in the content?

The State of CSS 2020 →

ibis β€” A PHP tool that helps you write eBooks in markdown and convert to PDF

Mohamed Said recently wrote the book β€œLaravel Queues in Action”. To create the book he wrote it Markdown and then used his self-created tool ibis to generated the PDF and ePub versions.

Installation per Composer:

composer global require themsaid/ibis

After which you start a new project with ibis init

Check out the preview of β€œLaravel Queues in Action” to get an idea of what is being generated.

Laravel Queues in Action Preview (Light) →
Laravel Queues in Action Preview (Dark) →

Customise the caret color with the CSS `caret-color` property

Thanks to this tweet by Álvaro Trigo I found out that you can change the color of the caret β€” that little blinking | in text inputs β€” using the caret-color CSS property:


input {
  caret-color: red;

πŸ’β€β™‚οΈ Do note that the caret-color defaults to currentColor, so you don’t need to manually match the color set on an element.


Browser support is really great:

Data on support for the css-caret-color feature across the major browsers from

πŸ’‘ Shown above is a live table, showing an always up-to-date support table. By the time you are reading this browser support might have become better.


Wondering if there were more caret-* properties this turned out to be not the case. A pity though, as I can think of cases where I would like to set the caret-height and caret-thickness, such as emulating the cursor of a terminal:


As a fun little experiment Tim Carambat created a Pen that changes the caret color from green to yellow to red as you near the maxlength of the <textarea> you’re typing in.

See the Pen
Color Changing Cursor in TextArea
by Timothy Carambat (@rambat1010)
on CodePen.

Usability-wise this isn’t that great, but it’s fun nonetheless πŸ™‚

BlurHash β€” Low-res Blurred Placeholder Images Represented as Text

If you’re dealing with images it’s quite common to show a small placeholder while the image is loading. You could go with grey placeholders, but a low-res blurred version of the original is preferred. That way you can, in the example use case of a website, use the Blur Up technique once the image is loaded. BlurHash is something that can help you with exactly that:

In short, BlurHash takes an image, and gives you a short string (only 20-30 characters!) that represents the placeholder for this image. The string is short enough that it comfortably fits into whatever data format you use. For instance, it can easily be added as a field in a JSON object.

An example of a BlurHash would be LEHV6nWB2yk8pyo0adR*.7kCMdnj

Implementations that can encode and decode exist for TypeScript, PHP, Python, Swift, Kotlin, etc.

To use BlurHashes in the context of a web browser without needing to rely on JavaScript on the client side, I’d use this with a Cloud Function (or the like) that converts the encoded version to the actual image. Your markup could then look something like this:

<span style="display: inline-block; background: transparent url('') 0 0 / 100% 100%;">
	<img src="" width="538" height="" alt="346" title="" />

To tone down the potential number of network requests you could of course pre-decode those BlurHashes on the server and inject the background images using Data URIs from within your template engine.

BlurHash →

Painting a Selfie Girl, with Math

Today we are painting a girl taking a selfie, with mathematics.

I like how the author, a few minutes into the video, says … none of which is too complicated to be honest … while I’m hardly understanding any of the things that he’s explaining πŸ₯΅

You can play with the result over at Shadertoy.

Native Aspect Ratio Boxes in CSS thanks to aspect-ratio

Old vs. New. Image by @una.


Back in May 2020 I was very delighted to read that the first Working Draft of the CSS Box Sizing Module Level 4 got published, as it featured an addition to CSS that I’ve been wanting for a long time now: native support for aspect ratio boxes through the new aspect-ratio CSS property.

With Chromium 89 (current Canary) and Firefox 85 (current Nightly) already supporting aspect-ratio unflagged, it’s time to start playing with this new addition and start thinking about dropping all those nasty hacks to mimic aspect ratios in CSS. Let’s take a look …

πŸ€” Working Draft (WD)?

The Working Draft (WD) phase is the first phase of the W3C Recommendation Track, and is considered the design phase of a W3C spec.

From thereon a spec can become a Candidate Recommendation (CR) to finally land on being a Recommendation (REC). In between those three stages there are two transition stages: Last Call Working Draft (LCWD) and Proposed Recommendation (PR)

In visual form, the Recommendation Track looks something like this:

See An Inside View of the CSS Working Group at W3C for more details on all phases.

⚠️ Note that the current implementations in both Firefox Nightly and Chrome Canary are not finalised yet (most likely due to the spect still being a WD?). You can track these bugs to stay up-to-date:


Welcome aspect-ratio

In short, the aspect-ratio property allows you to define a preferred aspect ratio on elements:

.box {
  width: 20vw;
  aspect-ratio: 16 / 9;

[CodePen Demo]

In the example above the .box will have a preferred aspect ratio of 16:9. Since its width is set to 20vw, the resulting height will be 20vw / 16 * 9 = 11.25vw. Easy, right?

🀞 Psst, further down this you can find a demo that includes a fallback for browsers that don’t support aspect-ratio πŸ˜‰


Allowed values for aspect-ratio

The value as set in the example above for aspect-ratio is of the <ratio> type:

  • It typically consists of two numbers separated by a /. The first parameter targets the width and the second one the height.
  • It’s also allowed to pass in just a single number. In that case the second number will be we considered to be 1. E.g. a <ratio> of 2 will translate to 2 / 1.
  • Passing in a 0 for either of the numbers is not allowed.
  • The spaces around the / are not required, so 2/1 is also a valid <ratio> value.

Another allowed value for the aspect-ratio property β€” which also is the default β€” is auto. This indicates that the box has no preferred aspect ratio and should size itself as it normally would.

πŸ™‹β€β™‚οΈ Hold up! How come images already behave correctly, without needing to define an aspect-ratio?

Images may be commonly used, but they are a quite uncommon type of HTML element:

  1. Images are replaced elements:

    A replaced element is an element whose content is outside the scope of the CSS formatting model, such as an image or embedded document. For example, the content of the HTML <img> element is often replaced by the image that its src attribute designates.

    Just check your DevTools: the browser will make an extra HTTP request for any image and fetch its contents separately. Once loaded, the browser will replace the original img tag with the actual image contents.

  2. Images have an intrinsic aspect ratio:

    The intrinsic dimensions represent a preferred or natural size of the object itself; that is, they are not a function of the context in which the object is used.

    Each photo that you take with your phone results in an image that has a certain width and height, which is referred to as the intrinsic or natural width/height. The intrinsic aspect ratio is the ratio between the intrinsic width and intrinsic height.

    When the browser has fetched the image and needs to draw it on screen it will take its intrinsic aspect ratio into account to know how big it should be drawn.

☝️ Do note that you can still set an aspect-ratio on an element that has an intrinsic aspect ratio. In that case your defined aspect-ratio will override the intrinsic aspect ratio.


The fine print

Aspect of what?

Depending upon which of width or height you set, the box dimensions will be calculated against that.

.box {
  width: 20vw;
  aspect-ratio: 16 / 9; /* Dimensions will be calculated against the width,
                           yielding a height of 11.25vw (20vw / 16 * 9) */
.box {
  height: 20vw;
  aspect-ratio: 16 / 9; /* Dimensions will be calculated against the height,
                           yielding a width of 35.55vw (20vw / 9 * 16) */

aspect-ratio+width+height = 🚫

Setting an aspect-ratio won’t have effect on elements that have both a CSS width and CSS height set to a value other than auto. Only one of width or height can be explicitly set, and the other should remain set to auto.

.box {
  width: 20vw;
  height: 20vw;
  aspect-ratio: 16 / 9; /* won't have any effect! */

aspect-ratio + percentage based width/height

In case one of the width and height should be set to a percentage based value such as 100%, the targeted box will take a look at the direct parent element’s dimensions to define its value upon that.

.parent {
  height: 100px;
.parent .box {
  height: 100%;
  aspect-ratio: 1 / 1; /* .box will be 100px by 100px */

There’s some more edge cases here too, but let’s not get too deep into the spec πŸ˜‰

aspect-ratio sets a preferred aspect ratio

Setting an aspect-ratio will tell the browser that this is a preferred aspect ratio. Should the content of the box be larger, then the box will simply grow.

div {
  aspect-ratio: 1/1;
  /* 'width' and 'height' both default to 'auto' */
+----------+  +----------+  +----------+
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~ |
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~ |
| ~~~~~~~  |  | ~~~~~~~~ |  | ~~~~~~~~ |
|          |  | ~~~      |  | ~~~~~~~~ |
+----------+  +----------+  | ~~~~~~~~ |
                            | ~~~~~~   |

To maintain the aspect-ratio, you can set overflow to auto so that a scrollbar will be shown should the contents be larger:

div {
  overflow: auto;
  aspect-ratio: 1/1;
+----------+  +----------+  +----------+
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~^|
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~ |
| ~~~~~~~  |  | ~~~~~~~~ |  | ~~~~~~~~ |
|          |  | ~~~      |  | ~~~~~~~~v|
+----------+  +----------+  +----------+

What also works, is setting min-height

Overriding the min-height property also maintains the 1:1 aspect ratio, but will result in content overflowing the box if it is not otherwise handled.

div {
  aspect-ratio: 1/1;
  min-height: 0;
+----------+  +----------+  +----------+
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~ |
| ~~~~~~~~ |  | ~~~~~~~~ |  | ~~~~~~~~ |
| ~~~~~~~  |  | ~~~~~~~~ |  | ~~~~~~~~ |
|          |  | ~~~      |  | ~~~~~~~~ |
+----------+  +----------+  +-~~~~~~~~-+



Using aspect-ratio with a fallback for older browsers

Thanks to the powerful @supports it’s possible to add a fallback for browsers that don’t support aspect-ratio. In the demo below (based upon this demo by Una) a fallback using the padding-top hack is applied:

[CodePen Demo]

Using aspect-ratio with CSS Variables

By introducing a CSS Variable CSS Custom Property it’s possible to make your code more generic and extract away a .aspect-ratio class.

[CodePen Demo]

To use it, add apply the .aspect-ratio on the element you want, and pass in a --aspect-ratio CSS Custom Property:

  style="--aspect-ratio: 16/9;"
>I am an aspect ratio box</div>

The code is written so that it will use the value for --aspect-ratio in both the fallback and the modern version.

Automatically setting aspect-ratio on iframes and the like

When you embed an iframe you most likely set its width and height HTML attribute.


It’s possible to use the values of these attributes to automatically set the aspect-ratio.

iframe[width][height] {
  aspect-ratio: attr(width) / attr(height);

Heck, you could even target [width][height] if you’d want!

[CodePen Demo]

πŸ› I’ve noticed that reading the width/height attribute values using attr() to pass them into aspect-ratio doesn’t work in current Chromium. To cater for that I’m also passing their values by means of a CSS Custom Property …

  style="--aspect-ratio: 560 / 315"
πŸ™‹β€β™‚οΈ Why doesn’t this iframe demo have a padding-top fallback injected using :after?

Just like images, iframes also are replaced elements. It’s not possible to inject contents using :before/:after on replaced elements.

If you really need to have a fallback, you need to wrap the iframe in a container and apply the aspect-ratio on the container. See Embed Responsively and adjust were needed.


In Closing

After 8 years of wanting this feature to land in CSS (ref) I’m very happy to see this addition make it into the spec. It’s still a Working Draft right now, but that doesn’t stop me from being excited about it already. I hope you are too πŸ™‚

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would always put a smile on my face. Thanks!

β˜•οΈ Buy me a Coffee (€3)

Skypack β€” Load optimized npm packages with no install and no build tools

I was delighted to read that CodePen now has built-in support for Skypack. This is a huge step forward to working with packages on CodePen. Great addition to the product!

But what exactly is Skypack? Well, it’s the successor to the aforementioned Pika CDN *COMBINED* with the aforementioned Snowpack: Skypack not only serves ES Modules, it also converts older CommonJS Modules to ES Modules while at it.

Ever tried to load JavaScript from a CDN and realized that it doesn’t work in a browser without a bundler? Skypack operates like your favorite CDN but with an important difference: packages are preoptimized for browser use.

But Skypack doesn’t stop there: it handles minification, browser polyfilling, gzip/brotli, HTTP/3, caching, and more!

Skypack is free to use for personal and commercial purposes, forever. The basic CDN is production-ready and is backed by Cloudflare, Google Cloud, and AWS. We’re fully committed to building a core piece of infrastructure you can rely on.

Fred K. Schott, one of its authors, announced it this summer at ESNext Conf β€” a virtual conference which I also gave a talk at.

(Fast forward to the 18 minute mark to get to the Skypack part)

Here’s a simple Confetti example:

See the Pen
by Chris Coyier (@chriscoyier)
on CodePen.

Neat, right?

Skypack β€” Load optimized npm packages with no install and no build tools →
Skypack + CodePen →

The 6 Stages of Spam Protection

The journey of the folks over at Laracasts on how they stopped spam (for now) on their forums.

  1. Keyword Censoring
  2. Email Confirmation
  3. Language Detection
  4. Throttling
  5. Honeypots
  6. reCAPTCHA

Comes with (Laravel) code snippets to go along with that.

The 6 Stages of Spam Protection →

Yes, that dreaded reCAPTCHA. Hate it all you want, but it actually works. And yes, it can become quite stressful in some edge cases:


Front Line PHP – Building modern web applications with PHP 8

The folks over at Spatie are at it again, this time with Front Line PHP.

An ebook on cutting edge tactics in PHP 8, accompanied by videos and practical examples.

The videos covering the new additions to PHP 8 are free to watch, and should give you an idea of what you can expect.

At €79 (now €56 due to #BlackFriday) this is a steal.

Front Line PHP →
Front Line PHP Videos (paid + free)