Cooltipz.css — Pure CSS Customisable Tooltips

See the Pen Cooltipz.css – Cool tooltips made from pure CSS by Bramus (@bramus) on CodePen.

I especially like the fact that these are customisable using CSS Custom Properties. Here’s a few of them:

:root {
    --cooltipz-bg-color: #fff;
    --cooltipz-text-color: #333;
    --cooltipz-border-radius: 5rem;
}

Installation per NPM:

npm install cooltipz-css

Cooltipz.css →

HTML and CSS techniques to reduce your JavaScript

Anthony Ricaud, writing for the Web Performance Calendar, on the extra load that JavaScript can put on your site, and how you can replace some things with basic HTML and CSS:

Relying on solutions provided natively by browsers enables you to benefit at low cost from the expertise of the community creating web standards. These solutions generally have the advantage of using less code, thus reducing maintenance efforts for a development team (for example, no need to update the libraries used).

In this article, we will explore some of these native solutions that are available to the majority of your users.

It’s things like smooth scrolling, sticky items, carousels, etc. — those all can be implemented using pure CSS nowadays.

HTML and CSS techniques to reduce your JavaScript →

Thinking on ways to solve Centering in CSS

Adam Argyle looking at several techniques to center in CSS, and how they hold up in several conditions (narrow screen, rtl, etc)

In today’s challenge, we’re stress testing 5 different CSS centering techniques. See what techniques should earn a place in your tool belt by watching how they react to common layout stress. The contestants: content center, gentle flex, autobot, fluffy center, and pop & plop.

If you prefer a written format, a full write-up is also available on web.dev

Centering in CSS →

Injecting a JavaScript Attack Vector using CSS Custom Properties

Earlier this week I saw this tweet by Sansec float by:

This one’s pretty nice I must say: as the syntax for CSS Custom Properties is overly permissive (see here) you can use Custom Properties to store your JavaScript attack vector in. If you then use window.getComputedStyle to extract the contents of the Custom Property (see here) and combine it with a function constructor and an IIFE, it’s possible to execute it.

Here’s a pen that loads a remote confetti script using the method described:

Let this underline the importance of a Content Security Policy to prevent remote script loading script evaluation.

Update: Blocking this “hack” with a proper CSP

It took me some time to figure out — as I’m no CSP expert — but turns out the unsafe-inline keyword in the CSP’s source list is enough to block the execution of the JS-IN-CSS.

As a reminder, here are the four allowed keywords:

  • 'none', as you might expect, matches nothing.
  • 'self' matches the current origin, but not its subdomains.
  • 'unsafe-inline' allows inline JavaScript and CSS.
  • 'unsafe-eval' allows text-to-JavaScript mechanisms like eval.

I first thought unsafe-inline would be insufficient here as the code does not call eval, but apparently a function constructor is (correctly!) considered equally harmful, and therefore also blocked.

Here’s an updated demo that blocks the script evaluation:

See the Pen
Injecting a JavaScript attack vector using CSS Custom Properties (with CSP)
by Bramus (@bramus)
on CodePen.

The CSP used is this one:

<meta
    http-equiv="Content-Security-Policy"
    content="script-src https://cpwebassets.codepen.io https://cdpn.io https://cdn.jsdelivr.net 'unsafe-inline';"
>

It works as follows:

  • https://cpwebassets.codepen.io and https://cdpn.io are there for the CodePen demo to work
  • https://cdn.jsdelivr.net is there to allow legitimate loading of scripts — such as a jQuery you might need — from that CDN.
  • unsafe-inline is the one that prevents the execution of the JS-IN-CSS defined script by blocking the call to the function constructor

That calls for confetti! 🤪

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 surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

content-visiblity: auto; vs. jumpy scrollbars, a solution

As warned in content-visibility: the new CSS property that boosts your rendering performance you need to be careful with applying content-visibility: auto; on each and every element as the scrollbar might get jumpy.

This is because elements will be rendered as they scroll into the viewport and will be hidden as they scroll out of the viewport, thereby affecting the height of the rendered page, and thus also affecting the scrollbar.

ℹ️ Apart from a jumpy scrollbar it can also negatively affect accessibility when you include headings and landmark elements inside of regions styled with content-visibility: auto;. See Content-visibility and Accessible Semantics for details.

