Tag: Layout

4 CSS Grid Properties (and One Value) for Most of Your Layout Needs

CSS Grid provides us with a powerful layout system for websites. The CSS-Tricks guide gives you a comprehensive overview of Grid’s properties with layout examples. What we’re going to do here is a reverse approach to show you the smallest possible set of grid properties you need to know to meet most of your layout needs.

These five properties will get you up and running:

  • display (for the grid value)
  • grid-template-columns
  • grid-gap
  • grid-auto-flow
  • grid-column / grid-row

Here’s how simple it is. Let’s assume you want to implement the following layout for small, medium and large screens.

Small and medium-sized screens
Large screen layout

This is the markup we’ll be working with:

 <!-- Stuff before -->  <nav class="container-nav">   <ul>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>   </ul> </nav>  <div class="container-main">   <section class="item item-type-a"></section>   <section class="item item-type-b"></section>   <section class="item item-type-b"></section>   <section class="item container-inner">     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>   </section> </div>  <!-- Stuff after -->

If we apply a few baseline styles, this is what we get, which is already sufficient for small screens:

Now we can get into the grid properties!

Use display: grid to divide the page into independent layout containers

First, we need to determine which parts of the page should be aligned with grid layouts. It is possible to define a single grid layout for the whole page. However, for websites with a very complex structure (e.g. news websites), handling a large grid quickly becomes complicated to wrangle. In this case, I recommend breaking things down into several, independent grid containers.

Like this:

Where do you draw the line between what is and isn’t a grid? Here’s a personal rule of thumb I follow:

If the layout in a particular part of the page does not fit into the grid of an adjacent or surrounding part of the page, make that part its own grid container.

I have drawn the grid lines into the page section with the class .container-main in the following image You may notice that the section with the .container-inner class from the markup does not fit exactly into the grid of rows.

Here’s another possible layout where the small sections fit into the surrounding grid if a finer line raster is chosen. A separate grid container is not absolutely necessary here.

To kick this off, let’s .container-main into a grid container. This is the basic building block for CSS Grid — turning an element into a grid container with the display property:

.container-main {   display: grid;          }

We’ll want to do the same with our other grid containers:

.container-inner {   display: grid;          }  .container-nav {   display: grid;          }

Use grid-template-columns to define the required columns

Next, we’re going to define the number of columns we need in each grid container and how wide those columns should be. My guideline for the number of columns:  use the smallest common multiple of the maximum number of columns required for the different screen sizes.

How does that work? The .container-main element has a total of two columns on medium-sized screens. If we take that and multiply it by the number of columns on large screens (three), we get a total of six columns.

We can do the same for our navigation, the .container-inner element. There are three columns on medium-sized screens, which we multiple by one column on large screens to get a total of three columns.

The .container-nav element provides no number of columns. In this case, the grid system should automatically adjust the number of columns to the number of menu elements. It’s common to add or remove items in a navigation, and it’d be great if it responded accordingly, which is something grid can help us with a little later on.

OK, so we defined the number of columns for each grid container. Let’s use the grid-template-columns property to set those into place. But, first a couple of minor details:

  • The grid-template-columns property is only used on the grid container. In other words, you won’t find it being used (at least correctly) on a grid item inside the container.
  • The property accepts a bunch of different values that both define the number of columns and how wide they should be. The one we’re interested in here is the fractional (fr) unit. I’d highly suggest checking out Robin’s overview because it’s unique to grid and does an amazing job doing calculations to decide how grid elements fit inside a grid container.

We need six equal-width columns in .container-main. We can write that like this:

.container-main {   display: grid;   grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; }

Or, we can turn to the repeat() function to simplify it into something more readable:

.container-main {   display: grid;   grid-template-columns: repeat(6, 1fr); }

Let’s take that knowledge and apply it to our .container-inner element as well, which we decided needs three columns.

.container-inner {   display: grid;   grid-template-columns: repeat(3, 1fr); }

Use grid-gap to add spacing between grid items

By default, grid uses all the space it has in a grid container to fit in grid items. Having elements flush next to one another might be a design requirement, but not for the particular layout we’re making. We want some breathing room between things!

We have the grid-gap property for that. Again, this is a property that’s just for grid containers and what it does is create vertical and horizontal spacing between grid items. It’s actually a shorthand property that combines the vertical spacing powers of grid-row-gap and horizontal spacing powers of grid-column-gap. It’s handy that we’re able to break things out like that but, in times like this where we’re working with the same amount of spacing in each direction, the shorthand grid-gap is much nicer to write.

We want 20px of space between grid items in .container-main, 10px of space in .container-inner, and 5px of space in .container-nav. No problem! All it takes is a one-liner on each grid container.

.container-main{   display: grid;   grid-template-columns: repeat(6, 1fr);   grid-gap: 20px; }  .container-inner {   display: grid;   grid-template-columns: repeat(3, 1fr);   grid-gap: 10px; }  .container-nav {   display: grid;   grid-gap: 5px; }

Use grid-column and grid-row to determine the size of the individual grid items

Now it is time to put the layout into the shape we want it!

First is the grid-column property, which allows us to extend a grid item across n columns, where n is the number of columns to span. If you’re thinking this sounds an awful lot like the rowspan attribute that lets us extend cells across multiple rows in HTML tables, you wouldn’t be wrong.

It looks like this when we use it on a grid .item in our .container-main element, and on the .inner-item elements in .container-inner:

.item {   grid-column: span 6; }  .item-inner {   grid-column: span 3; }

What we’re saying here is that each item span six rows in our main container and three rows in our inner container — which is the total number of columns in each container.

