Tag: Layout

The Holy Grail Layout with CSS Grid

A reader wrote in asking specifically how to build this layout in CSS Flexbox:

My answer: That’s not really a layout for CSS Flexbox. You could pull it off if you had to, but you’d need some kind of conceit, like grouping the nav and article together in a parent element (if not more grouping). CSS Grid was born to describe this kind of layout and it will be far easier to work with, not to mention that the browser support for both is largely the same these days.

What do you mean by “Holy Grail”?

See, kids, layout on the web used to be so janky that the incredible simple diagram above was relatively difficult to pull off, particularly if you needed the “columns” there to match heights. I know, ridiculous, but that was the deal. We used super weird hacks to get it done (like huge negative margins paired with positive padding), which evolved over time to cleaner tricks (like background images that mimicked columns). Techniques that did manage to pull it off referred to it as the holy grail. (Just for extra clarity, usually, holy grail meant a three-column layout with content in the middle, but the main point was equal height columns).

CSS is much more robust now, so we can use it without resorting to hacks to do reasonable things, like accomplish this basic layout.

Here it is in CSS Grid

This grid is set up both with grid-template-columns and grid-template-rows. This way we can be really specific about where we want these major site sections to fall.

I slipped in some extra stuff

  • I had another question come my way the other day about doing 1px lines between grid areas. The trick there is as simple as the parent having a background color and using gap: 1px;, so I’ve done that in the demo above.
  • It’s likely that small screens move down to a single-column layout. I’ve done that at a media query above. Sometimes I use display: block; on the parent, turning off the grid, but here I’ve left grid on and reset the columns and rows. This way, we still get the gap, and we can shuffle things around if needed.
  • Another recent question I was asked about is the subtle “body border” effect you can see in the demo above. I did it about as simple as possible, with a smidge of padding between the body and the grid wrapper. I originally did it between the body and the HTML element, but for full-page grids, I think it’s smarter to use a wrapper div than use the body for the grid. That way, third-party things that inject stuff into the body won’t cause layout weirdness.

The post The Holy Grail Layout with CSS Grid appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,

Native CSS Masonry Layout In CSS Grid

Rachel Andrew introducing the fact that masonry layout is going to be a thing in native CSS via CSS grid layout. The thing with masonry is that we can already do it for the most part, but there is just one thing that makes it hard: doing the vertical-staggering and having a left-to-right source order. So that’s what this new ability will solve in addition to it just being less hacky in general.

You can already test a partial implementation in Firefox Nightly by enabling layout.css.grid-template-masonry-value.enabled.

.container {   display: grid;   grid-template-columns: repeat(4, 1fr);   grid-template-rows: masonry; }

I like the grid-template-rows: masonry; syntax because I think it clearly communicates: “You aren’t setting these rows. In fact, there aren’t even really rows at all anymore, we’ll take care of that.” Which I guess means there are now rows to inherit in subgrid, which also makes sense.


The post Native CSS Masonry Layout In CSS Grid appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

Logical layout enhancements with flow-relative shorthands

Admission: I’ve never worked on a website that was in anything other than English. I have worked on websites that were translated by other teams, but I didn’t have much to do with it. I do, however, spend a lot of time thinking in terms of block-level and inline-level elements. It’s been a couple of years now since logical properties have started to drop, and they have definitely started to invade my CSS muscle memory.

If you work in top-to-bottom, left-to-right languages like English as I do, you just map top and bottom to block in your head (you probably already do) and left and right as inline. So instead of height, you think block-size. Instead of border-right, you think border-inline-end. Instead of padding: 0 1em, you think padding-inline: 1em. And instead of margin-top, you think margin-block-start.

I mapped out that stuff in another post.

One trouble is that browser support is a little weird. Like margin-block-end is gonna work anywhere that any logical properties at all work, but if you’re like, “I’d like to set both the start and the end (like margin: 1rem 0), so I’ll use just margin-block,” well, that doesn’t work in some browsers (yet). That makes a certain sense, because there is no “direct mapping” of margin-block to any ex-logical CSS property. There are enough other little caveats like that, making me a just a smidge squeamish about using them everywhere.

Still, I’m probably going to start using them a lot more, as even if I still mostly only work on English sites, I like the idea that if I use them consistently, it makes translating any site I work on to languages that aren’t left-to-right and top-to-bottom a lot easier. Not to mention, I just like the mental model of thinking of things as block and inline.

I’m trying to link to Adam Argyle and Oriol Brufau’s article here, so let me just end with a quote from it, putting a point on why using non-logical properties only makes sense for one “language style”:

In English, letters and words flow left to right while paragraphs are stacked top to bottom. In traditional Chinese, letters and words are top to bottom while paragraphs are stacked right to left. In just these 2 cases, if we write CSS that puts “margin top” on a paragraph, we’re only appropriately spacing 1 language style. If the page is translated into traditional Chinese from English, the margin may well not make sense in the new vertical writing mode.

Direct Link to ArticlePermalink


The post Logical layout enhancements with flow-relative shorthands appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Bold on Hover… Without the Layout Shift

