Expandable Sections Within a CSS Grid

https://css-tricks.com/expandable-sections-within-a-css-grid/

https://css-tricks.com/?p=353473

I love CSS Grid. I love how, with just a few lines of code, we can achieve fully responsive grid layouts, often without any media queries at all. I’m quite comfortable wrangling CSS Grid to produce interesting layouts, while keeping the HTML markup clean and simple.

But recently, I was presented with a unique UI conundrum to solve. Essentially, any given grid cell could have a button that would open up another, larger area that is also part of the grid. But this new larger grid cell needed to be:

  1. right below the cell that opened it, and
  2. full width.

Turns out there is a nice solution to it, and in the spirit of CSS Grid itself, it only involves a couple of lines of code. In this article, I’ll combine three one-line CSS Grid “tricks” to solve this. No JavaScript needed at all.

An explanation of the actual problem I need to solve

Here’s a minimalist UI example of what I needed to do:

This is our actual product card grid, as rendered in our Storybook component library:

A grid of product cards in a three by two layout. Each card has a placeholder gray image, product name, descriptions, price, and small text.

Each product card needed a new “quick view” button added such that, when clicked, it would:

  • dynamically “inject” a new full-width card (containing more detailed product information) immediately below the product card that was clicked,
  • without disrupting the existing card grid (i.e. retain the DOM source order and the visual order of the rendered cards in the browser), and
  • still be fully responsive.

Hmmm… was this even possible with our current CSS Grid implementation?

Surely I would need to resort to JavaScript to re-calculate the card positions, and move them around, especially on browser resize? Right?

Google was not my friend. I couldn’t find anything to help me. Even a search of “quick view” implementations only resulted in examples that used modals or overlays to render the injected card. After all, a modal is usually the only choice in situations like this, as it focuses the user on the new content, without needing to disrupt the rest of the page.

I slept on the problem, and ultimately came to a workable solution by combining some of CSS Grid’s most powerful and useful features.

CSS Grid Trick #1

I was already employing the first trick for our default grid system, and the product card grid is a specific instance of that approach. Here’s some (simplified) code:

.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, 20rem);
}

The “secret sauce” in this code is the grid-template-columns: repeat(auto-fit, 20rem); which gives us a grid with columns (20rem wide in this example) that are arranged automatically in the available space, wrapping to the next row when there’s not enough room.

Curious about auto-fit vs auto-fill? Sara Soueidan has written a wonderful explanation of how this works. Sara also explains how you can incorporate minmax() to enable the column widths to “flex” but, for the purposes of this article, I wanted to define fixed column widths for simplicity.

CSS Grid Trick #2

Next, I had to accommodate a new full-width card into the grid:

.fullwidth {
  grid-column: 1 / -1;
}

This code works because grid-template-columns in trick #1 creates an “explicit” grid, so it’s possible to define start and end columns for the .fullwidth card, where 1 / -1 means “start in column 1, and span every column up to the very last one.”

Great. A full-width card injected into the grid. But… now we have gaps above the full-width card.

Two rows of four rectangles. All of the rectangles are light gray and numbered, except one that has a wheat-colored background and another box beneath it containing text, and taking up the full container width.

CSS Grid Trick #3

Filling the gaps — I’ve done this before with a faux-masonry approach:

.grid {
  grid-auto-flow: dense;
}

That’s it! Required layout achieved.

The grid-auto-flow property controls how the CSS Grid auto-placement algorithm works. In this case, the dense packing algorithm tries to fills in holes earlier in the grid.

  • All our grid columns are the same width. Dense packing also works if the column widths are flexible, for example, by using minmax(20rem, 1f).
  • All our grid “cells” are the same height in each row. This is the default CSS Grid behavior. The grid container implicitly has align-items: stretch causing cells to occupy 100% of the available row height.

The result of all this is that the holes in our grid are filled — and the beautiful part is that the original source order is preserved in the rendered output. This is important from an accessibility perspective.

See MDN for a complete explanation of how CSS Grid auto-placement works.

The complete solution

These three combined tricks provide a simple layout solution that requires very little CSS. No media queries, and no JavaScript needed.

But… we do still need JavaScript?

Yes, we do. But not for any layout calculations. It is purely functional for managing the click events, focus state, injected card display, etc.

For demo purposes in the prototype, the full-width cards have been hard-coded in the HTML in their correct locations in the DOM, and the JavaScript simply toggles their display properties.

In a production environment, however, the injected card would probably be fetched with JavaScript and placed in the correct location. Grid layouts for something like products on an eCommerce site tend to have very heavy DOMs, and we want to avoid unnecessarily bloating the page weight further with lots of additional “hidden” content.

Quick views should be considered as a progressive enhancement, so if JavaScript fails to load, the user is simply taken to the appropriate product details page.

Accessibility considerations