An interesting thing about CSS Grid is that we are able to name the lines of the grid. They come with implicit names out of the box but naming them is a powerful way to distinguish between the starting and ending lines for each column on the track.

We can change the number of columns and rows the items should span at different breakpoints:

@media screen and (min-width: 600px) {   .item-type-b {     grid-column: span 3;   }    .item-inner {     grid-column: span 1;   } }  @media screen and (min-width: 900px) {   .item {     grid-column: span 2;     grid-row: span 2;   }    .item-type-b{     grid-row: span 1;   }    .item-inner{     grid-column: span 3;   } }

Using grid-auto-flow to control the placing of the elements

CSS Grid places elements one row after the other. This is why the result in our example looks like this at the moment:

A column-by-column placement can be achieved by setting the grid-auto-flow property to column (row is the default value). Our layout will profit from column-wise placement in two cases. First, it makes our menu items finally appear in a horizontal orientation. Secondly, it brings the elements of the container class into the desired grouping.

The final result

Conclusion: More or less specification?

The grid system allows us to work under the motto, “make as many specifications as necessary, but as few as possible.” We’ve only covered a few of the specifications necessary to turn elements into a CSS grid container and the items inside it into grid items for the sake of showing just how little you need to know to build even complex layouts with CSS Grid.

CSS Grid supports additional use cases where:

  • We want to make even fewer specifications in order to instead rely more on automatic positioning.
  • We want to make even more specifications in order to determine more details of the resulting layout.

If the first case applies, then it’s worth considering the following additional grid options:

  • When creating the grid with grid-template-columns, you can have the grid system automatically determine the width of individual columns with the auto keyword or adapt it to the existing content with the settings min-content, max-content, or fit-content.
  • You can let the grid system automatically determine the number of required columns with the help of repeat, auto-fill, auto-fit, and minmax. Even media queries can become redundant and these tools help make things flexible without adding more media queries.

Here are a couple of articles on the topic that I recommend: Becoming a CSS Grid Ninja! and Auto-Sizing Columns in CSS Grid: auto-fill vs. auto-fit.

If the second case applies, CSS Grid offers even more settings options for you:

  • You can explicitly specify the width of the columns in the unit of your choice (e.g. px or %) using the grid-template-columns property. In addition, the property grid-template-rows is available to define the number and width of rows, should there be a specific number of them. 
  • You can also define specific column or row numbers for positioning as values for grid-column and grid-row (or use the properties grid-column-start, grid-column-end, grid-row-start, or grid-row-end).

And we haven’t even gotten into CSS Grid alignment! Still, the fact that we can accomplish so much without even broaching that topic shows how powerful CSS Grid is.

The post 4 CSS Grid Properties (and One Value) for Most of Your Layout Needs appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,

Responsive Grid Magazine Layout in Just 20 Lines of CSS

I was recently working on a modern take of the blogroll. The idea was to offer readers a selection of latest posts from those blogs in a magazine-style layout, instead of just popping a list of our favorite blogs in the sidebar.

The easy part was grabbing a list of posts with excerpts from our favorite RSS feeds. For that, we used a WordPress plugin, Feedzy lite, which can aggregate multiple feeds into a single time-ordered list — perfect for showcasing their latest offerings. The hard part was making it all look awesome.

The plugin’s default list UI is rather bland, so I wanted to style it to look like a newspaper or magazine website with a mixture of smaller and larger “featured content” panels.

This seems like an ideal case for CSS Grid! Create a grid layout for different layouts, say, one five-column layout and one three-column layout, then use media queries to switch between them at different break points. Right? But do we actually need those media queries — and all the hassle of identifying break points — when we can use grid’s auto-fit options to automatically create a fluid responsive grid for us? 

The approach sounded tempting, but when I started introducing column-spanning elements, I ran into trouble with the grid overflowing on narrow screens. Media queries appeared to be the only solution. That is, until I found a workaround!

After looking at several tutorials on CSS Grid, I found that they largely fall into two camps:

  1. Tutorials that show you how to create an interesting layout with spanned elements, but for a fixed number of columns.
  2. Tutorials that explain how to make a responsive grid that resizes automatically, but with all of the grid items the same width (i.e. without any spanned columns).

I want to make the grid do both: create a fully responsive fluid layout that includes responsively resizing multi-column elements as well.

The beauty is that once you understand the limitations of responsive grids, and why and when column spans break grid responsiveness, it is possible to define a responsive magazine/news style layout in just a dozen lines of code plus one simple media query (or even with no media queries if you are willing to limit your span options).

Here’s a visual showing the RSS plugin right out of the box and what it’ll look like after we style it up. 

(Demo)

This magazine-style grid layout is fully responsive with the colored featured panels adjusting dynamically as the number of columns change. The page displays around 50 posts, but the layout code is agnostic as to the number of items displayed. Ramp up the plugin to show 100 items and the layout stays interesting all the way down.

All of this is achieved using only CSS and with only a single media query to deal with a single column display on the narrowest of screens (i.e. smaller than 460px).

Incredibly, this layout only took 21 lines of CSS (excluding global content styling). However, to achieve such flexibility in such a few lines of code, I had to dig deep into the more obscure parts of some of  CSS Grid and learn how to work around some of its inherent limitations.

The essential elements of the code that produce this layout is incredibly short and a testament to the awesomeness of CSS Grid:

.archive {   display: grid;   grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));   grid-gap: 32px;   grid-auto-flow: dense; }  /* Extra-wide grid-posts */ .article:nth-child(31n + 1) {   grid-column: 1 / -1; } .article:nth-child(16n + 2) {   grid-column: -3 / -1; } .article:nth-child(16n + 10) {   grid-column: 1 / -2; }  /* Single column display for phones */ @media (max-width: 459px) {   .archive {     display: flex;     flex-direction: column;   } }

The techniques in this article could be used equally well to style any dynamically generated content such as the output from a latest posts widget, archive pages or search results.

Creating a responsive grid

I have set up seventeen items displaying a variety of mock content — headlines, images and excerpts — which are all contained in a wrapper

<div class="archive">   <article class="article">     <!-- content -->   </article>      <!-- 16 more articles -->    </div>

The code that turns these items into a responsive grid is remarkably compact:

.archive {   /* Define the element as a grid container */   display: grid;   /* Auto-fit as many items on a row as possible without going under 180px */   grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));   /* A little spacing between articles */   grid-gap: 1em; }

Notice how the heights of the rows automatically adjust to accommodate the tallest content in the row. If you change the width of the Pen, you will see the items grow and shrink fluidly and the number of columns change from one to five, respectively.

The CSS Grid magic at play here is the auto-fit keyword that works hand-in-hand with the minmax() function that’s applied to grid-template-columns.

How it works

We could have achieved the five-column layout alone using this:

.archive {   display: grid;   grid-template-columns: repeat(5, 1fr); }

However, this would create five columns that grow and shrink with different screen widths, but always stay at five columns, resulting in them becoming ridiculously narrow on small screens. The first thought might be to create a bunch of media queries and redefine the grid with different numbers of columns. That would work fine, but with the auto-fit keyword, it is all done automatically.

For auto-fit to work the way we want, we need to use the minmax() function. This tells the browser how small the columns can be squeezed down to followed by the maximum width they can expand to. Any smaller, and it will automatically reduce the number of columns. Any larger, and the number of columns increases.

.archive {   grid-template-columns: repeat (auto-fit, minmax(180px, 1fr)); }

In this example, the browser will fit in as many columns as it can 180px wide. If there is space left over the columns will all grow equally by sharing the remaining space between them —  that’s what the 1fr value is saying: make the columns equal fractions of the available width. 

Drag the window out and as the available space increases the columns all grow equally to use up any additional space. The columns will keep growing until the available space allows for an additional 180px column, at which point a whole new column appears. Decrease the screen width, and the process reverses, perfectly adjusting the grid all the way down to a single column layout. Magic!

And you get all this responsiveness out of just one line of code. How cool is that? 

Creating spans with “autoflow: dense”

So far, we have a responsive grid but all items the same width. For a news or magazine layout we need some content to be featured by spanning two or more columns or even, perhaps, to span all the columns.

To create multi-column spans we can add the column-span feature to the grid items we want to take up more space. For example, if we want the third item in our list to be two columns wide we can add:

.article:nth-child(3) {   grid-column: span 2; }

However, once we start adding spans a number of problems can arise. First, gaps may appear in the grid because a wide item may may not fit on the row, so grid auto-fit pushes it onto the next line, leaving a gap where it would have been:

The easy fix is adding grid-auto-flow: dense to the grid element which tells the browser to fill in any gaps with other items, effectively making the narrower content flow around the wider items like this:

Note that the items are now out of order, with the fourth item coming before the third item, which is double the width. There is no way round this as far as I can tell, and it is one of the limitations you have to accept with CSS Grid.

Check out Geoff Graham’s “The Auto-Flowing Powers of Grid’s Dense Keyword” for an introduction to grid-auto-flow: dense with examples of how it behaves.

Ways to specify spans

There are several ways to indicate how many columns an item should span. The easiest is to apply grid-columns: span [n] to one of the items, where n  is the number of columns the element will span. The third item in our layout has grid-column: span 2, which explains why it is double the width of other items that only span a single column.

Other methods require you to explicitly define grid lines. The numbering system for grid lines is as follows:

Grid lines can be specified from left-to-right using positive values (e.g. 1, 2, 3) or negative values (e.g. -1, -2, -3) to go from right-to-left. These can be used to place items on the grid using the grid-column property like this:

.grid-item {   grid-column: (start track) / (end track); }

So, this gives us additional ways to specify a spanned item. This is especially flexible as either the start or end value can be replaced with the span keyword. For example, the three-column blue box in the example above could be created by adding any of the following to the eighth grid item:

  • grid-column: 3 / 6
  • grid-column: -4 / -1
  • grid-column: 3 / span 3
  • grid-column: -4 / span 3
  • grid-column: span 3 / -1
  • Etc.

On a non-responsive (i.e. fixed columns) grid, these all produce the same effect (like the blue box above), however, if the grid is responsive and the number of columns changes, their differences start to become apparent. Certain column spans break the  layout with an auto-flowing grid, making the two techniques appear incompatible. Fortunately, there are some solutions which allow us to combine the two successfully. 

First, however, we need to understand the problem.

Overflow side-scrolling problems

Here are some featured areas created using the notation above:

(Demo)

It all looks good at full-width (five columns) but when resized to what should be two columns, the layout breaks like this:

 As you can see, our grid has lost its responsiveness and, although the container has shrunk, the grid is trying to maintain all five columns. To do so, it has given up trying to keep equal-width columns, and the grid is breaking out of the right-hand side of its container, causing horizontal scrolling.

Why is this? The problem comes about because the browser is trying to honor the explicit grid lines we named. At this width, the auto-fit grid should implicitly be displaying two columns, but our grid line numbering system contradicts this by explicitly referring to the fifth grid line. This contradiction leads to the mess. To display our implicit two-column grid correctly, the only line numbers allowed are 1, 2 and 3 and -3, -2, -1, like this:

But if any of our grid items contains grid-column references that lie outside this, such as grid line number 4, 5 or 6 (or -4, -5 or -6), the browser is getting mixed messages. On the one hand, we have asked it to automatic create flexible columns (which should implicitly give us two columns at this screen width) but we have also explicitly referred to grid lines that don’t appear in a two-column grid. When there is a conflict between implicit (automatic) columns and an implicit number of columns, grid always defers to the explicit grid; hence the unwanted columns and horizontal overflow (which has also been aptly named CSS data loss). Just like using grid line numbers, spans can also create explicit columns. So, grid-column: span 3 (the eighth grid item in the demo) forces the grid to explicitly adopt at least three columns, whereas we want it, implicitly display two.

At this point it might seem like the only way forward is to use media queries to change the grid-column values at the width where our layout breaks — but not so fast! That’s what I assumed at first. But after thinking it though a bit more and playing around with various options, I found there are a limited set of workarounds that work all the way down to two columns, leaving just one media query to cover a single column layout for the narrowest screens.

The solutions

The trick, I realized, is to only specify spans using grid lines that appear in the narrowest grid you intend to display. That is a two-column grid in this case. (We will use a media query to cover the single column scenario for very narrow screens.) That means we can safely use grid lines 1, 2 and 3 (or -3, -2 and -1) without breaking the grid.

I initially thought that meant limiting myself to a maximum span of two columns, using combinations of the following:

  • grid column: span 2
  • grid-column: 1 /3
  • grid-column: -3 / -1

Which remains perfectly responsive right down to two columns:

Although this works, it is rather limiting from a design perspective, and not particularly exciting. I wanted to be able to create spans that would be three, four or even five columns wide on large screens. But how? My first thought was that I would have to resort to media queries (OMG old habits die hard!) but I was trying to get away from that approach and think differently about responsive design.

Taking another look at what we can do with just 1 to 3 and -3 to -1, I gradually realized that I could mix positive and negative line numbers for the grid column’s start and end values ,such as 1/-3 and 2/-2. At first glance, this does not seem very interesting. That changes when you realize where these lines are located as you resize the grid: these spanned elements change width with the screen size. This opened up a whole new set of possibilities for responsive column spans: items that will span different numbers of columns as the screen gets wider, without needing media queries.

The first example I discovered is grid-column: 1/-1.This makes the item act like a full-width banner, spanning from the first to the last column at all column numbers. it even works down to one column wide!

By using grid-column: 1/-2, a left-aligned nearly-full-width span could be created that would always leave a one column item to the right of it. When shrunk to two columns it would shrink responsively to a single column. Surprisingly, it even works when shrunk to a single column layout. (The reason seems to be that grid will not collapse an item to zero width, so it remains one column wide, as does grid-column: 1/1.) I assumed grid-column: 2/-1 would work similarly, but aligned with the right-hand edge, and for the most part it does, except at one column display when it causes overflow.

Next I tried 1/-3  which worked fine on wider screen, showing at least three columns, and smaller screens, showing one column. I thought it would do something weird on a two-column grid as the first grid line is the same as the grid line with -3. To my surprise, it still displays fine as a single-column item. 

After a lot of playing around, I came up with eleven possible grid column values using grid line numbers from the two-column grid. Surprisingly, three of these work right down to single-column layouts. Seven more work down to two columns and would only need a single media query to deal with single column display.

Here is the full list:

Responsive grid-column values, showing how they display at different screen sizes in an auto-fit grid. (Demo)

As you can see, although this is a limited subset of every possible responsive span, there are actually a lot of possibilities.

  • 2/-2 is interesting as it creates a centered span which works all the way down to one column! 
  • 3/-1 is  least useful as it causes overflow even with two-columns.
  • 3/-3 was a surprise.

By using a variety of grid-column values from this list, it is possible to create an interesting and fully responsive layout. Using a single media query for the narrowest single-column display, we have ten different grid-column span patterns to play with.  

The single-column media query is generally straightforward as well. The one on this final demo reverts to using flexbox at smaller screens:

@media (max-width: 680px) {   .archive {     display: flex;     flex-direction: column;   }    .article {     margin-bottom: 2em;   } }

Here is the final grid which, as you can see, is fully responsive from one to five columns:

(Demo)

Using :nth-child() to repeat variable length displays

The last trick I used to get my code down to two dozen lines was the :nth-child(n) selector which I used to style multiple items in my grid. I wanted my span styling to apply to multiple items in my feed, so that the featured post boxes appeared regularly throughout the page. To start with I used a comma-separated selector list, like this:

.article:nth-child(2), .article:nth-child(18), .article:nth-child(34), .article:nth-child(50)  {   background-color: rgba(128,0,64,0.8);   grid-column: -3 / -1; }

But I soon found this cumbersome, especially as I had to repeat this list for each child element I wanted to style within each article — such as the title, links and so on. During prototyping, if I wanted to play around with the position of my spanned elements, I had to manually change the numbers in each of these lists, which was tedious and error prone.

That’s when I realized that I could use a powerful feature :nth-child pseudo-selector instead of a simple integer as I had used in the list above. :nth-child(n) can also take an equation, such as :nth-child(2n+ 2), which will target every second child element.

Here is how I used the :nth-child([formula]) to create the blue full-width panels in my grid which appear at the very top of the page, and is repeated just over half way down:

.article:nth-child(31n + 1) {   grid-column: 1 / -1;   background: rgba(11, 111, 222, 0.5); }