When you change the font-weight of a font, the text will typically cause a bit of a layout shift. That’s because bold text is often larger and takes up more space. Sometimes that doesn’t matter, like a vertical stack of links where the wider/bolder text doesn’t push anything anyway. Sometimes it does matter, like a horizontal row where the wider/bolder text pushes other elements away a smidge.

Ryan Mulligan demonstrates:

Ryan’s technique is very clever. Each item in the list has a pseudo-element on it with the exact text in the link. That pseudo-element is visually hidden, but pre-bolded and still occupies width. So when the actual link text is bolded, it won’t take up any additional width.

It also sorta depends on how you’re doing the layout. Here, if I force four columns with CSS grid and text that doesn’t really challenge the width, the bolding doesn’t affect the layout either:

But if I were to, say, let those links flow into automatic columns, we would have the shifting problem.


The post Bold on Hover… Without the Layout Shift appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Fluid Images in a Variable Proportion Layout

Creating fluid images when they stand alone in a layout is easy enough nowadays. However, with more sophisticated interfaces we often have to place images inside responsive elements, like this card:

Screenshot. A horizontal card element with an image of two strawberries against a light blue background to the left of text that contains a heading and two sentences.

For now, let’s say this image is not semantic content, but only decoration. That’s a good use for background-image. And because in this context the image contains an object, we can’t allow any parts to be cropped out when it’s responsive, so we’d pick background-size: contain.

Here’s where it starts to get tricky: on mobile devices, this card shifts direction and becomes vertical, with the image on top. We can make that happen with any sort of CSS layout technique, and probably best handled with CSS grid or flexbox.

Screenshot. The same strawberry card but in a vertical format.

But as we test for smaller screens, because of the contain property, this is what we get:

The same card element in vertical but now the strawberry image is not flush with the top border of the card.
Hey, get back up there!

That’s not very nice. The image resizes to maintain its aspect ratio without cutting off any details, and if the image is important content and should not be cropped, we can’t change background-size to cover.

At this point, our next attempt might be familiar to you: placing the image inline, instead the background. 

On desktop, this works fine:

It’s not bad on mobile either:

But on smaller screens, because of all the fixed sizes, the image’s proportions get distorted.

Screenshot. The vertical card element with the strawberry image out of proportion, causing the strawberries to appear stretched vertically.
Hmm, those strawberries are not as appetizing when stretched.

We could spend hours fiddling with the image, the card, the flex properties, going back and forth. Or, we could…

Separate main content from the background

This is the base for obtaining much more flexibility and resilience when it comes to responsive images. It might not be possible 100% of the time but, in many cases, it can be achieved with a little effort on the design side of things, especially if this approach is planned beforehand.

For our next iteration, we’re placing our strawberries image on a transparent background and setting what was the blue color in the raster image with CSS instead. Go ahead and play with viewport sizes in this demo by adjusting the size of the sample space!

Looking deeper at the styles, notice that we’ve also added padding to the div that holds the image, so the strawberries don’t come too close to the edges. We have full control of how close or distant we want them to be, through this padding.

Note how we’re also using negative margins to compensate for the padding on our outer card wrapper, otherwise we’d get white space all around the image.

Use the object-fit property for inline images

As much as the previous demo works, we can still improve the approach. Up to now, we’ve assumed that the image was un-semantical content — but with this layout, it’s also likely that the image illustration could be more than decoration.

If that’s the case, we definitely don’t want the image to get cut off because that would essentially amount to data loss. It’s semantically better to put the image inline instead of a background to prevent that, and we can use the object-fit property to make it happen.

We’ve extracted the strawberries from the background and it’s now an inline <img> element, but we kept the background color in that same image div. 

Finally, combining the object-fit: contain with a 100% width makes it possible to resize the window and keep the aspect ratio of the strawberries. The caveat of this approach, however, is that we need to set a fixed height for the image on the desktop version — otherwise it’s going to follow the proportion of the set width (and reducing it will alter the layout). That might make things too constrained if we need to generate these cards with a variable amount of text that breaks into several lines.

Coming soon: aspect-ratio

The solution for the concern above might be just around the corner with the upcoming aspect-ratio property. This will enable setting a fixed ratio for an element, like this:

.el {   aspect-ratio: 16 / 9; }

This means we’ll be able to eliminate fixed height and replace it with our calculated aspect ratio. For example, the dimensions in the desktop breakpoint of our last example looked like this:

.image {   /* ... */   height: 184px;   width: 318px; }

With aspect-ratio, we could remove the height declaration and do the math to get the closest ratio that amounts to 184:

.image {   /* ... */   width: 318px; /*  Base width */   height: unset; /* Resets the height that was set outside the media query */   aspect-ratio: 159 / 92; /* Amounts close to a 184px height */ }

The upcoming property is better explored in this article, if you want to learn more about it.

In the end, there are multiple ways to achieve reliably responsive images in a variable proportion layout. However, the trick to make this job easier — and better — does not necessarily lie with CSS; it can be as simple as adapting your images, whether that’s by separating the foreground from background (like we did) or selecting specific images that will still work if a fair portion of the edges get cropped.