I’m passionate about using correct semantic HTML markup, adding aria- properties when absolutely necessary, and ensuring the UI works with just a keyboard as well as in a screen reader.

So, here’s a rundown of the considerations that went into making this pattern as accessible as possible:

  • The product card grid uses a <ul><li> construct because we’re displaying a list of products. Assistive technologies (e.g. screen readers) will therefore understand that there’s a relationship between the cards, and users will be informed how many items are in the list.
  • The product cards themselves are <article> elements, with proper headings, etc.
  • The HTML source order is preserved for the cards when the .fullwidth card is injected, providing a good natural tab order into the injected content, and out again to the next card.
  • The whole card grid is wrapped in an aria-live region so that DOM changes are announced to screen readers.
  • Focus management ensures that the injected card receives keyboard focus, and on closing the card, keyboard focus is returned to the button that originally triggered the card’s visibility.

Although it isn’t demonstrated in the prototype, these additional enhancements could be added to any production implementation:

  • Ensure the injected card, when focused, has an appropriate label. This could be as simple as having a heading as the first element inside the content.
  • Bind the ESC key to close the injected card.
  • Scroll the browser window so that the injected card is fully visible inside the viewport.

Wrapping up

So, what do you think?

This could be a nice alternative to modals for when we want to reveal additional content, but without hijacking the entire viewport in the process. This might be interesting in other situations as well — think photo captions in an image grid, helper text, etc. It might even be an alternative to some cases where we’d normally reach for <details>/<summary> (as we know those are only best used in certain contexts).

Anyway, I’m interested in how you might use this, or even how you might approach it differently. Let me know in the comments!


The post Expandable Sections Within a CSS Grid appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Different Degrees of Custom Property Usage

https://css-tricks.com/different-degrees-of-custom-property-usage/

https://css-tricks.com/?p=353057

One way to work with Custom Properties is to think of them as design tokens. Colors, spacings, fonts, and whatnot. You set them at the root of the page and use them throughout your CSS. Very useful, and the classic use case for not only Custom Properties but for preprocessor variables for the last one million years.

Another way to work with Custom Properties, which can be done in addition to the design tokens approach, is to go a lot harder and use them for every major unique styling choice on any given element.

Imagine you have a Card like this (simplified for demonstration sake, of course):

.card {
  background: hsl(200deg 15% 73%);
  border: 4px solid rgb(255 255 255 / 0.5);
  padding: 2rem;
  border-radius: 8px;
}
.card > h2 {
  margin: 0 0 1rem 0;
  border-bottom: 3px solid rgba(0 0 0 / 0.2);
}

Fine.

But then when you inevitably make variations of the card, you’re on your own to override these rulesets. A CSS Custom Property approach can be like:

.card {
  --card-background: hsl(200deg 15% 73%);
  --card-border: 4px solid rgb(255 255 255 / 0.5);
  --card-padding: 2rem;
  --card-border-radius: 8px;
  --card-title-margin: 0 0 1rem 0;
  --card-title-border: 3px solid rgba(0 0 0 / 0.2);

  background: var(--card-background);
  border: var(--card-border);
  padding: var(--card-padding);
  border-radius: var(--card-border-radius);
}
.card > h2 {
  margin: var(--card-title-margin);
  border-bottom: var(--card-title-border);
}

A little more verbose, for now, but look what happens when we want to do a variation:

.card-variation {
  --card-background: purple;
  --card-padding-block: 2.5rem;
  --card-title-margin: 0 0 2rem 0;
} 

Here are three clear advantages right off the bat:

  • I’m only changing values that I’ve clearly set up to be changed. My main Card prototype maintains the integrity I want it to keep.
  • I can style children of the variation without having to re-write those selectors correctly.
  • I can now pass in styling overrides from the style attribute in the HTML for quick, one-off variations.

Less verbose with fallbacks

Rather than declaring the Custom Properties at the top and then using them right below, I can do both at the same time like this:

.card {
  background: var(--card-background, hsl(200deg 15% 73%));
  border: var(--card-border, 4px solid rgb(255 255 255 / 0.5));
  padding: var(--card-padding, 2rem);
  border-radius: var(--card-border-radius, 8px);
}
.card > h2 {
  margin: var(--card-title-margin, 0 0 1rem 0);
  border-bottom: var(--card-title-border, 3px solid rgba(0 0 0 / 0.2));
}

Now if something like --card-background does happen to get set, it will override the fallback value here. I don’t completely love this, because it means elements above .card can override it. That might be what you want, but it’s not exactly the same as declaring the values at the .card level to begin with. No strong opinions here.

Breaking it up even more

An example here is that you might want to individually control padding.

.card {
  --card-padding-block: 2rem;
  --card-padding-inline: 2rem;
  --card-padding: var(--card-padding-block) var(--card-padding-inline);

  padding: var(--card-padding);
}

Now a variation can control just a part of the padding if I want:

.card-variation {
  --card-padding-inline: 3rem;
}

