The Matrix: How to Begin a Movie

The Matrix has one of the all-time greatest opening scenes. Let’s talk about why it works.

Elsewhere , , Leave a comment

Learning Vue

I haven’t checked out Vue myself yet (more into React 😉), but this five-part series by Sarah Drasner seems like a very solid start …

  1. Rendering, Directives, and Events
  2. Components, Props, and Slots
  3. Vue-cli and Lifecycle Hooks
  4. Vuex
  5. Animations

Learning Vue – CSS-Tricks →

Elsewhere , , Leave a comment

react-datasheet, an Excel-like Datagrid Component for React

A simple react component to create a spreadsheet:

  • Select cells, copy-paste cells
  • Navigation using keyboard keys
  • Deletion using keyboard keys
  • Callbacks for onChange, valueRenderer(visible data)
  • dataRenderer(underlying data in the input, takes the value by default)

Installation per npm, of course:

npm install react-datasheet --save

Cells can have both a value and an expression (the underlying data), each with their own renderer:

const grid = [
   [{value:  5, expr: '1 + 4'}, {value:  6, expr: '6'}, {value: new Date('2008-04-10')}],
   [{value:  5, expr: '1 + 4'}, {value:  5, expr: '1 + 4'}, {value: new Date('2004-05-28')}]
]
const onChange = (cell, i, j, newValue) => console.log("New expression :" + newValue)

<ReactDataSheet 
  data={grid}
  valueRenderer={(cell, i, j) => j == 2 ? cell.value.toDateString() : cell.value}
  dataRenderer={(cell, i, j) => j == 2 ? cell.value.toISOString() : cell.expr}
  onChange={} 
/>

React datasheet (GitHub) →
React datasheet Demos →

Elsewhere , , Leave a comment

Exploring interdependencies in global resource trade

The volume of natural resources traded globally has increased over 60% since the turn of the century, reflecting and reinforcing new economic and geopolitical realities and bringing new environmental and social challenges – as well as opportunities. Now everyone can explore these fast-evolving dynamics through Chatham House’s comprehensive and accessible data and insights into resource trade.

Tightly executed data visualisation … and it’s interactive too! Very, very, nice work!

Exploring interdependencies in global resource trade →

Elsewhere , Leave a comment

Aspect Ratios in CSS are a Hack

👋 Hello new visitors! Looks like this post has been getting some attention, bringing you here … welcome! 🙂

If you happen to like this kind of post: my blog is packed with lots more stuff like this, all curated and maintained by me. Why not give it a look?

Additionally you can subscribe to the RSS feed, follow bram.us on Twitter and even on Facebook 🙈.

Thanks,
Bramus.

Right now I’m in Amsterdam attending CSSDay (my fourth time already!). Earlier this morning Bert Bos and Håkon Wium Lie – yes, the inventors of CSS – were on stage reflecting on the first days of CSS and things they’d’ve done differently or turned out differently than they expected.

At the end of the talk the question came up if we, the audience, found if things were missing in CSS. Immediately aspect ratios came to my mind, as it’s something that has been bothering me for a few years by now, over, and over again.

At last years’ Fronteers Conference it – for a short period of time – even became a hot topic after a demo using a spacer gif to creating aspect ratios was shown on stage. It created some outrage, yet my response to it was more nuanced:

Before going any further, let’s first take a look at the current hacks that exist to creating aspect ratios on the web.

~

Current Techniques

Technique #0: Spacer gifs

No. Just no. 1999 called. They want their IE5 back.

Here, a dancing baby if you’re feeling nostalgic:

~

Technique #1: Vertical Padding

A (hopefully) well known and longstanding hack to faking aspect ratios on the web is to abuse the vertical padding. By setting the height of an element to 0 and the padding-top or padding-bottom to a percentage based value one can force a box to have a fixed aspect ratio.

The reason to why this hack works is that the padding of an element is calculated against the width of that element (*).

The percentage is calculated with respect to the width of the generated box’s containing block, even for ‘padding-top‘ and ‘padding-bottom‘. If the containing block’s width depends on this element, then the resulting layout is undefined in CSS 2.1.

CSS2 Box Model: Padding properties: ‘padding-top‘, ‘padding-right‘, ‘padding-bottom‘, ‘padding-left‘, and ‘padding.

(*) The vertical padding isn’t always calculated against the width though, there is an exception … but that’s food for another blogpost 😉

Say you need a box with an aspect ratio of 16:9. The resulting percentage to apply as a vertical padding can then be calculated via the formula 100% * 9 / 16, resulting in 56.25%. Say you want a 4:3 box, use 75% instead (100% / 4 * 3).

A generic implementation in CSS would be something like this:

<div class="aspectratio" data-ratio="16/9">
  <div>
    <p>16:9</p>
  </div>
</div>
.aspectratio {
  position: relative;
  height: 0;
  width: 100%;
}