The bit in the brackets (31n + 1 ) ensures that the 1st, 32nd, 63rd, etc. child is selected. The browser runs a loop starting with n=0 (in which case 31 * 0 + 1 = 1), then n=1 (31 * 1 + 1 = 32), then n=2 (31 * 2 + 1 = 63). In the last case, the browser realizes that  there is no 63rd child item so it ignores that, stops looping, and applies the CSS to the 1st and 32nd children.

I do something similar for the purple boxes which alternate down the page from right-to-left:

.article:nth-child(16n + 2) {   grid-column: -3 / -1;   background: rgba(128, 0, 64, 0.8); }  .article:nth-child(16n + 10) {   grid-column: 1 / -2;   background: rgba(128, 0, 64, 0.8); }

The first selector is for the right-hand purple boxes. The 16n + 2 makes sure that the styling applies to every 16th grid item, starting with the second item.

The second selector targets the right-hand boxes. It uses the same spacing (16n) but with a different offset (10). As a result, these boxes appear regularly on the right-hand side for grid items 10, 26, 42, etc.

When it comes to the visual styling for these grid items and their contents, I used another trick to reduce repetition. For styles that both boxes share (such as the background-color, for example) a single selector can be used to target both:

.article:nth-child(8n + 2) {   background: rgba(128, 0, 64, 0.8);   /* Other shared syling */ }

This will target items 2, 10, 18, 26, 34, 42, 50, and so forth.  In other words,  it selects both the left- and right-hand featured boxes.

It works because 8n is exactly half of 16n, and because the offsets used in the two separate selectors have a difference of 8 (i.e. the difference between +10 and +2 is 8) 

Final thoughts

Right now, CSS Grid can be used to create flexible responsive grids with minimal code, but this does come with some significant limitations on positioning elements without the retrograde step of using media queries.

It would be great to be able to specify spans that would not force overflow on smaller screens. At the moment, we effectively tell the browser, “Make a responsive grid, please,” which it does beautifully. But when we continue by saying, “Oh, and make this grid item span four columns,” it throws a hissy-fit on narrow screens, prioritizing the four-column span request rather than the responsive grid. It would be great to be able to tell grid to prioritize responsiveness over our span request. Something like this:

.article {   grid-column: span 3, autofit; }

Another issue with responsive grids is the last row. As the screen width changes the last row will frequently not be filled. I spent a long time looking for a way to make the last grid item span (and hence fill) the remaining columns, but it seems you can’t do it in Grid right now. It would be nice if we could specify the item’s start position with a keyword like auto meaning, “Please leave the left-hand edge wherever it falls.” Like this:

.article {   grid-column: auto, -1; }

…which would make the left-hand edge span to the end of the row.

The post Responsive Grid Magazine Layout in Just 20 Lines of CSS appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Print-Inspired Layout on the Web

I always love seeing people get inspired by print design and trying to port it over to the web. There is a much deeper history of interesting print work to draw from, and still a ton of modern work happening that eclipses most digital design work today. The web is fully capable of bold, interesting designs, yet we see it all-too-rarely.

Just lately, we’ve seen a little surge of interest…

Dan Davies took inspiration from nine different print articles and built layouts that are similar in spirit to each of them.


Ahmad Shadeed rebuilt a rather complex grid layout with bold typography inspired by an image from a book.


Facundo Corradini built out a design from The New York Times Style Magazine.


Frederick O’Brien compared newspaper design to web design.

(more…)

,
[Top]

Auto Layout lands in Figma

Here’s a fresh update to my favorite design tool that is thoroughly exciting: Auto layout! That means we can make frames that resize based on the size of the content within it. That’s particularly useful for buttons in a design system where you want to drop a button on the page and then keep its left and right padding equal.

However! The other exciting part of this update is that content can now be nudged down based on the content above it, too — just like on a webpage. If you’re interested in trying out this feature then I’d recommend just booting up Figma where you can immediately hop over to a playground that explains how this game-changing new feature works with a handy step-by-step tutorial.

Direct Link to ArticlePermalink

CSS-Tricks

, , ,
[Top]

The Thought Process Behind a Flexbox Layout

I just need to put two boxes side-by-side and I hear flexbox is good at stuff like that.

Just adding display: flex; to the parent element lays out the children in a row.

Well, that’s cool. I guess I could have floated them, but this is easier.

They should probably take up the full space they have though. Can I just stretch the parent to 100% wide? Well, I can, but that’s apparently not going to affect the child elements.

If the parent element has more space than the children need, it doesn’t do anything to help the children fill the space alone.

Maybe I can use width: 50%; on the children? That works, but I thought the point of flexbox is that you don’t have to be all specific about width. Ah yes, flexbox has all of these ways of expressing the growy-shrinky-initial behavior of children. Looks like flex: 1; is about as easy as it gets here.

Applying flex: 1; to the children allow them to grow and fill the space.

I like how I haven’t had to do any math or hard code values so far. Can I make it a three-up pattern without touching CSS?

Nice.

Hmmm, wait. The sizing is a bit, uhhhh, flexy? Nothing is forcing these boxes to be one-third of the container all the time.

Looks like flex-basis: 33% doesn’t fix this. flex: 0 0 33%; also doesn’t do the trick. Looks like width: 33%; flex-shrink: 0; does though, if we’re really wanting to strongarm it.

Sometimes a design calls for exactly equal size boxes. This is maybe CSS Grid territory, but whatever.

The long word forcing that sizing behavior at narrow widths is perhaps an uncommon scenario. We could have also solved it with word-break: break-word; hyphens: auto; on the child.