You gotta be careful of the big gotcha though. Meaning if you declare all these at the root, this isn’t going to work, because those nested properties have already been resolved. But so long as it’s first declared on .card, you’ll be fine here.

Too far?

Say you wanted super ultimate control over every part of a value. For example:

html {
  --color-1-h: 200deg;
  --color-1-s: 15%;
  --color-1-l: 73%;
  --color-1-hsl: var(--color-1-h) var(--color-1-s) var(--color-1-l);
  --color-1: hsl(var(--color-1-hsl));
}

That’s kinda neat, but it’s likely too far. Colors are almost certainly going to be declared at the root and left alone, so the great gotcha is going to make overriding the low-level child properties impossible. Besides, if you have a --color-1, you probably have a 2-9 (or more) as well, which is all well and good because there is far more delicate design magic to a color system than simple mathematical manipulations of color parts.

Deliverable design systems?

There is no doubt that Tailwind has enjoyed a lot of popularity. It uses an atomic approach where a slew of HTML classes control one property each. I’d argue some of that popularity is driven by the fact that if you choose from these pre-configured classes, that the design ends up fairly nice. You can’t go off the rails. You’re choosing from a limited selection of values that have been designed to look good.

I wouldn’t go as far as to say that a Custom Properties heavy-based approach to styling is exactly the same. For example, you’ll still need to think of a class name abstraction rather than apply styling directly to the HTML element. But, it might enjoy some of the same constraints/limitations that make Tailwind and other atomic class approaches desirable. If you can only pick from a pre-defined set of --spacing-x values, --color-x values, and --font-x values, you might achieve a more cohesive design than you would have otherwise.

Personally, I’ve found inching toward a design system that is more heavily based on Custom Properties feels good — if nothing else to make variations and overrides more sensible to manage.

What about third-party design systems delivering what they deliver as… nothing but a big ol’ set of Custom Properties to use at your leisure?

Pollen

Third-party deliverables don’t even have to be the entire kitchen sink like this. For example, Adam Argyle’s transition.style provides a “Hackpack” that is nothing but Custom Properties of transition animation helpers.

Understandabilty cost

One pushback I’ve heard against this more all-in approach on Custom Properties is newcomer understandability. If you wrote the system, it probably makes perfect sense to you. But it’s an additional abstraction on top of CSS. CSS knowledge is shared by all, bespoke systems knowledge is only shared by the people actively working on it.

Rolling in fresh to a system heavily using Custom Properties is going to have a heck of a learning curve.

Videos


The post Different Degrees of Custom Property Usage appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Embedded Analytics Made Simple With Cumul.io Integrations

https://css-tricks.com/embedded-analytics-made-simple-with-cumul-io-integrations/

https://css-tricks.com/?p=353243

(This is a sponsored post.)

Browse through SaaS communities on Twitter, LinkedIn, Reddit, Discord, you name it and you’ll see a common theme appear in many of them. That theme can go by many names: BI, analytics, insights and so on. It’s natural, we do business, collect data, we succeed or fail. We want to look into all of that, make some sense of the data we have and take action. This need has produced many projects and tools that make the lives of anyone who wants to look into the data just a bit easier. But, when humans have, humans want more. And in the world of BI and analytics, “more” often comes in the form of embedding, branding, customized styling and access and so on. Which ends up meaning more work for developers and more time to account for. So, naturally there has been a need for BI tools that will let you have it all.

Let’s make a list of challenges you may face as the builder and maintainer of these dashboards:

  1. You want to make the dashboards available to end users or viewers from within your own application or platform
  2. You want to be able to manage different dashboard collections (i.e. “integrations”)
  3. You want to be able to grant specific user rights to a collection of dashboards and datasets
  4. You want to make sure users have access to data only relevant to them

Cumul.io provides a tool we call Integrations which helps solve these challenges. In this article I’ll walk you through what integrations are, and how to set one up. The cool thing is that for most of the points above, there is minimal code required and for the most part can be set within the Cumul.io UI.

Some Background — Integrations

An Integration in Cumul.io is a structure that defines a collection of dashboards intended to be used together (e.g. in the same application). It is also what we use to embed dashboards into an application. In other words, to embed dashboards into an application, we give the application access to the integration that they belong to. You can associate dashboards to an integration and administrate what type of access rights the end users of the integration will have on these dashboards and the datasets they use. A dashboard may be a part of multiple integrations, but it may have different access rights on different integrations. When it comes to embedding, there are a number of SDKs available to make life simple regardless of what your stack looks like. 😊

Once you have a Cumul.io account and if you are an “owner” of an organization in Cumul.io, you will be able to manage and maintain all of your integrations via the Integrations tab. Let’s have a look at an example Cumul.io account. Below you can see the Dashboards that one Cumul.io user might have created:

Although these are all the dashboards this user may have created, it’s likely that not all dashboards are intended for the same end-users, or application for that matter. So, the owner of this Cumul.io account would create and maintain an Integration (or more!) 💪 Let’s have a look at what that might look like for them:

So, it looks like the owner of this Cumul.io account maintains two separate applications.

Now let’s see what the process of creating an integration and embedding its dashboards into an application would look like. The good news is, as mentioned before, a lot of the steps you will have to take can be done within the Cumul.io UI.

Disclaimer: For the purposes of this article, I’ll solely focus on the Integration part. So, I’ll be skipping everything to do with dashboard creation and design and we will be starting with a pre-made set of imaginary dashboards.

What we will be doing:

Creating an Integration

For simplicity, let’s only create one integration for now. Let’s imagine we have an analytics platform that we maintain for our company. There are three dashboards that we want to provide to our end-users: the Marketing Dashboard, the Sales Dashboard and the Leads Dashboard.

Let’s say that out of all the dashboards this account has created or has access to, for this particular project they want to use only the following:

New Integration

To create the integration, we go to the Integrations tab and select New Integration. The dialogue that pops up will already give you some idea of what your next steps will be:

Selecting Dashboards

Next up, you will be able to select which of your dashboards will be included in this integration. You will also be able to give the Integration a name, which here I’ve decided will appropriately be “Very Important Integration”:

Once you confirm your selection, you will have the option of defining a slug for each dashboard (highly recommended). These can later be used while embedding the dashboards into your application. You will later see that slugs make it easy to reference dashboards in your front-end code, and make it easier to replace dashboards if needed too (as you won’t need to worry about dashboard IDs in the front-end code).

Access Rights

You will then get to set the integration’s access rights for the datasets its dashboards use. Here we set this to “Can view.” For more info on access rights and what they entail, check out our associating datasets to integrations:

Filters and Parameters (and Multi-Tenant Access)

Side Note: To help with multi-tenant access — which would make sense in this imaginary set up — Cumul.io makes it possible to set parameters and filters on datasets that a dashboard uses. This means that each user that logs into your analytics platform would only see the data they personally have access to in the dashboards. You can imagine that in this scenario access would be based on which department the end user works for in the company. For more on how to set up multi-tenancy with Cumul.io, check out our article, “Multi-Tenancy on Cumul.io Dashboards with Auth0”. This can be done within the dashboard design process (which we are skipping), which makes it easier to visualize what the filters are doing. But here, we will be setting these filters in the Integration creation process.

Here, we set the filters the datasets might need to have. In this scenario, as we filter based on the users’ departments, we define a department parameter and filter based on that:

And voilà! Once you’re done with setting those, you have successfully created an integration. The next dialogue will give you instructions for what will be your next steps for embedding your integration:

Now you’ll be able to see this brand new Integration in your Integration tab. This is also where you will have quick access to the Integration ID, which will later be used for embedding the dashboards.

Good news! After your Integration is created, you can always edit it. You can remove or add dashboards, change the slugs of dashboards or access rights too. So you don’t have to worry about creating new integrations as your application changes and evolves. And as editing an integration is all within the UI, you won’t need to worry about having a developer set it all up again. Non-technical users can adapt these integrations on the go.

Embedding Dashboards

Let’s see where we want to get to. We want to provide the dashboards within a custom app. Simple, user logs into an app, the app has dashboards, they see the dashboards with the data they’re allowed to see. It could look like the following for example:

Someone had a very specific vision on how they wanted to provide the dashboards to the end user. They wanted a sidebar where they could flip through each of the dashboards. It could have been something completely different too. What we will focus on is how we can embed these dashboards into our application regardless of what the host application looks like.

Cumul.io comes with a set of publicly available SDKs. Here I’ll show you what you would do if you were to use the Node SDK. Check out our developer docs to see what other SDKs are available and instructions on how to use them.

Step 1: Generate SSO Tokens For Your End Users

Before you can generate SSO tokens for your end users, you will have to make sure that you create an API key and token in Cumul.io. You can do this from your Cumul.io Profile. It should be the organization owner with access to the integration that creates and uses this API key and token to make the SSO authorization request. Once you’ve done this, let’s first create a Cumul.io client which would be done in the server side of the application:

const Cumulio = require("cumulio");

const client = new Cumulio({
  api_key: '<YOUR API KEY>',
  api_token: '<YOUR API TOKEN>',
});

Now we can create the SSO token for the end user. For more information on this API call and the required fields check out our developer documentation on generating SSO tokens.

let promise = client.create('authorization', {
  integration_id: '<THE INTEGRATION ID>',
  type: 'sso',
  expiry: '24 hours',
  inactivity_interval: '10 minutes',
  username: '< A unique identifier for your end user >',
  name: '< end-user name >',
  email: '< end-user email >',
  suborganization: '< end-user suborganization >',
  role: 'viewer',
  metadata: {}
});