.aspectratio[data-ratio="16:9"] {
  padding-top: 56.25%;
}

.aspectratio[data-ratio="4:3"] {
  padding-top: 75%;
}

You’ll need to wrap the content of .aspectratio in an extra element – a simple <div> will do – though, and sprinkle some extra CSS on top to position said element it properly inside .aspectratio:

.aspectratio > * {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

See the Pen CSS Aspect Ratios, Technique #1 by Bramus (@bramus) on CodePen.

Works fine in all browsers – even good old IE2 will do – but one must admit: it’s a hack, right?

~

Technique #1b: Vertical Padding (using CSS variables)

If you’re familiar with CSS variables you can exchange the introduced data-ratio attribute from above with a CSS variable to define the aspect ratio to use:

<div class="aspectratio" style="--aspect-ratio: 16/9;">
  <div>
    <p>16:9</p>
  </div>
</div>
.aspectratio {
  position: relative;
  height: 0;
  width: 100%;
  padding-top: calc(100% / (var(--aspect-ratio)));
}

.aspectratio > * {
  …
}

See the Pen CSS Aspect Ratios, Technique #1b by Bramus (@bramus) on CodePen.

Same core technique, yet a tad more modern implementation 🙂

~

Technique #2: Vertical Padding with Generated Content

A similar yet somewhat different approach to the first technique is to dynamically inject some content using :after or :before, and then stretch that out:

.aspectratio {
  position: relative;
}

.aspectratio:after {
  content: "";
  position: absolute;
  top: 0;
  width: 100%;
  z-index: -1;
}

.aspectratio[data-ratio="16:9"]:after {
  padding-top: 56.25%;
}

.aspectratio[data-ratio="4:3"]:after {
  padding-top: 75%;
}

See the Pen CSS Aspect Ratios, Technique #2 by Bramus (@bramus) on CodePen.

Unlike the first technique, this technique doesn’t stretch out the .aspectratio element itself though. Only the generated content box is stretched out. This can make it quite nasty to style and rather impossible to center the contents both horizontally and vertically.

~

Technique #3: Viewport based units

A technique I’m very fond of is to use viewport based units to hack together aspect ratios. It’s really great when you’re implementing full-width layouts, independent of the size of viewport (most typical designs for, say, blogs eventually limit the width of the main column).

An element that is 100vw can be given a height of 100vw / 16 * 9 = 56.25vw to give it an aspect ratio of 16:9

See the Pen CSS Aspect Ratios, Technique #3 by Bramus (@bramus) on CodePen.

On the upside you don’t need extra elements to wrap your content in, nor do you need to alter its position. On the downside however is the fact it isn’t very usable nor portable when things start shifting around or have different widths. Because this technique relies on explicit widths (eg. vw) instead of dynamic ones (eg. %), you’ll need to explicitly define the width/height per breakpoint and element.

Huh? An element that has a width of 33vw will need to a height of 33vw / 16 * 9 = 18.5625vw to give it an aspect ratio of 16:9. An element with a width of 40vw will need a different height, even though they have the same aspect ratio.

~

Technique #4: Viewport based units + CSS Grid

In Experiments in fixed aspect ratios Stephanie Liu experimented a bit further with fixed aspect ratios involving the grid spec. By defining square grid cells – using viewport based units – she’s then able to span elements over it:

.aspectratio {
  display: grid;
  grid-template-columns: repeat(16, 6.25vw);
  grid-auto-rows: 6.25vw;
}

.aspectratio[data-ratio="16:9"] .content {
  grid-column: span 16;
  grid-row: span 9;
  background: hotpink;
}

See the Pen CSS Aspect Ratios, Technique #4 by Bramus (@bramus) on CodePen.

This technique inherits the upsides and downsides of technique 3, but also re-introduces the extra element required to wrap around the content.

What now?

As already hinted in the title and introduction I find these techniques hacks and would like to see a proper, non-hacky, way to implementing aspect ratios on the web.

The ideal technique would involve best parts of all ones mentioned above:

  1. Work with elements that have dynamic widths
  2. Don’t require an extra element wrapping the content

A to me ideal syntax would be something along these lines:

.aspectratio[data-ratio="16:9"] {
  width: 100%;
  aspect-ratio: 16/9;
}

Researching upon this topic it came to my attention that Tab Atkins started writing a proposal for this back in 2012, suggesting a likewise syntax. In it he highlighted a case where things would start to become fuzzy. What if you were to specify both the width, height, and aspect-ratio but with a wrong aspect-ratio for that width/height combination?

For example, given an element with width:auto; height:auto; aspect-ratio: 2/1; max-height: 200px; in a 500px wide container, the element would first be set to 500px wide, then aspect-ratio would naively set the height to 250px, which is in violation of the max-height constraint. Instead, the element’s height becomes 200px and the width is set to 400px. If the element additionally had min-width: 450px, aspect-ratio would be completely ignored, as there’s no way to satisfy it.

Given the issue above, another syntax that would please me (and bypass the issue along with that) is this:

.aspectratio[data-ratio="16:9"] {
  width: 100%;
  height: aspect-ratio(16/9);
}

Since you can’t set the height to a fixed unit, no extra calculations would need to be done. Of course you’d run into problems when setting both the width and the height to aspect-ratio(…), but that can be specced out: only the last one defined will be used, the previous ones will revert to auto.

On Twitter it was also pointed out to me that there’s a WICG repo on the issue. Greg Whitworth from Microsoft participates in the repo. The repo contains a link to a spec entitled Logical sizing properties which is also edited by Tab.

The proposed syntax is currently leaning towards this (aspect-ratio needing to be a number):

.aspectratio[data-ratio="16:9"] {
  width: 100%;
  aspect-ratio: calc(16/9);
}

~

So, can we use this “Logical Sizing” thing then? And when?

Given the fact that Tab is present here at CSSDay I’ll be asking him about it later (I’m actually sitting next to him right now, yet he’s currently busy finishing up his slidedeck on Houdini – which he’s about to present later today – so I won’t be bothering him right now 😉).

Speaking of Houdini: I’m not sure this can be fixed with Houdini but perhaps it could … another thing I’ll be asking Tab about.

A follow-up post will definitely land, once I’ve picked Tab his brain on this. To stay in the loop on this I’d recommend one to subscribe to the bram.us RSS feed, or follow bram.us on on Twitter or Facebook.

Elsewhere , 2 Comments

Nicer CSS underlines with text-decoration-skip: ink;

When applying text-decoration: underline; on an element, the line drawn will cross descenders.

Using text-decoration-skip one can control the behavior of the underline

The text-decoration-skip CSS property specifies what parts of the element’s content any text decoration affecting the element must skip over. It controls all text decoration lines drawn by the element and also any text decoration lines drawn by its ancestors.

When set to ink, the underline will skip over descenders:

The text decoration is only drawn where it does not touch or closely approach a glyph. I.e. it is interrupted where it would otherwise cross over a glyph.

MDN text-decoration-skip

Elsewhere , , Leave a comment

Zttp, a developer friendly wrapper for Guzzle

If you’re not familiar with the evolution of Guzzle, the library has basically gotten more professional and less usable with each new version. New layers upon layers of specification-respecting abstractions and rules made Guzzle incredibly difficult to get started with.

Zttp solves just that, by keeping things simple:

Zttp is a simple Guzzle wrapper designed to provide a really pleasant development experience for most common use cases.

$response = Zttp::withHeaders(["Fancy" => "Pants"])->post($url, [
    "foo" => "bar",
    "baz" => "qux",
]);

var_dump($response->json());

As per usual: it depends. Zttp might float your boat, you might need Guzzle itself if you want to do some more advanced things.

Zttp (GitHub) →

(via)

Elsewhere , , Leave a comment

Inclusive Design Principles

These Inclusive Design Principles are about putting people first. It’s about designing for the needs of people with permanent, temporary, situational, or changing disabilities — all of us really.

They are intended to give anyone involved in the design and development of websites and applications – designers, user experience professionals, developers, product owners, idea makers, innovators, artists and thinkers – a broad approach to inclusive design.

Nice straightforward list, clearly explained (both the problem as solutions).

Inclusive Design Principles →

Elsewhere , , Leave a comment

CSS Shapes, Clipping and Masking

The release of Firefox 54 is just around the corner and it will introduce new features into an already cool CSS property: clip-path.

clip-path is a property that allows us to clip (i.e., cut away) parts of an element. Up until now, in Firefox you could only use an SVG to clip an element:

But with Firefox 54, you will be able to use CSS shapes as well: insets, circles, ellipses and polygons!, circles, ellipses and polygons!

Do note that clipping is different from masking. Masking just hides some content – leaving the bounding box unaltered – clipping actually cuts away things:

CSS Shapes, Clipping and Masking →

Elsewhere , , Leave a comment

Safari Auto-Play Policy Changes for macOS

The Safari team:

Safari in macOS High Sierra uses an automatic inference engine to block media elements with sound from auto-playing by default on most websites. Safari 11 also gives users control over which websites are allowed to auto-play video and audio by opening Safari’s new “Websites” preferences pane, or through the “Settings for This Website…” option in the Safari menu. Further, a new power-saving feature prevents silent videos from auto-playing when either hidden in a background tab or otherwise off-screen.

Calling .play() on a <video> element will now return a Promise:

var promise = document.querySelector('video').play();

if (promise !== undefined) {
    promise.catch(error => {
        // Auto-play was prevented
        // Show a UI element to let the user manually start playback
    }).then(() => {
        // Auto-play started
    });
}

Auto-Play Policy Changes for macOS →

Elsewhere , Leave a comment