Another thing we could do it just let the dang items wrap instead of being so strict about it. Flexbox can do that, right?

Oh hey, that reminds me how cool it is that those first two items are the same height. That’s the default stretch behavior, but it can be controlled as well. And it’s by row, which is why the second row has its own different height.

What if I want that first “Love” block to be on top instead? Looks like I can re-order it, eh? Let’s see, the default order is 0, so to be first, I do order: -1;.

Ha! That kinda worked. But I meant that I want it to take up the full width on the top row. I guess I can just kick it up to flex-basis: 100%; and the others will wrap accordingly.

It’s pretty weird to have the source order and visual order different like this. Maybe that should go in the “don’t ever do this” category.

What if I wanna bail on the whole flexbox thing at a certain point? Part of me wants to change the direction to go vertical with flex-direction: column; and force the children to be full-width. Ah, a simple display: block; on the parent does that in one swoop.

Rather than changing all the flexbox stuff to handle a column layout, we just turn flexbox off.

Flexbox can do way more stuff! One of my favorites is how auto margins work to “push” other elements away when there is space. This is just one little journey playing with some UI and seeing the useful things flexible does along with things that can make it confusing.

The post The Thought Process Behind a Flexbox Layout appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements

I recently had to craft a newspaper-like design that featured multiple row and column spans with divider lines in between them. Take a look at the mockup graphic here and see if it makes you sweat at all. If you’re like me, you have been around a while and know just how difficult this would have been with old layout techniques.

Newspaper design with line dividers between cells

The project came with a few requirements:

  • Show the outlines of the grid
  • Columns can be wider, or longer than others
  • Divider lines must be shown between the various blocks

CSS Grid: Teaching an old layout new tricks

Newspaper layouts can cause headaches because everyday CSS is one-dimensional, meaning that elements flow on either a horizontal or vertical axis. Even modern flexbox layout is still uni-directional.

For a layout like this, we would almost want the properties that good ol’ HTML tables once provided: things like row and column spans to stretch cells in all directions. We would also want the benefits of modern day CSS, with all the responsiveness and flexible boxes that can grow to fill available space.

CSS grid combines the best of tables with the best of flexible boxes. In fact, grid’s even better because it provides the grid-gap property for creating gutters between cells while taking available space into account. Powerful as this may be, how can we create divider-lines exactly in the middle of those gutters?

Let’s look at three techniques to make that happen.

What we’ll create

First, we will build a simplified version of the newspaper design that’ll help illustrate the crux of the three different techniques that we’re going to cover. A deceptively easy design, one would say.

Column and row spans in a CSS grid layout

Technique 1: The faux column

This solution creates “faux” columns that allow us to draw vertical lines, and then place a grid on top. Horizontal dividers are painted if needed. The “faux” columns are created by using pseudo selectors in the grid container.

<div class="frontpage">   <div class="fp-cell fp-cell--1">     <div class="fp-item">1</div>   </div>   <div class="fp-cell fp-cell--2">     <div class="fp-item">2</div>   </div>   <div class="fp-cell fp-cell--3 fp-cell--border-top">     <div class="fp-item">3</div>   </div>   <div class="fp-cell fp-cell--4 fp-cell--border-top">     <div class="fp-item">4</div>   </div> </div>

See the Pen
Newspaper-design, ‘faux-column’ technique
by Marco Troost (@marco-troost)
on CodePen.

Setting up the lines between the columns

Let’s create a three-column container using display: grid and pseudo-selectors (:before and :after) to create two columns that fill 100% of the container’s height.