Here, notice how we have added the optional metadata field. This is where you can provide the parameters and values with which you want to filter the dashboards’ datasets on. In the example we’ve been going through we’ve been filtering based on department so we would be adding this to the metadata. Ideally you would get this information from the authentication provider you use. See a detailed explanation on how we’ve done this with Auth0.

This request will return a JSON object that contains an authorization id and token which is later used as the key/token combination to embed dashboards in the client-side.

Something else you can optionally add here which is pretty cool is a CSS property. This would allow you to define custom look and feel for each user (or user group). For the same application, this is what the Marketing Dashboard could look like for Angelina vs Brad:

Step 2: Embed

We jumped ahead a bit there. We created SSO tokens for end users but we haven’t yet actually embedded the dashboards into the application. Let’s have a look at that. First up, you should install and import the Web component.

import '@cumul.io/cumulio-dashboard';

After importing the component you can use it as if it were an HTML tag. This is where you will embed your dashboards:

<cumulio-dashboard
  dashboardId="< a dashboard id >"
  dashboardSlug="< a dashboard slug >"
  authKey="< SSO key from step 1 >"
  authToken="< SSO token from step 1 >">
</cumulio-dashboard>

Here you will have a few options. You can either provide the dashboard Id for any dashboard you want to be embedding, or you can provide the dashboard slug which we defined in the Integration setup (which is why I highly recommend this, it’s much more readable doing it this way). For more detailed information on how to embed dashboards you can also check out our developer documentation.

A nice way to do this step is of course just defining the skeleton of the dashboard component in your HTML file and filling in the rest of it from the client side of your application. I’ve done the following, although it’s of course not the only way:

I’ve added the dashboard component with the ID dashboard:

<cumulio-dashboard id="dashboard"></cumulio-dashboard>

Then, I’ve retrieved this component in the client code as follows:

const dashboardElement = document.getElementById("dashboard");

Then I request the SSO token from the server side of my application which returns the required key and token to add to the dashboard component. Let’s assume we have a wrapper function getDashboardAuthorizationToken() that does this for us and returns the response from the server-side SSO token request. Next, we simply fill in the dashboard component accordingly:

const authorizationToken = await getDashboardAuthorizationToken();
if (authorizationToken.id && authorizationToken.token) {
  dashboardElement.authToken = authorizationToken.token;
  dashboardElement.authKey = authorizationToken.id;
  dashboardElement.dashboardSlug = "marketing|sales|leads";
}

Notice how in the previous steps I chose to define slugs for my dashboards that are a part of this integration. This means I can avoid looking up dashboard IDs and adding dashboardId as one of my parameters of the dashboardElement. Instead I can just provide one of the slugs marketing, sales or leads and I’m done! Of course you would have to set up some sort of selection process to your application to decide where and when you embed which dashboard.

That’s it folks! We’ve successfully created an Integration in Cumul.io and in a few lines of code, we’ve been able to embed its dashboards into our application 🎉 Now imagine a scenario where you have to maintain multiple applications at once, either for within the same company or separate ones. Whatever your scenario, I’m sure you can imagine how if you have a number of dashboards where each of them have to go to different places and each of them have to have different access rights depending on where they are and on and on we go.. How it can quickly get out of hand. Integrations allow you to manage this in a simple and neat way, all in one place, and as you can see, mostly from within the Cumul.io UI.

There’s a lot more you can do here which we haven’t gone through in detail. Such as adding user specific custom themes and CSS. We also didn’t go through how you would set parameters and filters in dashboards, or how you would use them from within your host application so that you have a multi-tenant setup. Below you can find some links to useful tutorials and documentation for these steps if you are interested.


The post Embedded Analytics Made Simple With Cumul.io Integrations appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Bonsai Browser

https://bonsaibrowser.com/

https://css-tricks.com/?p=353719

Web-browser for research that helps programmers think clearly.

With Bonsai, rather than being like, I’m going to go use my web browser now, you hit Option + Space and it brings up a browser. It’s either full-screen or a very minimal float-over-everything window. You can visually organize things into Workspaces. I can see it being quite good for research, but also just getting you to think differently about what a “web browser” interface can be and do for you.

Perhaps for what we’re losing in browser engine diversity, we’ll gain in browser UI/UX diversity.

Direct Link to ArticlePermalink


The post Bonsai Browser appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS is Going Gosh-Darned Hog Wild, I Tell Ya What

https://css-tricks.com/css-is-going-gosh-darned-hog-wild-i-tell-ya-what/

https://css-tricks.com/?p=352459

As someone just sittin’ back watching CSS evolve, it feels like we’re at one of the hottest moments of innovation in CSS history. It was really something when we got flexbox across all browsers, and not terribly long after, grid. They changed the game from CSS feeling like an awkward collection of tricks to something more sensible and of the times.

That feeling keeps getting more and more true all the time. Just in the last short while, here’s a list of things happening.

