One of the highlights in the world of web design for 2018 was when Jen Simmons came up with the term Intrinsic Web Design and shared it with the world. Intrinsic Web Design is not a framework. It isn’t a set of rules to follow either. Rather, it is a collection of concepts that highlight what is now possible with modern CSS. How we choose to utilize these concepts for better art direction on the web and to build better layouts, that’s up to us.
Jen covered the following six major concepts when she talked about Intrinsic Web Design:
You’ll notice that none of those concepts pinpoint a specific CSS property or module. That is because CSS works best when various complementary properties are used together. In this post, I want to talk about the concept of stages of squishiness, and how it is going to greatly enhance art direction of editorial content on the web.
Let’s start off with some basics. Browsers perform a lot of computations to ensure that every element gets rendered correctly on a web page. Each element has to have every possible CSS property value resolved and computed before it can be laid out on the page.
According to the visual formatting model, each element in the document tree generates zero or more boxes. And there are numerous factors that influence the dimensions of these boxes.
The CSS specification that covers this in detail is the CSS Intrinsic & Extrinsic Sizing Module Level 3. Extrinsic sizing is based on the context of the element, without taking into account its contents, while intrinsic sizing is based on the contents of the element, without taking into account its context.
Most of us would be familiar with extrinsic sizing because that’s usually what we use to size items in our web pages. Almost every web developer I’ve met started off by doing things like setting
height with fixed CSS units like
px, or relative CSS units like percentages.
Then we’d learn about
em units, and gravitate towards those. Some of us start using viewport units as well, which were another type of relative unit. Sizing in this manner ignores the content in the element altogether, as illustrated in the following Codepens:
It’s not that intrinsic sizing is a new thing, I think it’s more that the usage of intrinsic sizing simply meant leaving things alone. The browser is doing the sizing for us based on the amount of content within the element.
There is a long rule set to determining an element’s width and height, depending on its type (block or inline, replaced or not, positioning scheme etc.), which can be found from the CSS2.1 specification if you’re interested. And the CSS Intrinsic & Extrinsic Sizing Module Level 3 extends the specification further.
One thing I want to remind everyone when it comes to the
height properties is that these two sizing properties do not apply to inline elements. The width of an inline element is determined by the width its rendered content, while the height of an inline element is determined by font size.
The Level 3 specification adds new content-based keywords to the
height properties, namely:
fit-content(), which allows non-inline elements to have more content-based sizing options.
All of these values are supported when used in a Grid formatting context. However, your mileage may vary if you want to use them in sizing properties at the moment.
A common design pattern for responsive design on the web is having columns of content adjust to fit the viewport. Developers would code such layouts with numerous media queries, as the width of each column had to be specified at specific breakpoints. This approach would be achieved with either floats or inline-block, but the mechanism of using numerous media queries is the same.
As you resize the window and observe the columns growing and shrinking, notice that all of the columns grow and shrink at the same rate. This is to be expected because each column is sized as a percentage of the viewport width.
A consequence of this behaviour is that it becomes harder to build layouts that present different types of content at an optimum size across a broad spectrum of viewport sizes. Content with intrinsic aspect ratios, like images, would require more consideration as opposed to textual content, which can flow and adapt more easily.
Let’s take a look at situations where the size of columns grow and shrink at different rates. Such situations may arise when we are operating in a flex formatting context, a grid formatting context when certain track-sizes are applied, or when content-based sizing is used.
For this Flexbox example, I highly recommend reading Rachel Andrew’s step-by-step explanation of how the sizing algorithm works. Here you can see when there is more content in the last column Flexbox gives it more space and shrinks the second column “earlier” for the bottom example versus the top one.
Grid introduces the
fr unit, which is defined as the fraction of the leftover space in the grid container. It behaves similarly to how flex items fill up space within a flex container.
Once all non-flexible tracks have reached their maximum size, the total size of such rows or columns is subtracted from the available space, yielding the leftover space, which is then divided among the flex-sized rows and columns in proportion to their flex factor.
For this Grid-based example, columns are sized with a variety of values, and this affects their resultant behaviour when the viewport size changes. For the first example, the first column is sized with
1fr, which means it takes up the amount of space required for the content plus any available free space. So it will keep growing if the viewport gets wider.
As the viewport shrinks, however, its behaviour is determined by how the other columns are sized. The other two columns are
fit-content(400px), which, as space is taken away, behave similarly because
fit-content resolves to
minmax(auto, max-content), except that it’s clamped at the provided argument value.
For the second example, the last column is sized with
minmax(200px, 400px). Notice that this column holds its maximum size for as long as possible, while other columns shrink. The
fr column shrinks first, followed by the
auto column. But both the
auto column and
minmax() column reach their minimum size at the same time.
Now let’s apply this to an actual design. This example could be for a featured article on an editorial publication, with a large hero image, header and some opening text. Again, I highly recommend opening this demo in a separate window so behaviour across the full width of the viewport can be observed.
The first example is done with percentage sizing, and the limitation here is two-fold. Overlap of the header over the image is a little clunky because it’s done with negative margins. Secondly, the image and text all shrink at the same rate so at the narrowest size, the image is a bit too small and the text is also a bit too squished.
With Grid, the overlap is much easier to manage, as placing items within the grid is a matter of assigning them to the required rows and columns, and there is no limit against having multiple items taking up the same space on the grid.
If you have Firefox installed, open up DevTools and toggle on the Grid inspector, which will show you how the tracks are adjusting as the viewport size changes. In addition, use of
minmax() for track sizing allows the content in the middle column to “hold“ its size as long as possible, while the tracks sized to
auto shrink first.
Such behaviour gives web designers and developers better options and greater flexibility in terms of art direction and ensures that the focus of the content is never lost regardless of the context in which it is viewed in.
I highly encourage developers to try out these newer properties and techniques themselves, as it was through experimentation that I figured a lot of this stuff out. With more developers and designers using these new tools, we’ll have a greater pool of ideas and inspiration for building designs that truly suit the nature of the web.
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Angular’s new `defer` feature, introduced in Angular 17, can help us optimize the delivery of our apps to end users.
ElectricSQL is a cool piece of software with immense potential. It gives developers the ability to build a true local-first application.
Leptos is an amazing Rust web frontend framework that makes it easier to build scalable, performant apps with beautiful, declarative UIs.