.frontpage {   position: relative;   display: grid;   /* Three columns */   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  /* Two faux columns */ .frontpage:before, .frontpage:after {   position: absolute;   top: 0;   height: 100%;   content: '';   width: calc(33.3% - 4px); }  .frontpage:before {   left: 0;   border-right: 1px solid #DADCE0; }  .frontpage:after {   right: 0;   border-left: 1px solid #DADCE0; }

Note: 33% of the container doesn’t take the gutter width into account, so you’ll have to compensate accordingly.

This is calculated as:

33% minus (gutter-width divided by (amount of gutters times amount of gutters)) divided by amount of gutters)

Or, with actual numbers:

33% - (32 / (2* 2)) / 2 = 4

We could use one pseudo-selector instead:

.frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  .frontpage:before {   box-sizing: border-box;   position: absolute;   top: 0;   height: 100%;   content: '';   left: calc(33.3% - 5.3px);   width: calc(33.3% + 10.7px);   border-left: 1px solid #DADCE0;   border-right: 1px solid #DADCE0; }

See the Pen
Newsgrid-layout ‘faux-columns’ (using only :before)
by Marco Troost (@marco-troost)
on CodePen.

Note: A different calculation is needed when using only one pseudo-selector: One for positioning, and one for width.

The width is calculated as:

33% plus (amount of gutters times gutter-width) / (amount of gutters times amount of columns)

Again, with actual numbers:

33% + (2 * 32) / (2 * 3) = 10.7

The position is calculated as:

33% minus (amount of gutters times gutter-width) / (amount of gutters times amount of columns) divided by 2)

Making the grid

The design consists of four blocks of content. We’re going to place them in the container and give them a modifier class for future reference while making sure their z-index is higher than the pseudo-selectors of the grid.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3"></div>   <div class="fp-cell fp-cell--4"></div> </div>

Now let’s set the background color for the cells (.fp-cell) to white. This way, the vertical lines won’t show through. We can also set the vertical padding for the cell to 16px in order to match half of the gutter.

The first and second content blocks should get their own unique spans as shown in the design. The first block spans all the way down and the second block spans the second and third columns.

.fp-cell {   position: relative;   z-index: 2;   padding: 16px 0;   background-color: #fff; }  /* Span all the way down! */ .fp-cell--1 {   grid-row: 1 / span 2; }  /* Span the second and third columns */ .fp-cell--2 {   grid-column: 2 / span 2; }

Vertical line dividers

If you look at the design, only the last two cells need a horizontal border. We can give ’em a sweet modifier class.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3 fp-cell--border-top"></div>   <div class="fp-cell fp-cell--4 fp-cell--border-top"></div> </div>
.fp-cell--border-top:before {   content: '';   position: absolute;   top: 0;   left: -16px;   right: -16px;   border-top: 1px solid #DADCE0; }

The negative margins are half of the gutter width.

Technique #2: Using background-color

Another way to create the dividers is to utilize the grid-gap property. This solution doesn’t necessarily create a “real” distance between cells, but rather leaves some blank space where the background-color of the grid can shine through. The gutter width is delegated to padding within the grid cells.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">       <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   overflow-x: hidden;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   margin: 0 -16px;   background-color: #DADCE0; }  .fp-cell {   background-color: #fff;   padding: 16px; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, background-color technique
by Marco Troost (@marco-troost)
on CodePen.

Since all cells have an extra 16px of horizontal padding, the grid needs to be offset by just as much. A wrapper container will take care of the overflow.

<div class="container">   <div class="frontpage">   <!-- ... -->   </div> </div>
.container {   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   background-color: #DADCE0;   margin: 0 -16px; }

Technique #3: Creating a cell border

This solution appends a right and bottom border to each cell. Like the last example, the grid-gap is mimicked by adding padding to the cell content. That means it also needs to be wrapped in an extra container.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">         <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   border-top: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }  .fp-cell {   padding: 16px;   background-color: #fff;   border-right: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, ‘cell-border’-technique
by Marco Troost (@marco-troost)
on CodePen.

As mentioned, each cell is given a border on the right and on the bottom. The main trick here is the use of the (asymmetrical) negative margin on the grid. This is needed to compensate for the cell’s right border.

.frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }

Conclusion

Occam’s razor stipulates that the simplest solution wins. In our case, that’s technique number two. But then again, the other solutions have plenty of merit and they could prove useful if, for example, access to the DOM is not possible.

All of these techniques will work. Choosing the right one depends on your use case. The first technique uses the actual grid-gap property to create the gaps, but the others are perhaps easier to understand at a glance… and perhaps easier to maintain as well.

The post Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

Adaptive Photo Layout with Flexbox

Let’s take a look at a super lightweight way to create a horizontal masonry effect for a set of arbitrarily-sized photos. Throw any set of photos at it, and they will line up edge-to-edge with no gaps anywhere.

The solution is not only lightweight but also quite simple. We’ll be using an unordered list of images and just 17 lines of CSS, with the heavy lifters being flexbox and object-fit.

Why?

I have two hobbies: documenting my life with photos, and figuring out interesting ways to combine CSS properties, both old and new.

A couple of weeks ago, I attended XOXO and shot a ton of photos which I narrowed down to a nice little set of 39. Wanting to own my content, I’ve spent the past couple of years thinking about putting together a simple photo blog, but was never able to nail the layout I had in mind: a simple masonry layout where photos fill out rows while respecting their aspect ratio (think Photos.app on iOS, Google Photos, Flickr…).

I did some research to see if there were any lightweight, non-JavaScript options, but couldn’t find anything suiting my needs. Facing some delayed flights, I started playing around with some code, limiting myself to keep things as simple as possible (because that’s my definition of fun).

Basic Markup

Since I’m basically creating a list of images, I opted for an unordered list:

<ul>   <li>     <img>   </li>   <!-- ... -->   <li>     <img>   </li> </ul>

All hail flexbox

Then came a string of lightbulb moments:

  • Flexbox is great for filling up rows by determining cell width based on cell content.
  • This meant the images (landscape or portrait) all needed to have the same height.
  • I could use object-fit: cover; to make sure the images filled the cells.

In theory, this sounded like a solid plan, and it got me a result I was about 90% happy with.

ul {   display: flex;   flex-wrap: wrap; }  li {   height: 40vh;   flex-grow: 1; }  img {   max-height: 100%;   min-width: 100%;   object-fit: cover;   vertical-align: bottom; }

Note: 40vh seemed like the best initial approach for desktop browsers, showing two full rows of photos at a reasonable size, and hinting at more below. This also allowed more photos per line, which dramatically improves the aspect ratios.

Last row stretchiness

The only issue I ran into is that flexbox really wants to fill all the lines, and it did some silly things to the aspect ratios of the photos on the last row. This is probably my least favorite bit of this layout, but I had to add an empty <li> element at the end of the list.

<ul>   <li>     <img>   </li>   <!-- ... -->   <li>     <img>   </li>   <li></li> </ul>

Combined with this bit of CSS:

li:last-child {   flex-grow: 10; }

Note: There’s no science in using “10” here. In all my testing, this delivered the best results.

Demo

See the Pen
Adaptive Photo Layout
by Tim Van Damme (@maxvoltar)
on CodePen.

Viewport optimization

There are some considerations to keep in mind when working in different viewport orientations.

Portrait

If your viewport is taller than it is wide, this approach limits the amount of photos per line thus messing up their aspect ratios. To solve this, you can make the photo rows less tall with this simple media query:

@media (max-aspect-ratio: 1/1) {   li {     height: 30vh;   } }

Short Screens

To help with small devices in landscape, increasing the height of photos helps to see them as large as possible:

@media (max-height: 480px) {   li {     height: 80vh;   } }

Smaller Screens + Portrait

Most phones aren’t wide enough to allow flexbox to properly do its job without miniaturizing the photos, so here I opted to not try to fit multiple photos per line. Still, it’s worth setting a maximum height here so you’ll at least have a hint at the next photo in the list.

@media (max-aspect-ratio: 1/1) and (max-width: 480px) {   ul {     flex-direction: row;   }    li {     height: auto;     width: 100%;   }    img {     width: 100%;     max-height: 75vh;     min-width: 0;   } }

There we have it!

This approach doesn’t fully respect the aspect ratios of photos (but it’s close) and occasionally leads to some weird results, but I absolutely love the simplicity and flexibility of it all. Want to have your gallery scroll horizontally instead of vertically? A couple of tweaks will allow you to do this. Are there 1,000 photos in the gallery or just one? It’ll all look good. Unclear about aspect ratios? Flexbox is your best friend. Take another look at the demo if you haven’t yet, and let me know what you think!

Bonus

Depending on the size of these photos, a page like this can grow to multiple megabytes real quick. On the blog I’m working on, I’ve added loading="lazy" to help with this. With that attribute in place on the images, it only loads photos once you approach them while scrolling. It’s supported just in Chrome for now, but you could roll your own more supported technique.

The post Adaptive Photo Layout with Flexbox appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Weekly Platform News: Layout Shifts, Stalled High-Bitrate Videos, Screenshots in Firefox

In this week’s roundup: fighting shifty layouts, some videos might be a bit stalled, and a new way to take screenshots in Firefox.

Let’s get into the news!

Identifying the causes of layout shifts during page load

You can now use WebPageTest to capture any layout shifts that occur on your website during page load, and identify what caused them.

Step 1: Paste a snippet

Paste the following snippet into the “Custom Metrics” on webpagetest.org in field in the Custom tab (under Advanced Settings) and make sure that a Chrome browser is selected.

[LayoutShifts] return new Promise(resolve => {   new PerformanceObserver(list => {     resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));   }).observe({type: "layout-shift", buffered: true}); });

Step 2: Inspect entries

After completing the test, inspect the captured LayoutShifts entries on the Custom Metrics page, which is linked from the Details section.

Step 3: Check the filmstrip

Based on the "startTime" and "value" numbers in the data, use WebPageTest’s filmstrip view to pinpoint the individual layout shifts and identify their causes.

(via Rick Viscomi)

A high bitrate can cause your videos to stall

If you serve videos for your website from your own web server, keep an eye on the video bitrate (the author suggests FFmpeg and streamclarity.com). If your video has a bitrate of over 1.5 Mbps, playback may stall one or more times for people on 3G connections, depending on the video’s length.

50% of videos in this study have a bitrate that is greater than the downlink speed of a 3G connection — meaning that video playback will be delayed and contain stalls.

(via Doug Sillars)

Firefox’s :screenshot command

Firefox’s DevTools console includes a powerful command for capturing screenshots of the current web page. Like in Chrome DevTools, you can capture a screenshot of an individual element, the current viewport, or the full page, but Firefox’s :screenshot command also provides advanced options for adjusting the device pixel ratio and setting a delay.

// capture a full-page screenshot at a device pixel ratio of 2 :screenshot --fullpage --dpr 2  // capture a screenshot of the viewport with a 5-second delay :screenshot --delay 5

(via Reddit)


Read even more news in my weekly Sunday issue, which can be delivered to you via email every Monday morning.

Web Platform News: Sunday issue →

The post Weekly Platform News: Layout Shifts, Stalled High-Bitrate Videos, Screenshots in Firefox appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , , , ,
[Top]

The Fight Against Layout Jank

A web page isn’t locked in stone just because it has rendered visually. Media assets, like images, can come in and cause the layout to shift based on their size, which typically isn’t known in fluid layouts until they do render. Or fonts can load and reflow layout. Or XHRs can bring in more content to be placed onto the page. We’re always doing what we can to prevent the layout from shifting around — that’s what I mean by layout jank. It’s awkward and nobody likes it. At best, it causes you to lose your place while reading; at worst, it can mean clicking on something you really didn’t mean to.

While I was trying to wrap my head around the new Layout Instability API and chatting it out with friends, Eric Portis said something characteristically smart. Basically, layout jank is a problem and it’s being fought on multiple fronts:

The post The Fight Against Layout Jank appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Every Layout

Every Layout is a new work-in-progress website and book by Heydon Pickering and Andy Bell that explains how to make common layout patterns with CSS. They describe a lot of the issues when it comes to the design of these layouts, such as responsive problems and making sure we all write maintainable code, and then they’ve provided a handy generator at the end of each article to create our own little frameworks for dealing with these things.

They also have a complementary blog and one of the posts called “Algorithmic Design” caught my eye:

We make many of our biggest mistakes as visual designers for the web by insisting on hard coding designs. We break browsers’ layout algorithms by applying fixed positions and dimensions to our content.

Instead, we should be deferential to the underlying algorithms that power CSS, and we should think in terms of algorithms as we extrapolate layouts based on these foundations. We need to be leveraging selector logic, harnessing flow and wrapping behavior, and using calculations to adapt layout to context.

The tools for flexible, robust, and efficient web layout are there. We are just too busy churning out CSS to use them.

I’m looking forward to seeing where this project goes and how many more layouts these two end up documenting.

Direct Link to ArticlePermalink

The post Every Layout appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]