⚠️🤷 The syntax might not be exactly like any of the snippets below this when they ship for real. 🤷⚠️

Native Nesting

Native Nesting has become a First Public Working Draft, meaning it’s a lot closer to becoming a real thing than ever before. A lot of people use preprocessors just for the convenience of nesting and this should be helpful for those looking to simplify their build tools to avoid that.

I especially like how you can nest conditional rules.

.card {
  & .title { }
  & .body { }

  @media (min-inline-size > 1000px) {
    & { }
  }

  @nest body.dark & { }
}

I’ve heard whispers of this being a workable idea too, which avoids requiring the & on simple selectors and also avoids @nest at all.

.card {{
  .title { }
  .body { }

  body.dark & { }
}}

Container Queries

Container Queries is just an Editor’s Draft (CSS Containment Module Level 3) at the moment, but they already have an implementation in Chrome (with a flag). These are a huge deal as they allow us to make styling decisions based on the size of the container itself, which in today’s component-driven world, is just a absolutely good idea.

See the code for a simple example site (might look weird if you don’t have the flag on in Chrome).

/* Set containment on the parent you're querying */
.card-container {
  /* Both work right now, not sure which is right */
  contain: style layout inline-size;
  container: inline-size;
}
.card {
  display: flex;
}
@container (max-width: 500px) {
  /* Must style a child, not the container */
  .card {
    flex-direction: column;
  }
}

Container Units

Container Units have a draft spec as well, which, to me, nearly doubles the usefulness of container queries. The idea is that you have a unit that is based on the size of the container (width, height, or “inline-size” / “block-size”). I imagine the qi unit is the most useful.

Hopefully soon, we’ll be writing container-scoped CSS that styles itself based on the size of itself and can pass that size for other properties to use inside. The font-size property is an easy example of how useful this is (fonts that scale in size based on their container), but I’m sure container units will be used for all sorts of stuff, like gap, padding, and who knows what all else.

/* Set containment on the parent you're querying */
.card-container {
  /* Both work right now, not sure which is right */
  contain: style layout inline-size;
  container: inline-size;
}
.card h2 {
  font-size: 1.5rem; /* fallback */
}
@container type(inline-size) {
  .card h2 {
    font-size: clamp(14px, 1rem + 2qi, 56px)
  }
}

Cascade Layers

Cascade Layers (in Working Draft spec) introduces a whole new paradigm for which CSS selectors win in the Cascade. Right now it’s mostly a specificity contest. Selectors with the highest specificity win, only losing out to inline styles and specific rules with !important clauses. But with layers, any matching selector on a higher layer would win.

@layer base;      
@layer theme;   
@layer utilities; 

/* Reset styles with no layer (super low) */
* { box-sizing: border-box; }

@layer theme { 
  .card { background: var(--card-bg); }
}

@layer base { 
  /* Most styles? */
}

@layer utilities {
  .no-margin { margin: 0; }
}

@when

Tab Atkins’ proposal for CSS When/Else Rules has been accepted and is a way of expressing @media and @supports queries in such a way that you can much more easily express else conditions. While media queries already have some ability to do logic, doing mutually exclusive queries has long been hard to express and this makes it very simple.

@when media(width >= 400px) and media(pointer: fine) and supports(display: flex) {
  /* A */
} @else supports(caret-color: pink) and supports(background: double-rainbow()) {
  /* B */
} @else {
  /* C */
}

Scoping

The idea of Scoped Styles (this one is an Editor’s Draft) is that it provides a syntax for writing a block of styles that only apply to a certain selector and within, but also have the ability to stop the scope, creating a scope donut.

My favorite part of all this is the “proximity” strength stuff. Miriam explains like this:

.light-theme a { color: purple; }
.dark-theme a { color: plum; }
<div class="dark-theme">
  <a href="#">plum</a>

  <div class="light-theme">
    <a href="#">also plum???</a>
  </div>
</div>

Good point right?! There is no great way to express that you want the proximity of that link to the .light-theme to win. Right now, the fact that the specificity of both themes is the same, but .dark-theme comes after — so it wins. Hopefully scoped styles helps with this angle, too.

@scope (.card) to (.content) {
  :scope {
    display: grid;
    grid-template-columns: 50px 1fr;
  }
  img {
    filter: grayscale(100%);
    border-radius: 50%;
  }
  .content { ... }
}
/* Proximity help! */
@scope (.light-theme) {
  a {
    color: purple;
  }
}

@scope (.dark-theme) {
  a {
    color: plum;
  }
}


You can’t use anything on this list right now on your production websites. After all these years attempting to follow this kind of thing, I remain ignorant to how it all ultimately goes. I think the specs need to be finished and agreed upon first. Then browsers pick them up, hopefully more than one. And once they have, then I think the specs can be finalized?