Now, thanks to infinite scroll we are — or at least I am — kind of used to the thumb part of the scrollbar shrinking and jumping back up a bit on the scrollbar track as you scroll down. What we’re not used to is the thumb part jump forwards on the scroll track as you scroll down. This is because elements that slide out of the viewport will no long be rendered — as that’s what content-visibility: auto; does — and the scrollbar is (by default) only calculated against the rendered elements.


Elements can become non-rendered elements as they scroll out of the viewport,
thanks to content-visibility: auto; doing its thing.

To cater for this jumpy behavior you should use contain-intrinsic-size so space for an element is reserved when it’s not being rendered. However, it is not always possible to know a box its dimensions in advance. Looking for a way to automatically reserve space for previously rendered elements, Alex Russel created a little script for it.

One challenge with naive application of content-visibility, though, is the way that it removes elements from the rendered tree once they leave the viewport — particularly as you scroll downward. If the scroll position depends on elements above the currently viewable content “accordion scrollbars” can dance gleefully as content-visibility: auto does its thing.

In a first version of the script he applied content-visibility: visible on each element from the moment it had appeared on screen. To detect this an IntersectionObserver is used. While this does prevent the scrollbar thumb from jumping forwards as you scroll down, it will make the page slow again as that content remains rendered (even though it’s off-screen).

A second version of the script takes a different approach and calculates the contain-intrinsic-size to apply based on the element’s dimensions. That way elements that passed by once now have a correct contain-intrinsic-size set, and can safely be hidden again as content-visibility: auto does its job.

let spaced = new WeakMap();
let reserveSpace = (el, rect) => {
    let old = spaced.get(el);
    // Set intrinsic size to prevent jumping.
    if (!old || rectNotEQ(old, rect)) {
        spaced.set(el, rect);
        el.attributeStyleMap.set(
        "contain-intrinsic-size",
        `${rect.width}px ${rect.height}px`
        );
    }
};

Additionally he also added a ResizeObserver to cater for resize events.

Resize-Resilient `content-visiblity` Fixes →

🤔 Clever script indeed, yet I cannot help but think: this should be possible without the needs for this extra script. What if a value like contain-intrinsic-size: auto; would be allowed, and do exactly as the script Alex built does?

UPDATE: I’ve created an issue on GitHub that proposes contain-intrinsic-size: auto;. Let’s see where this goes …

Debugging CSS

Apart from writing a ton of articles for his website this year, Ahmad has also written a book on Debugging CSS:

An ebook with lots of tips and techniques on how to debug CSS the right way with easy and studied methods.

It’s a very practical book that should get you help solve any potential CSS issues you might run into.

Debugging CSS →

Side note: I’m proud to have been asked to review this book while it was still in the making, and am glad I was of help to Ahmad. Great job you did there!

Sticky CSS Grid Items

Melanie Richards:

If you’ve ever tried to put a sticky item in a grid layout and watched the item scroll away with the rest of the content, you might have come to the conclusion that position: sticky doesn’t work with CSS Grid. Fear not! It is possible to get these two layout concepts working together. All you likely need is one more line of CSS.

The solution is to make it so that the item you want to stick does not stretch out vertically. You can do this by applying align-self: start; on said element, which is the same approach I took when implementing that Smooth Scrolling Sticky ScrollSpy Navigation earlier this year 🙂

Sticky CSS Grid Items →

Cyberpunk 2077 Button Glitch Effect in CSS

Wonderful demo by Jhey Tompkins, showcasing some recreated glitch effect buttons based upon Cyberpunk 2077.

Recreate the Cyberpunk 2077 Button Glitch Effect in CSS →

If you can’t quite follow there — as it’s quite a big demo — here’s a more simplified demo from 2015 featuring a simple glitch text effect:

See the Pen
CSS Glitch
by Bramus (@bramus)
on CodePen.

Both demos work in a similar way: data is duplicated, and a clip-path is being animated on top of it.

What Makes CSS Hard To Master

Tim Severien:

CSS may seem simple at first, but the learning curve isn’t linear; mastering it is hard. By no means is the language perfect, but it’s amazingly efficient at what it’s designed to do. Despite its simple syntax, there’s little it can’t do.

What Makes CSS Hard To Master →

Related: As Jeremy Keith wrote in 2017: CSS is simple, but not easy

Beyond Fast: Features to Improve the Performance of your Web Pages

Few tips by Jake Archibald — as presented at #ChromeDevSummit — on how you can use some of the new and upcoming web features to improve the performance of your page.

Covered are the aforementioned content-visibility, Font metric override descriptors, the Back/Forward Cache, Portals, and Preloading