The post Fluid Images in a Variable Proportion Layout appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Styling Layout Wrappers In CSS

Two things that strike me often about the web are how many ways there are to go about the same thing and how many considerations go into even the most seemingly simple things.

Working with wrapper elements is definitely on both those lists. Wrappers (or containers or whatever) are so common — especially when establishing grid layouts and boundaries for the elements inside them — that it’s easy to take them for granted and reach for them without stepping back to consider how they work, why we use them, and how to use them effectively.

Ahmed Shadeed wrote up the most exhaustive article on wrappers I’ve ever read. He provides a brief overview of them before diving into a bunch of considerations and techniques for working with them, including:

  • When to use them
  • How to size them
  • Positioning them
  • Adding margin and padding
  • Working with CSS grid and other display values
  • Breaking out of the wrapper
  • Using CSS custom properties

If you take the images from the article, it tells a pretty cool story.

Direct Link to ArticlePermalink

The post Styling Layout Wrappers In CSS appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Grid for layout, flexbox for components

When should we reach for CSS grid and when should we use flexbox? Rachel Andrew wrote about this very conundrum way back in 2016:

Flexbox is essentially for laying out items in a single dimension – in a row OR a column. Grid is for layout of items in two dimensions – rows AND columns.

Ahmad Shadeed wrote a post where he gives the same advice, but from a different angle. He argues we should use grid for layout and flexbox for components:

Remember that old layout method might be perfect for the job. Overusing flexbox or grid can increase the complexity of your CSS by time. I don’t mean they are complex, but using them correctly and in the right context as explained from the examples in this article is much better.

Speaking of which, there’s so many great layout examples in this post, too.

Direct Link to ArticlePermalink

The post Grid for layout, flexbox for components appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

First Steps into a Possible CSS Masonry Layout

It’s not at the level of demand as, say, container queries, but being able to make “masonry” layouts in CSS has been a big ask for CSS developers for a long time. Masonry being that kind of layout where unevenly-sized elements are layed out in ragged rows. Sorta like a typical brick wall turned sideways.

The layout alone is achievable in CSS alone already, but with one big caveat: the items aren’t arranged in rows, they are arranged in columns, which is often a deal-breaker for folks.

/* People usually don't want this */  1  4  6  8 2     7 3  5     9

/* They want this *.  1  2  3  4 5  6     7 8     9

If you want that ragged row thing and horizontal source order, you’re in JavaScript territory. Until now, that is, as Firefox rolled this out under a feature flag in Firefox Nightly, as part of CSS grid.

Mats Palmgren:

An implementation of this proposal is now available in Firefox Nightly. It is disabled by default, so you need to load about:config and set the preference layout.css.grid-template-masonry-value.enabled to true to enable it (type “masonry” in the search box on that page and it will show you that pref).

Jen Simmons has created some demos already:

Is this really a grid?

A bit of pushback from Rachel Andrew

Grid isn’t Masonry, because it’s a grid with strict rows and columns. If you take another look at the layout created by Masonry, we don’t have strict rows and columns. Typically we have defined rows, but the columns act more like a flex layout, or Multicol. The key difference between the layout you get with Multicol and a Masonry layout, is that in Multicol the items are displayed by column. Typically in a Masonry layout you want them displayed row-wise.

[…]

Speaking personally, I am not a huge fan of this being part of the Grid specification. It is certainly compelling at first glance, however I feel that this is a relatively specialist layout mode and actually isn’t a grid at all. It is more akin to flex layout than grid layout.

By placing this layout method into the Grid spec I worry that we then tie ourselves to needing to support the Masonry functionality with any other additions to Grid.

None of this is final yet, and there is active CSS Working Group discussion about it.

As Jen said:

This is an experimental implementation — being discussed as a possible CSS specification. It is NOT yet official, and likely will change. Do not write blog posts saying this is definitely a thing. It’s not a thing. Not yet. It’s an experiment. A prototype. If you have thoughts, chime in at the CSSWG.

Houdini?

Last time there was chatter about native masonry, it was mingled with idea that the CSS Layout API, as part of Houdini, could do this. That is a thing, as you can see by opening this demo (repo) in Chrome Canary.

I’m not totally up to speed on whether Houdini is intended to be a thing so that ideas like this can be prototyped in the browser and ultimately moved out of Houdini, or if the ideas should just stay in Houdini, or what.

The post First Steps into a Possible CSS Masonry Layout appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Exciting Things on the Horizon For CSS Layout

Michelle Barker notes that it’s been a heck of a week for us CSS layout nerds.

  1. Firefox has long had the best DevTools for CSS Grid, but Chrome is about to catch up and go one bit better by visualizing grid line numbers and names.
  2. Firefox supports gap for display: flex, which is great, and now Chrome is getting that too.
  3. Firefox is trying out an idea for masonry layout.

Direct Link to ArticlePermalink

The post Exciting Things on the Horizon For CSS Layout appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

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

, , , , ,
[Top]