I dunno. Maybe some of it will die. Maybe some of it will happen super fast, and some super slow. Likely, some of it will drop in some browsers but not others. Hey, at least we have evergreen browsers now so that when things do drop, it happens fast. I feel like right now we’re in a stage where most of the biggest and best CSS features are supported across all browsers, but with all this coming, we’ll be headed into a phase where support for the latest-and-greatest will be much more spotty.


The post CSS is Going Gosh-Darned Hog Wild, I Tell Ya What appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Less Absolute Positioning With Modern CSS

https://ishadeed.com/article/less-absolute-positioning-modern-css/

https://css-tricks.com/?p=353700

Ahmad Shadeed blogs the sentiment that we might not need to lean on position: absolute as much as we might have in the past. For one thing: stacking elements. For example, if you have a stack of elements that should all go on top of each other…

.stack {
  display: grid;
}
.stack > * {
  grid-area: 1 / -1;
}

All the elements occupy the same grid cell at that point, but you can still use alignment and justification to move stuff around and get it looking and behaving how you want.

What you are really saying with position: absolute is I want this element to be entirely removed from the flow such that it doesn’t affect other elements and other elements don’t affect it. Sometimes you do, but arguably less often than your existing CSS muscle memory would have you believe.

I’ll snag one of Ahmad’s idea here:

Both the tag and the title are positioned in a way we might automatically think of using absolute positioning. But again, something like CSS Grid has all of the alignment features we need to not only stack them vertically, but place them right where we want.

Direct Link to ArticlePermalink


The post Less Absolute Positioning With Modern CSS appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Jamstack Developers’ Favorite Frameworks of 2021

https://css-tricks.com/jamstack-developers-favorite-frameworks-of-2021/

https://css-tricks.com/?p=353415

Which new framework should I learn this year? Is it time to ditch my CMS? What tools should I pick up if I want to scale my site to an audience of millions? The 2021 Jamstack Community Survey is here with answers to those questions and more. 

For the past two years, Netlify has conducted the Jamstack Community Survey to better understand our growing group of developers—the insights inform our services, and they also help developers learn from one another. Our survey data provides a sense of best practices as well as an idea of what else is happening in the community.

What we’re seeing this year: it’s never been a better time to be a developer in the Jamstack community! Jamstack has gone mainstream and the ecosystem is thriving. Jamstack is becoming the default choice for web developers at all stages of their careers across different geographies and touching all industries, and the community is only getting bigger. We also saw a huge rise in the percentage of students in our community over the last year, a great sign for a growing ecosystem.

In 2021, Netlify received more than 7,000 responses to the Jamstack Community Survey. This is more than double the number of responses we received in 2020, confirming the growth of the Jamstack community. 

Here are a few of the highlights from our more technical findings…

Jamstack developers work differently at scale.

32% of Jamstack developers are building sites for audiences of millions of users, but the tools they use and their development priorities are different: for instance, they are more likely to specialize in front-end or back-end work, and they are more likely to consider mobile devices a key target.

JavaScript dominates programming languages for the web—but TypeScript is giving it a run for its money.

For 55% of developers, JavaScript is their primary language. But TypeScript is coming from behind with a growing share.

A plot chart with colored dots representing different languages. Y axis is satisfaction, x-axis is usage. JavaScript is the most used and halfway up the satisfaction axis. Typescript is at the top of satisfaction, and halfway through the usage axis.

Figma is almost the only design tool that matters.

When it comes to design tools, more than 60% of survey respondents use Figma and are happier with it than the users of any other design tool we asked about.

A plot chart with colored dots representing different design apps. Y axis is satisfaction, x-axis is usage. Figma is at the upper-right corner of the chart while everything else is clustered toward the bottom left.

React still reigns supreme for frameworks.

React continues to dominate the major frameworks category in usage and satisfaction, and Next.js continues to grow alongside it. But we also saw growth and higher satisfaction from a challenger framework, Vue.

A plot chart with colored dots representing different frameworks. Y axis is satisfaction, x-axis is usage.React is at the far right, but halfway up the satisfaction axis. Express is at the top of the satisfaction axis but between 10-20% usage.

WordPress leads in CMS usage.

WordPress remains the clear leader as a content management system, but it’s not well-liked as a standalone solution. When used in a headless configuration, users reported much higher satisfaction. This was a breakout year for other headless CMSs like Sanity and Strapi.

A plot chart with colored dots representing different content management systems. Y axis is satisfaction, x-axis is usage. WordPress is all the way at the bottom right corner of the chart, showing high usage but low satisfaction. Sanity has the highest satisfaction, but is between 10-15% usage.

And that’s just a taste of what we learned. To view the complete findings of the 2021 Jamstack Community Survey, visit our survey website


The post Jamstack Developers’ Favorite Frameworks of 2021 appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

WooCommerce + Google Analytics

https://css-tricks.com/woocommerce-google-analytics/

https://css-tricks.com/?p=353317

Google Analytics is powerful analytics software. A common way to use it is to just slap the JavaScript snippet on every page template you have and let it collect basic data about unique visitors and pageviews and such. That’s useful, but it’s also the bare minimum. Say there is an important button on your site. Leveling up, you could send custom events to track users clicking on that button. Those are the analytics that matter the most.

Further down that road is tracking eCommerce analytics. This is extra-tricky, as it requires you sending events to Google Analytics for sales, instances of adding/removing things from cart, views on products… all sorts of stuff. If you don’t do all that (and do it right), you don’t get good analytics information.

Yet another reason I like WooCommerce! Instead of this analytics integration being a monumental effort and a substantial bit of technical debt to maintain, you just install the WooCommerce Google Analytics plugin and… that’s it. Also: it’s free.

I’ve had this integrated for months right here on CSS-Tricks, and I can confirm:

  1. It was close to zero effort.
  2. It just works.
The plugin installed and activated!
The one bit of config is adding this ID, which is easy to find in Google Analytics, your own code, or another Google Analytics plugin.

Now, to be clear, WooCommerce has its own analytics built right in. If what you are interested in is sales reports and top sellers and stuff like that, those are the dashboards I’d be looking at. But there are some things that the built-in WooCommerce analytics just don’t do. For example, I can check out the sales funnel on Google Analytics now:

30 days of traffic starting from all unique visitors to sessions where they actually bought something.

CSS-Tricks isn’t exactly an eCommerce-focused website, so the funnel there starts super wide and gets super (super) tiny — but hey, at least I can confirm that and see it with my own eyes. Plus, I can glean some insights here, like the fact that 66/70 people completed checkout once they got there (pretty good), but only 70/525 even proceeded to checkout after adding to cart, so I’m losing a lot of people at that stage.

Here is some more interesting data that only Google Analytics knows:

Of 66 sales, 56 of them came from returning visitors, not new visitors. So people tend to not buy on first look, but do come back later. I’m not sure if that means I should be making things more enticing for those new visitors or if I should lean into reminding people about it after they’ve looked at it. Either way, now I know because I have the data.

There is data in the WooCommerce analytics that I’d normally have to go to Google Analytics to see. I can see individual orders. I can see what the top sellers are and compare product sales over different time periods. All useful stuff, and you might appreciate having all this in one place.

Again, my favorite part about this is having all this data. It feels like it should have been hard-won to get, but all it took was clicking a few buttons. That’s why I never regret just doing things the standard WordPress and WooCommerce way! Things tend to just work!


The post WooCommerce + Google Analytics appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Those “Get The App” Banners

https://css-tricks.com/those-get-the-app-banners/

https://css-tricks.com/?p=352907

Why would a company promote a native app over their perfectly usable website?

We’d have to ask them, I suppose. But it’s hard not to see this push to native as a matter of priorities: that these companies consider native applications worthy of their limited time, resources, and money. They’re a worthy investment, to hear these banners tell it.

—Ethan Marcotte, “Locus.”

Ethan shows off that the web is absolutely covered in amazingly obtrusive “get the app” banners, often covering up perfectly usable websites.

What I always think of when I see banners like this is a comment I remember Tim Holman making one time that was something like, What would it feel like to work on the web team at a company like this? There are a bunch of people in the world that work on websites that only exist behind big stupid banners telling people not to use the thing they work on all day.

Sure would be nice to get to a point where companies didn’t really care which method you used, because it’s probably all built with one technology anyway and is fully capable of anything the device can do.


The post Those “Get The App” Banners appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Cash (Tiny jQuery Alternative)

https://css-tricks.com/cash-tiny-jquery-alternative/

https://css-tricks.com/?p=353431

The README for Cash is straightforward:

Cash is an absurdly small jQuery alternative for modern browsers (IE11+) that provides jQuery-style syntax for manipulating the DOM. Utilizing modern browser features to minimize the codebase, developers can use the familiar chainable methods at a fraction of the file size. 100% feature parity with jQuery isn’t a goal, but Cash comes helpfully close, covering most day to day use cases.

6 KB minified and gzipped, which is even smaller than Zepto. Zepto’s whole point was a smaller jQuery, but it hasn’t been touched in a bunch of years, so there is that too.

I wonder how much smaller Cash would be if it dropped IE 11 support.

jQuery is still used on an absolute ton of sites, only just recently having peaked in usage and showing signs of decline. That must be because it comes on most WordPress sites, right?! That’s like 42% of all sites right there.

Anyway, if you tend to reach for jQuery just for some convenient APIs, Cash looks like a nice alternative. I don’t blame you either. Typing $ instead of document.querySelectorAll still feels good to me, not to mention all the other fanciness tucked behind that dollar sign function.


Also worth mentioning: if you’re looking to straight-up remove jQuery from a project, replace-jquery might be worth a look:

Automatically find jQuery methods from existing projects and generate vanilla js alternatives.


The post Cash (Tiny jQuery Alternative) appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.