Ads
Wednesday, November 30, 2022
Partly Cloudy today!
With a high of F and a low of 23F. Currently, it's 27F and Clear outside.
Current wind speeds: 19 from the South
Pollen: 0
Sunrise: November 30, 2022 at 07:51PM
Sunset: December 1, 2022 at 05:29AM
UV index: 0
Humidity: 60%
via https://ift.tt/1E34Zax
December 1, 2022 at 10:06AM
Using The New Constrained Layout In WordPress Block Themes
One of the main goals of the WordPress Site Editor (and, yes, that is now the “official” name) is to move basic block styling from CSS to structured JSON. JSON files are machine-readable, which makes it consumable by the JavaScript-based Site Editor for configuring a theme’s global styles directly in WordPress.
It’s not all the way there yet! If we look at the Twenty Twenty-Two (TT2) default theme, there were two main unresolved issues: styling interactions (like :hover
, :active
, :focus
), and the margins and padding of layout containers. You can see how those were temporarily fixed in the TT2 style.css
file rather than making it into the theme.json
file.
WordPress 6.1 fixed those issues and what I want to do is look specifically at the latter. Now that we have JSON-ified styles for the margins and padding of layout containers, that opens us up to more flexible and robust ways to define spacing in our theme layouts.
What kind of spacing are we talking about?
First off, we already have root-level padding which is a fancy way of describing padding on the <body>
element. That’s nice because it ensures consistent spacing on an element that is shared on all pages and posts.
But there’s more to it because now we have a way for blocks to bypass that padding and align themselves full-width. That’s thanks to padding-aware alignments which is a new opt-in feature in theme.json
. So, even if you have root-level padding, you can still allow, say, an image (or some other block) to break out and go full-width.
That gets us to another thing we get: constrained layouts. The idea here is that any blocks nested in the layout respect the layout’s content width — which is a global setting — and do not flow outside of it. We can override that behavior on a block-by-block basis with alignments, but we’ll get to that.
Let’s start with…
Root-level padding
Again, this isn’t new. We’ve had the ability to set padding on the <body>
element in theme.json
since the experimental Gutenberg plugin introduced it in version 11.7. We set it on the styles.spacing
object, where we have margin
and padding
objects to define the top, right, bottom, and left spacing on the body:
{
"version": 2,
"styles": {
"spacing": {
"margin": {
"top": "60px",
"right": "30px",
"bottom": "60px",
"left": "30px"
},
"padding": {
"top": "30px",
"right": "30px",
"bottom": "30px",
"left": "30px"
}
}
}
}
This is a global setting. So, if we were to crack open DevTools and inspect the <body>
element, we would see these CSS styles:
body {
margin-top: 60px;
margin-right: 30px;
margin-bottom: 60px;
margin-left: 30px;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
}
Cool. But herein lies the issue of how in the world we can allow some blocks to break out of that spacing to fill the full screen, edge-to-edge. That’s why the spacing is there, right? It helps prevent that from happening!
But there are indeed plenty of cases where you might want to break out of that spacing on a one-off instance when working in the Block Editor. Say we plop an Image block on a page and we want it to go full-width while the rest of the content respects the root-level padding?
Enter…
Padding-aware alignments
While attempting to create the first default WordPress theme that defines all styles in the theme.json
file, lead designer Kjell Reigstad illustrates the challenging aspects of breaking out of root-level padding in this GitHub issue.
New features in WordPress 6.1 were created to address this issue. Let’s dig into those next.
useRootPaddingAwareAlignments
A new useRootPaddingAwareAlignments
property was created to address the problem. It was actually first introduced in the Gutenberg plugin v13.8. The original pull request is a nice primer on how it works.
{
"version": 2,
"settings": {
"appearanceTools": true,
"useRootPaddingAwareAlignments": true,
// etc.
},
Right off the bat, notice that this is a feature we have to opt into. The property is set to false
by default and we have to explicitly set it to true
in order to enable it. Also notice that we have appearanceTools
set to true
as well. That opts us into UI controls in the Site Editor for styling borders, link colors, typography, and, yes, spacing which includes margin and padding.
Setting appearanceTools
set to true
automatically opts blocks into margin and padding without having to set either settings.spacing.padding
or setting.spacing.margin
to true
.
When we do enable useRootPaddingAwareAlignments
, we are provided with custom properties with root padding values that are set on the <body>
element on the front end. Interestingly, it also applies the padding to the .editor-styles-wrapper
class so the spacing is displayed when working in the back-end Block Editor. Pretty cool!
I was able to confirm those CSS custom properties in DevTools while digging around.
Enabling useRootPaddingAwareAlignments
also applies left and right padding to any block that supports the “content” width and “wide” width values in the Global Styles image above. We can also define those values in theme.json
:
{
"version": 2,
"settings": {
"layout": {
"contentSize": "640px",
"wideSize": "1000px"
}
}
}
If the Global Styles settings are different than what is defined in theme.json
, then the Global Styles take precedence. You can learn all about managing block theme styles in my last article.
contentSize
is the default width for blocks.wideSize
provides a “wide” layout option and establishes a wider column for blocks to stretch out.
So, that last code example will give us the following CSS:
/* The default content container */
.wp-container-[id] > * {
max-width: 640px;
margin-left: auto !important;
margin-right: auto !important;
}
/* The wider content container */
.wp-container-[id] > .alignwide {
max-width: 1000px;
}
[id]
indicates a unique number automatically generated by WordPress.
But guess what else we get? Full alignment as well!
.wp-container-[id] .alignfull {
max-width: none;
}
See that? By enabling useRootPaddingAwareAlignments
and defining contentSize
and wideSize
, we also get a full alignment CSS class for a total of three container configurations for controlling the width of blocks that are added to pages and posts.
This applies to the following layout-specific blocks: Columns, Group, Post Content, and Query Loop.
Block layout controls
Let’s say we add any of those aforementioned layout-specific blocks to a page. When we select the block, the block settings UI offers us new layout settings based on the settings.layout
values we defined in theme.json
(or the Global Styles UI).
We’re dealing with very specific blocks here — ones that can have other blocks nested inside. So, these Layout settings are really about controlling the width and alignment of those nested blocks. The “Inner blocks use content width” setting is enabled by default. If we toggle it off, then we have no max-width
on the container and the blocks inside it go edge-to-edge.
If we leave the toggle on, then nested blocks will adhere to either the contentWidth
or wideWidth
values (more on that in a bit). Or we can use the numeric inputs to define custom contentWidth
and wideWidth
values in this one-off instance. That’s great flexibility!
Wide blocks
The settings we just looked are set on the parent block. Once we’ve nested a block inside and select it, we have additional options in that block to use the contentWidth
, wideWidth
, or go full-width.
Notice how WordPress multiplies the root-level padding CSS custom properties by -1
to create negative margins when selecting the “Full width” option.
Using a constrained layout
We just covered the new spacing and alignments we get with WordPress 6.1. Those are specific to blocks and any nested blocks within blocks. But WordPress 6.1 also introduces new layout features for even more flexibility and consistency in a theme’s templates.
Case in point: WordPress has completely restructured its Flex and Flow layout types and gave us a constrained layout type that makes it easier to align block layouts in themes using the content width settings in the Site Editor’s Global Styles UI.
Flex, Flow, and Constrained layouts
The difference between these three layout types is the styles that they output. Isabel Brison has an excellent write-up that nicely outlines the differences, but let’s paraphrase them here for reference:
- Flow layout: Adds vertical spacing between nested blocks in the
margin-block
direction. Those nested blocks can also be aligned to the left, right, or center. - Constrained layout: Same exact deal as a Flow layout, but with width constraints on nested blocks that are based on the
contentWidth
andwideWidth
settings (either intheme.json
or Global Styles). - Flex layout: This was unchanged in WordPress 6.1. It uses CSS Flexbox to create a layout that flows horizontally (in a row) by default, but can flow vertically as well so blocks stack one on top of another. Spacing is applied using the CSS
gap
property.
This new slate of layout types creates semantic class names for each layout:
Semantic layout class | Layout type | Supported blocks |
---|---|---|
.is-layout-flow |
Flow layout | Columns, Group, Post Content, and Query Loop. |
.is-layout-constrained |
Constrained layout | Columns, Group, Post Content, and Query Loop. |
.is-layout-flex |
Flex layout | Columns, Buttons, Social Icons |
Justin Tadlock has an extensive write-up on the different layout types and semantic classes, including use cases and examples.
Updating your theme to support constrained layouts
If you’re already using a block theme of your own making, you’re going to want to update it to support constrained layouts. All it takes is swapping out a couple of things in theme.json
:
{
"version": 2,
"settings": {
"layout": {
"type": "constrained", // replaces `"inherit": true`
"type": "default", // replaces `"inherit": false`
}
}
}
These are recently released block themes that have enabled spacing settings with useRootPaddingAwareAlignments
and have an updated theme.json
file that defines a constrained layout:
Theme | Root-level padding | Constrained layout features |
TT3 | Source code | Source code, Templates |
ProWP | Source code | Source code, Templates |
Triangulate | Source code | Source code, Templates |
Oaknut | Source code | Source code, Templates |
Loudness | Source code | Source code, Templates |
Pixl | Source code | Source code, Templates |
Block Canvas | Source code | Source code, Templates |
Rainfall | Source code | Source code, Templates |
Disabling layout styles
The base layout styles are default features that ship in WordPress 6.1 Core. In other words, they’re enabled right out of the box. But we can disable them if we need to with this little snippet in functions.php
:
// Remove layout styles.
add_theme_support( 'disable-layout-styles' );
Big warning here: disabling support for the default layout types also removes all of the base styling for those layouts. That means you’ll need to roll your own styles for spacing, alignments, and anything else needed to display content in different template and block contexts.
Wrapping up
As a great fan of full-width images, the new contained WordPress 6.1 layout and padding aware alignment features are two of my most favorites yet. Taken together with other tools including, better margin and padding control, fluid typography, and updated List and Quote blocks, among others, is solid proof that WordPress is moving towards a better content creation experience.
Now, we have to wait and look at how the imagination and creativity of ordinary designers and content creators use these incredible tools and take it to a new level.
Because of the site editor development iterations in progress, we should always anticipate a difficult path ahead. However, as an optimist, I am eager to see what will happen in the upcoming version of WordPress 6.2. Some of the thing, that I am keeping a close eye on are things like features being considered for inclusion, support for sticky positioning, new layout class names for inner block wrappers, updated footer alignment options, and adding constrained and flow layout options to Cover blocks.
This GitHub issues #44720 lists the layout related discussions slated for WordPress 6.2.
Additional resources
I consulted and referenced a lot of sources while digging into all of this. Here’s a big ol’ list of things I found helpful and think you might enjoy as well.
Tutorials
- Layout Styles (Styles | Developer Resources)
- Theme.json layout and spacing options (Full Site Editing)
- Padding aware alignments (Full Site Editing)
- Layouts and Wide Alignments in WordPress: Then, Now, and Upcoming Changes (Gutenberg Times)
- A Walk-Through of Layout Classes in WordPress 6.1 (Gutenberg Times)
WordPress posts
- Updated editor layout support in 6.1 after refactor (Make WordPress Core)
- Moving Core block styling to JSON (Make WordPress Core)
GitHub pull requests and issues
- Core CSS support for root padding and alignfull blocks (GitHub PR 42085)
- Layout: Fix has-global-padding classname for constrained layouts without contentSize (GitHub PR #43689)
- Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json (GitHub PR 40875)
- Tracking: additional layout options, design tools and refinements (GitHub Issue 44720)
Using The New Constrained Layout In WordPress Block Themes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/SupGRts
via IFTTT
Tuesday, November 29, 2022
Clear today!
With a high of F and a low of 5F. Currently, it's 6F and Clear outside.
Current wind speeds: 6 from the Southwest
Pollen: 0
Sunrise: November 29, 2022 at 07:50PM
Sunset: November 30, 2022 at 05:29AM
UV index: 0
Humidity: 82%
via https://ift.tt/1E34Zax
November 30, 2022 at 10:06AM
More Than “Slapping Paint on a Website”
I’m a sucker for anything about front-end job titles.
CSS evolved and we’re beyond the point where everyone can just do it as a side interest. We all can learn it and build amazing stuff with it, but using it wisely and correctly in a large-scale context isn’t an easy job anymore. It deserves people whose work is to focus on that part of the code.
Anselm is partly in responding to Sacha Greif’s “Is There Too Much CSS Now?” and the overall sentiment that CSS has a much higher barrier to entry for those learning it today than it did, say, in the CSS3 days. Back then, there was a super direct path to see the magic of CSS. Rachel Andrew perfectly captures that magic feeling in a prescient post from 2019:
There is something remarkable about the fact that, with everything we have created in the past 20 years or so, I can still take a complete beginner and teach them to build a simple webpage with HTML and CSS, in a day. […] We just need a text editor and a few hours. This is how we make things show up on a webpage.
— “HTML, CSS and our vanishing industry entry points”
That’s the real entry point here […]
Rachel is speaking to the abstraction of frameworks on top of vanilla CSS (and HTML) but you might as well tack big, shiny, and fairly new features on there, like CSS grid, flexbox, container queries, cascade layers, custom properties, and relational pseudo-classes, to name a few. Not that those are abstractions, of course. There’s just a lot to learn right now, whether you’ve been writing CSS for 20 days or 20 years.
But back to Anselm’s post. Do we need to think about CSS as more than just, you know, styling things? I often joke that my job is slapping paint on websites to make them pretty. But, honestly, I know it’s a lot more than that. We all know it’s more than that.
Maybe CSS is an industry in itself. Think of all the possible considerations that have to pass through your brain when writing CSS rules. Heck, Ahmad Shadeed recently shared all the things his brain processes just to style a Hero component. CSS touches so much of the overall user experience — responsiveness, accessibility, performance, cross-browser, etc. — that it clearly goes well beyond “slapping paint on websites”. So far beyond that each of those things could be someone’s full-time gig, depending on the project.
So, yes, CSS has reached a point where I could imagine seeing “CSS Engineer” on some job board. As Anselm said, “[CSS] deserves people whose work is to focus on that part of the code.” Seen that way, it’s not so hard to imagine front-end development as a whole evolving into areas of specialization, just like many other industries.
More Than “Slapping Paint on a Website” originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/J6nh8mP
via IFTTT
Monday, November 28, 2022
Snow Showers Late today!
With a high of F and a low of 18F. Currently, it's 34F and Clear outside.
Current wind speeds: 15 from the Northwest
Pollen: 0
Sunrise: November 28, 2022 at 07:49PM
Sunset: November 29, 2022 at 05:29AM
UV index: 0
Humidity: 45%
via https://ift.tt/qGp9bcf
November 29, 2022 at 10:03AM
Apple Messages & Color Contrast
Well, color me this! I was griping to myself last night about just how gosh dang hard it is to read text messages in Apple Messages. You know, not the blue bubbles that you get when messaging other iPhone users. Those are iMessages.
What I’m talking about are the green bubbles you get when messaging non-iPhone users. Those are standard text messages.
Let’s run the green through a contrast checker to see what’s up.
Oomph. Now I know why I always reach for my reading glasses when a text message pops up. That 2.17:1 ratio is below the WCAG 2.0 AA requirement of 4.5:1 and wayyyyy below the AAA level of 7:1.
Turns out I’m not the only one griping. A quick search turned up a little trove of news and blog posts — some as recent as last week — about the readability of those green text message bubbles.
- How iPhone Violates Apple’s Accessibility Guidelines (Kevin Voller)
- Apple Accused of Purposely Making Messages From Android Devices Hard to Read (Hypebeast)
- Text Messaging Wars: Apple Makes Android Green (Psychology Today)
- Apple Message Color Complaints Continue (Infopackets)
- Apple Using Green Color For Android Messages To Establish iPhone’s Dominance? (Gizbot)
- How To Make iPhone Green Messages Easier To Read (Inquier.net)
I’m no conspiracy theorist and like to give benefit to doubt. Buuuuut…
- iOS 6: Dark text on a green gradient background
- iOS 7: White text on a
#5AB539
background (or something close to it) - iOS 16.1: White text on a
#6ACC46
background
That second one is based on old screenshots and might not be the most accurate color value. But still, the transition from iOS 6 with dark text to what we have today in iOS 16.1 shows a clear regression. I’d like think the design team checked the updated values against WCAG guidelines, sure, but at least against their own Human Interface Guidelines.
The current green background (#65C466
) appears to be different than what is listed as the green “system color” (#30D158
, converted from a RGB of 48, 209, 88) in the iOS palette listed in the guidelines. But it’s not like that gets us any closer to a passing WCAG AA or AAA rating.
🤷♂️
Apple Messages & Color Contrast originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/GkKoJpM
via IFTTT
Sunday, November 27, 2022
Mostly Clear today!
With a high of F and a low of 24F. Currently, it's 30F and Clear outside.
Current wind speeds: 14 from the South
Pollen: 0
Sunrise: November 27, 2022 at 07:48PM
Sunset: November 28, 2022 at 05:30AM
UV index: 0
Humidity: 95%
via https://ift.tt/qGp9bcf
November 28, 2022 at 10:03AM
Saturday, November 26, 2022
Mostly Cloudy/Wind today!
With a high of F and a low of 27F. Currently, it's 37F and Fair outside.
Current wind speeds: 18 from the North
Pollen: 0
Sunrise: November 26, 2022 at 07:47PM
Sunset: November 27, 2022 at 05:30AM
UV index: 0
Humidity: 55%
via https://ift.tt/TPkLXZn
November 27, 2022 at 10:03AM
Friday, November 25, 2022
Clear today!
With a high of F and a low of 28F. Currently, it's 33F and Clear outside.
Current wind speeds: 10 from the Southwest
Pollen: 0
Sunrise: November 25, 2022 at 07:46PM
Sunset: November 26, 2022 at 05:31AM
UV index: 0
Humidity: 33%
via https://ift.tt/FcYv5a1
November 26, 2022 at 10:03AM
Thursday, November 24, 2022
Clear today!
With a high of F and a low of 21F. Currently, it's 25F and Clear outside.
Current wind speeds: 8 from the Northwest
Pollen: 0
Sunrise: November 24, 2022 at 07:45PM
Sunset: November 25, 2022 at 05:31AM
UV index: 0
Humidity: 66%
via https://ift.tt/FcYv5a1
November 25, 2022 at 10:03AM
Wednesday, November 23, 2022
Mostly Cloudy/Wind today!
With a high of F and a low of 27F. Currently, it's 38F and Clear/Wind outside.
Current wind speeds: 24 from the Northwest
Pollen: 0
Sunrise: November 23, 2022 at 07:44PM
Sunset: November 24, 2022 at 05:32AM
UV index: 0
Humidity: 46%
via https://ift.tt/4Y6swGV
November 24, 2022 at 10:03AM
Tuesday, November 22, 2022
Mostly Clear today!
With a high of F and a low of 24F. Currently, it's 28F and Clear outside.
Current wind speeds: 7 from the Southwest
Pollen: 0
Sunrise: November 22, 2022 at 07:43PM
Sunset: November 23, 2022 at 05:32AM
UV index: 0
Humidity: 41%
via https://ift.tt/aD8Tp7x
November 23, 2022 at 10:03AM
WordPress Developer Blog
Well, hey check this out. Looks like there is a brand spankin’ new blog over at WordPress.org all about WordPress development. In the original proposal for the blog, Birgit Pauli-Haak writes:
The Make Core blog has a heavy emphasis on meeting notes for the various core teams, rather than highlighting new features. This makes it difficult for developers who are not contributors or who just occasionally contribute to find the relevant information among the team-related posts.
Josepha describes the blog further in the announcement post:
These are types of content that lend themselves more toward the long-form content of a blog. However, there are more practical reasons for this new home for developers on WordPress.org:
- Posts that detail updated or new APIs.
- A way to subscribe to development-related updates.
- A place to keep up with ongoing discussions.
Perhaps the most important reason for the Developer Blog is to have a central place for WordPress extenders. Information can fragment across various sites, and developers spend valuable time seeking it out. This blog is an attempt to provide a curated experience of the most important updates.
Hear, hear! This is exactly the sort of thing I feel has been missing in the WordPress development space: quality information from established developers that shares useful tips, tricks, and best practices for working with WordPress in this new era of full-site editing. With WordPress Core development taking place at break-neck speeds, having a central source of updated information and a way to syndicate it is a welcome enhancement for sure.
There are already a few excellent articles in there to kick-start things:
- Creating Themes from a Pattern-First Mindset (Justin Tadlock)
- Demystifying Home and Posts Templates in WordPress theme development (Daisy Olsen)
- How to extend WordPress via the SlotFill system (Ryan Welcher)
It’s WordPress, of course, so anyone and everyone is encouraged to contribute. If you do, it’s a good idea to first check our the writing tips and guidelines. And, naturally, there is an RSS feed you can use to keep up with the lastest posts.
If you wanna go down the ol’ rabbit trail for how the blog came together, here are a few links to get that context:
- Developer blog content repository (GitHub)
- Developer Blog Content Board (GitHub)
- Developer Blog Content Idea Board (GitHub)
- Proposal to Start a News blog on developer.WordPress.org (Make WordPress Blog)
(High fives to Ganesh Dahal for the tip!)
To Shared Link — Permalink on CSS-Tricks
WordPress Developer Blog originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/cbX8wmy
via IFTTT
Monday, November 21, 2022
Partly Cloudy today!
With a high of F and a low of 21F. Currently, it's 27F and Clear outside.
Current wind speeds: 10 from the Southwest
Pollen: 0
Sunrise: November 21, 2022 at 07:42PM
Sunset: November 22, 2022 at 05:33AM
UV index: 0
Humidity: 30%
via https://ift.tt/aD8Tp7x
November 22, 2022 at 10:03AM
Taming the Cascade With BEM and Modern CSS Selectors
BEM. Like seemingly all techniques in the world of front-end development, writing CSS in a BEM format can be polarizing. But it is – at least in my Twitter bubble – one of the better-liked CSS methodologies.
Personally, I think BEM is good, and I think you should use it. But I also get why you might not.
Regardless of your opinion on BEM, it offers several benefits, the biggest being that it helps avoid specificity clashes in the CSS Cascade. That’s because, if used properly, any selectors written in a BEM format should have the same specificity score (0,1,0
). I’ve architected the CSS for plenty of large-scale websites over the years (think government, universities, and banks), and it’s on these larger projects where I’ve found that BEM really shines. Writing CSS is much more fun when you have confidence that the styles you’re writing or editing aren’t affecting some other part of the site.
There are actually exceptions where it is deemed totally acceptable to add specificity. For instance: the :hover
and :focus
pseudo classes. Those have a specificity score of 0,2,0
. Another is pseudo elements — like ::before
and ::after
— which have a specificity score of 0,1,1
. For the rest of this article though, let’s assume we don’t want any other specificity creep. 🤓
But I’m not really here to sell you on BEM. Instead, I want to talk about how we can use it alongside modern CSS selectors — think :is()
, :has()
, :where()
, etc. — to gain even more control of the Cascade.
What’s this about modern CSS selectors?
The CSS Selectors Level 4 spec gives us some powerful new(ish) ways to select elements. Some of my favorites include :is()
, :where()
, and :not()
, each of which is supported by all modern browsers and is safe to use on almost any project nowadays.
:is()
and :where()
are basically the same thing except for how they impact specificity. Specifically, :where()
always has a specificity score of 0,0,0
. Yep, even :where(button#widget.some-class)
has no specificity. Meanwhile, the specificity of :is()
is the element in its argument list with the highest specificity. So, already we have a Cascade-wrangling distinction between two modern selectors that we can work with.
The incredibly powerful :has()
relational pseudo-class is also rapidly gaining browser support (and is the biggest new feature of CSS since Grid, in my humble opinion). However, at time of writing, browser support for :has()
isn’t quite good enough for use in production just yet.
Lemme stick one of those pseudo-classes in my BEM and…
/* ❌ specificity score: 0,2,0 */
.something:not(.something--special) {
/* styles for all somethings, except for the special somethings */
}
Whoops! See that specificity score? Remember, with BEM we ideally want our selectors to all have a specificity score of 0,1,0
. Why is 0,2,0
bad? Consider this same example, expanded:
.something:not(.something--special) {
color: red;
}
.something--special {
color: blue;
}
Even though the second selector is last in the source order, the first selector’s higher specificity (0,2,0
) wins, and the color of .something--special
elements will be set to red
. That is, assuming your BEM is written properly and the selected element has both the .something
base class and .something--special
modifier class applied to it in the HTML.
Used carelessly, these pseudo-classes can impact the Cascade in unexpected ways. And it’s these sorts of inconsistencies that can create headaches down the line, especially on larger and more complex codebases.
Dang. So now what?
Remember what I was saying about :where()
and the fact that its specificity is zero? We can use that to our advantage:
/* ✅ specificity score: 0,1,0 */
.something:where(:not(.something--special)) {
/* etc. */
}
The first part of this selector (.something
) gets its usual specificity score of 0,1,0
. But :where()
— and everything inside it — has a specificity of 0
, which does not increase the specificity of the selector any further.
:where()
allows us to nest
Folks who don’t care as much as me about specificity (and that’s probably a lot of people, to be fair) have had it pretty good when it comes to nesting. With some carefree keyboard strokes, we may wind up with CSS like this (note that I’m using Sass for brevity):
.card { ... }
.card--featured {
/* etc. */
.card__title { ... }
.card__title { ... }
}
.card__title { ... }
.card__img { ... }
In this example, we have a .card
component. When it’s a “featured” card (using the .card--featured
class), the card’s title and image needs to be styled differently. But, as we now know, the code above results in a specificity score that is inconsistent with the rest of our system.
A die-hard specificity nerd might have done this instead:
.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }
That’s not so bad, right? Frankly, this is beautiful CSS.
There is a downside in the HTML though. Seasoned BEM authors are probably painfully aware of the clunky template logic that’s required to conditionally apply modifier classes to multiple elements. In this example, the HTML template needs to conditionally add the --featured
modifier class to three elements (.card
, .card__title
, and .card__img
) though probably even more in a real-world example. That’s a lot of if
statements.
The :where()
selector can help us write a lot less template logic — and fewer BEM classes to boot — without adding to the level of specificity.
.card { ... }
.card--featured { ... }
.card__title { ... }
:where(.card--featured) .card__title { ... }
.card__img { ... }
:where(.card--featured) .card__img { ... }
Here’s same thing but in Sass (note the trailing ampersands):
.card { ... }
.card--featured { ... }
.card__title {
/* etc. */
:where(.card--featured) & { ... }
}
.card__img {
/* etc. */
:where(.card--featured) & { ... }
}
Whether or not you should opt for this approach over applying modifier classes to the various child elements is a matter of personal preference. But at least :where()
gives us the choice now!
What about non-BEM HTML?
We don’t live in a perfect world. Sometimes you need to deal with HTML that is outside of your control. For instance, a third-party script that injects HTML that you need to style. That markup often isn’t written with BEM class names. In some cases those styles don’t use classes at all but IDs!
Once again, :where()
has our back. This solution is slightly hacky, as we need to reference the class of an element somewhere further up the DOM tree that we know exists.
/* ❌ specificity score: 1,0,0 */
#widget {
/* etc. */
}
/* ✅ specificity score: 0,1,0 */
.page-wrapper :where(#widget) {
/* etc. */
}
Referencing a parent element feels a little risky and restrictive though. What if that parent class changes or isn’t there for some reason? A better (but perhaps equally hacky) solution would be to use :is()
instead. Remember, the specificity of :is()
is equal to the most specific selector in its selector list.
So, instead of referencing a class we know (or hope!) exists with :where()
, as in the above example, we could reference a made up class and the <body>
tag.
/* ✅ specificity score: 0,1,0 */
:is(.dummy-class, body) :where(#widget) {
/* etc. */
}
The ever-present body
will help us select our #widget
element, and the presence of the .dummy-class
class inside the same :is()
gives the body
selector the same specificity score as a class (0,1,0
)… and the use of :where()
ensures the selector doesn’t get any more specific than that.
That’s it!
That’s how we can leverage the modern specificity-managing features of the :is()
and :where()
pseudo-classes alongside the specificity collision prevention that we get when writing CSS in a BEM format. And in the not too distant future, once :has()
gains Firefox support (it’s currently supported behind a flag at the time of writing) we’ll likely want to pair it with :where() to undo its specificity.
Whether you go all-in on BEM naming or not, I hope we can agree that having consistency in selector specificity is a good thing!
Taming the Cascade With BEM and Modern CSS Selectors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/Hm9xOJG
via IFTTT
Sunday, November 20, 2022
Clear today!
With a high of F and a low of 19F. Currently, it's 24F and Clear outside.
Current wind speeds: 6 from the Southwest
Pollen: 0
Sunrise: November 20, 2022 at 07:40PM
Sunset: November 21, 2022 at 05:33AM
UV index: 0
Humidity: 34%
via https://ift.tt/DWhRXy4
November 21, 2022 at 10:03AM
Saturday, November 19, 2022
Clear today!
With a high of F and a low of 20F. Currently, it's 21F and Clear outside.
Current wind speeds: 11 from the Southwest
Pollen: 0
Sunrise: November 19, 2022 at 07:39PM
Sunset: November 20, 2022 at 05:34AM
UV index: 0
Humidity: 47%
via https://ift.tt/zGJuTYl
November 20, 2022 at 10:03AM
Friday, November 18, 2022
Clear today!
With a high of F and a low of 8F. Currently, it's 9F and Clear outside.
Current wind speeds: 12 from the Southwest
Pollen: 0
Sunrise: November 18, 2022 at 07:38PM
Sunset: November 19, 2022 at 05:34AM
UV index: 0
Humidity: 77%
via https://ift.tt/U3MRwD5
November 19, 2022 at 10:03AM
Making Static Noise From a Weird CSS Gradient Bug
👋 The demos in this article experiment with a non-standard bug related to CSS gradients and sub-pixel rendering. Their behavior may change at any time in the future. They’re also heavy as heck. We’re serving them async where you click to load, but still want to give you a heads-up in case your laptop fan starts spinning.
Do you remember that static noise on old TVs with no signal? Or when the signal is bad and the picture is distorted? In case the concept of a TV signal predates you, here’s a GIF that shows exactly what I mean.
View image (contains auto-playing media)
Yes, we are going to do something like this using only CSS. Here is what we’re making:
Before we start digging into the code, I want to say that there are better ways to create a static noise effect than the method I am going to show you. We can use SVG, <canvas>
, the filter
property, etc. In fact, Jimmy Chion wrote a good article showing how to do it with SVG.
What I will be doing here is kind of a CSS experiment to explore some tricks leveraging a bug with gradients. You can use it on your side projects for fun but using SVG is cleaner and more suitable for a real project. Plus, the effect behaves differently across browsers, so if you’re checking these out, it’s best to view them in Chrome, Edge, or Firefox.
Let’s make some noise!
To make this noise effect we are going to use… gradients! No, there is no secret ingredient or new property that makes it happen. We are going to use stuff that’s already in our CSS toolbox!
The “trick” relies on the fact that gradients are bad at anti-aliasing. You know those kind of jagged edges we get when using hard stop colors? Yes, I talk about them in most of my articles because they are a bit annoying and we always need to add or remove a few pixels to smooth things out:
As you can see, the second circle renders better than the first one because there is a tiny difference (0.5%
) between the two colors in the gradient rather than using a straight-up hard color stop using whole number values like the first circle.
Here’s another look, this time using a conic-gradient
where the result is more obvious:
An interesting idea struck me while I was making these demos. Instead of fixing the distortion all the time, why not trying to do the opposite? I had no idea what would happen but it was a fun surprise! I took the conic gradient values and started to decrease them to make the poor anti-aliasing results look even worse.
Do you see how bad the last one is? It’s a kind of scrambled in the middle and nothing is smooth. Let’s make it full-screen with smaller values:
I suppose you see where this is going. We get a strange distorted visual when we use very small decimal values for the hard colors stops in a gradient. Our noise is born!
We are still far from the grainy noise we want because we can still see the actual conic gradient. But we can decrease the values to very, very small ones — like 0.0001%
— and suddenly there’s no more gradient but pure graininess:
Tada! We have a noise effect and all it takes is one CSS gradient. I bet if I was to show this to you before explaining it, you’d never realize you’re looking at a gradient. You have to look very carefully at center of the gradient to see it.
We can increase the randomness by making the size of the gradient very big while adjusting its position:
The gradient is applied to a fixed 3000px
square and placed at the 60% 60%
coordinates. We can hardly notice its center in this case. The same can be done with radial gradient as well:
And to make things even more random (and closer to a real noise effect) we can combine both gradients and use background-blend-mode
to smooth things out:
Our noise effect is perfect! Even if we look closely at each example, there’s no trace of either gradient in there, but rather beautiful grainy static noise. We just turned that anti-aliasing bug into a slick feature!
Now that we have this, let’s see a few interesting examples where we might use it.
Animated no TV signal
Getting back to the demo we started with:
If you check the code, you will see that I am using a CSS animation on one of the gradients. It’s really as simple as that! All we’re doing is moving the conic gradient’s position at a lightning fast duration (.1s
) and this is what we get!
I used this same technique on a one-div CSS art challenge:
Grainy image filter
Another idea is to apply the noise to an image to get an old-time-y look. Hover each image to see them without the noise.
I am using only one gradient on a pseudo-element and blending it with the image, thanks to mix-blend-mode: overlay
.
We can get an even funnier effect if we use the CSS filter
property
And if we add a mask
to the mix, we can make even more effects!
Grainy text treatment
We can apply this same effect to text, too. Again, all we need is a couple of chained gradients on a background-image
and then blend the backgrounds. The only difference is that we’re also reaching for background-clip
so the effect is only applied to the bounds of each character.
Generative art
If you keep playing with the gradient values, you may get more surprising results than a simple noise effect. We can get some random shapes that look a lot like generative art!
Of course, we are far from real generative art, which requires a lot of work. But it’s still satisfying to see what can be achieved with something that is technically considered a bug!
Monster face
One last example I made for CodePen’s divtober 2022 collection:
Wrapping up
I hope you enjoyed this little CSS experiment. We didn’t exactly learn something “new” but we took a little quirk with gradients and turned it into something fun. I’ll say it again: this isn’t something I would consider using on a real project because who knows if or when anti-aliasing will be addressed at some point in time. Instead, this was a very random, and pleasant, surprise when I stumbled into it. It’s also not that easy to control and it behaves inconsistently across browsers.
This said, I am curious to see what you can do with it! You can play with the values, combine different layers, use a filter
, or mix-blend-mode
, or whatever, and you will for sure get something really cool. Share your creations in the comment section — there are no prizes but we can get a nice collection going!
Making Static Noise From a Weird CSS Gradient Bug originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/PYA5RnJ
via IFTTT
Thursday, November 17, 2022
Cloudy today!
With a high of F and a low of 9F. Currently, it's 16F and Cloudy outside.
Current wind speeds: 11 from the North
Pollen: 0
Sunrise: November 17, 2022 at 07:37PM
Sunset: November 18, 2022 at 05:35AM
UV index: 0
Humidity: 91%
via https://ift.tt/U3MRwD5
November 18, 2022 at 10:03AM
Creating a Settings UI for a Custom WordPress Block
So far, we’ve covered how to work with data from an external API in a custom WordPress block. We walked through the process of fetching that data for use on the front end of a WordPress site, and how to render it directly in the WordPress Block Editor when placing the block in content. This time, we’re going to bridge those two articles by hooking into the block editor’s control panel to create a settings UI for the block we made.
Working With External APIs in WordPress Blocks
- Rendering Data on the Front End
- Rendering Data on the Back End
- Creating a Custom Settings UI (you are here!)
- Saving Custom Block Settings (coming soon)
You know the control panel I’m referring to, right? It’s that panel on the right that contains post and block settings in the block editor.
See that red highlighted area? That’s the control panel. A Paragraph block is currently selected and the settings for it are displayed in the panel. We can change styles, color, typography… a number of things!
Well, that’s exactly what we’re doing this time around. We’re going to create the controls for the settings of the Football Rankings block we worked on in the last two articles. Last time, we made a button in our block that fetches the external data for the football rankings. We already knew the URL and endpoints we needed. But what if we want to fetch ranking for a different country? Or maybe a different league? How about data from a different season?
We need form controls to do that. We could make use of interactive React components — like React-Select — to browse through the various API options that are available to parse that data. But there’s no need for that since WordPress ships with a bunch of core components that we hook right into!
The documentation for these components — called InspectorControls
— is getting better in the WordPress Block Editor Handbook. That’ll get even better over time, but meanwhile, we also have the WordPress Gutenberg Storybook and WordPress Gutenberg Components sites for additional help.
The API architecture
Before we hook into anything, it’s a good idea to map out what it is we need in the first place. I’ve mapped out the structure of the RapidAPI data we’re fetching so we know what’s available to us:
Seasons and countries are two top-level endpoints that map to a leagues endpoint. From there, we have the rest of the data we’re already using to populate the rankings table. So, what we want to do is create settings in the WordPress Block Editor that filter the data by Season, Country, and League, then pass that filtered data into the rankings table. That gives us the ability to drop the block in any WordPress page or post and display variations of the data in the block.
In order to get the standings, we need to first get the leagues. And in order to get the leagues, we first need to get the countries and/or the seasons. You can view the various endpoints in the RapidAPI dashboard.
There are different combinations of data that we can use to populate the rankings, and you might have a preference for which data you want. For the sake of this article, we are going to create the following options in the block settings panel:
- Choose Country
- Choose League
- Choose Season
Then we’ll have a button to submit those selections and fetch the relevant data and pass them into the rankings table.
Load and store a list of countries
We can’t select which country we want data for if we don’t have a list of countries to choose from. So, our first task is to grab a list of countries from RapidAPI.
The ideal thing is to fetch the list of countries when the block is actually used in the page or post content. There’s no need to fetch anything if the block isn’t in use. The approach is very similar to what we did in the first article, the difference being that we are using a different API endpoint and different attributes to store the list of returned countries. There are other WordPress ways to fetch data, like api-fetch, but that‘s outside the scope of what we’re doing here.
We can either include the country list manually after copying it from the API data, or we could use a separate API or library to populate the countries. But the API we’re using already has a list of countries, so I would just use one of its endpoints. Let’s make sure the initial country list loads when the block is inserted into the page or post content in the block editor:
// edit.js
const [countriesList, setCountriesList] = useState(null);
useEffect(() => {
let countryOptions = {
method: "GET",
headers: {
"X-RapidAPI-Key": "Your Rapid API key",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
},
};
fetch("https://api-football-v1.p.rapidapi.com/v3/countries", countryOptions)
.then( (response) => response.json() )
.then( (response) => {
let countriesArray = { ...response };
console.log("Countries list", countriesArray.response);
setCountriesList(countriesArray.response);
})
.catch((err) => console.error(err));
}, []);
We have a state variable to store the list of countries. Next, we are going to import a component from the @wordpress/block-editor package called InspectorControls
which is where all of the components we need to create our settings controls are located.
import { InspectorControls } from "@wordpress/block-editor";
The package’s GitHub repo does a good job explaining InspectorControls
. In our example, we can use it to control the API data settings like Country, League, and Season. Here’s a preview so that you get an idea of the UI we’re making:
And once those selections are made in the block settings, we use them in the block’s Edit
function:
<InspectorControls>
{ countriesList && (
<LeagueSettings
props={props}
countriesList={ countriesList }
setApiData={ setApiData }
></LeagueSettings>
)}
</InspectorControls>
Here, I am making sure that we are using conditional rendering so that the function only loads the component after the list of countries is loaded. If you’re wondering about that LeagueSettings
component, it is a custom component I created in a separate components
subfolder in the block so we can have a cleaner and more organized Edit
function instead of hundreds of lines of country data to deal with in a single file.
We can import it into the edit.js
file like this:
import { LeagueSettings } from "./components/LeagueSettings";
Next, we’re passing the required props to the LeagueSettings
component from the parent Edit
component so that we can access the state variables and attributes from the LeagueSettings
child component. We can also do that with other methods like the Context API to avoid prop drilling, but what we have right now is perfectly suitable for what we’re doing.
The other parts of the Edit
function can also be converted into components. For example, the league standings code can be put inside a separate component — like maybe LeagueTable.js
— and then imported just like we imported LeagueSettings
into the Edit
function.
Inside the LeagueSettings.js
file
LeagueSettings
is just like another React component from which we can destructure the props from the parent component. I am going to use three state variables and an additional leagueID
state because we are going to extract the ID from the league
object:
const [country, setCountry] = useState(null);
const [league, setLeague] = useState(null);
const [season, setSeason] = useState(null);
const [leagueID, setLeagueID] = useState(null);
The first thing we’re going to do is import the PanelBody
component from the @wordpress/block-editor package:
import { PanelBody } from "@wordpress/block-editor";
…and include it in our return
function:
<PanelBody title="Data settings" initialOpen={false}></PanelBody>
There are other panel tags and attributes — it’s just my personal preference to use these ones. None of the others are required… but look at all the components we have available to make a settings panel! I like the simplicity of the PanelBody
for our use case. It expands and collapses to reveal the dropdown settings for the block and that’s it.
Speaking of which, we have a choice to make for those selections. We could use the SelectControl
component or a ComboBoxControl
, which the docs describe as “an enhanced version of a SelectControl
, with the addition of being able to search for options using a search input.” That’s nice for us because the list of countries could get pretty long and users will be able to either do a search query or select from a list.
Here’s an example of how a ComboboxControl
could work for our country list:
<ComboboxControl
label="Choose country"
value={country}
options={ filteredCountryOptions }
onChange={ (value) => handleCountryChange(value) }
onInputChange={ (inputValue) => {
setFilteredCountryOptions(
setupCountrySelect.filter((option) =>
option.label
.toLowerCase()
.startsWith(inputValue.toLowerCase())
)
);
}}
/>
The ComboboxControl
is configurable in the sense that we can apply different sizing for the control’s label and values:
{
value: 'small',
label: 'Small',
},
But our API data is not in this syntax, so we can convert the countriesList
array that comes from the parent component when the block is included:
let setupCountrySelect;
setupCountrySelect = countriesList.map((country) => {
return {
label: country.name,
value: country.name,
};
});
When a country is selected from the ComboboxControl
, the country value changes and we filter the data accordingly:
function handleCountryChange(value) {
// Set state of the country
setCountry(value);
// League code from RapidAPI
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key": "Your RapidAPI key",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
},
};
fetch(`https://api-football-v1.p.rapidapi.com/v3/leagues?country=${value}`, options)
.then((response) => response.json())
.then((response) => {
return response.response;
})
.then((leagueOptions) => {
// Set state of the league variable
setLeague(leagueOptions);
// Convert it as we did for Country options
setupLeagueSelect = leagueOptions.map((league) => {
return {
label: league.league.name,
value: league.league.name,
};
});
setFilteredLeagueOptions(setupLeagueSelect);
})
.catch((err) => console.error(err));
}
Note that I am using another three state variables to handle changes when the country selection changes:
const [filteredCountryOptions, setFilteredCountryOptions] = useState(setupCountrySelect);
const [filteredLeagueOptions, setFilteredLeagueOptions] = useState(null);
const [filteredSeasonOptions, setFilteredSeasonOptions] = useState(null);
What about the other settings options?
I will show the code that I used for the other settings but all it does is take normal cases into account while defining errors for special cases. For example, there will be errors in some countries and leagues because:
- there are no standings for some leagues, and
- some leagues have standings but they are not in a single table.
This isn’t a JavaScript or React tutorial, so I will let you handle the special cases for the API that you plan to use:
function handleLeagueChange(value) {
setLeague(value);
if (league) {
const selectedLeague = league.filter((el) => {
if (el.league.name === value) {
return el;
}
});
if (selectedLeague) {
setLeague(selectedLeague[0].league.name);
setLeagueID(selectedLeague[0].league.id);
setupSeasonSelect = selectedLeague[0].seasons.map((season) => {
return {
label: season.year,
value: season.year,
};
});
setFilteredSeasonOptions(setupSeasonSelect);
}
} else {
return;
}
}
function handleSeasonChange(value) {
setSeason(value);
}
Submitting the settings selections
In the last article, we made a button in the block editor that fetches fresh data from the API. There’s no more need for it now that we have settings. Well, we do need it — just not where it currently is. Instead of having it directly in the block that’s rendered in the block editor, we’re going to move it to our PanelBody
component to submit the settings selections.
So, back in LeagueSettings.js
:
// When countriesList is loaded, show the country combo box
{ countriesList && (
<ComboboxControl
label="Choose country"
value={country}
options={filteredCountryOptions}
onChange={(value) => handleCountryChange(value)}
onInputChange={(inputValue) => {
setFilteredCountryOptions(
setupCountrySelect.filter((option) =>
option.label
.toLowerCase()
.startsWith(inputValue.toLowerCase())
)
);
}}
/>
)}
// When filteredLeagueOptions is set through handleCountryChange, show league combobox
{ filteredLeagueOptions && (
<ComboboxControl
label="Choose league"
value={league}
options={filteredLeagueOptions}
onChange={(value) => handleLeagueChange(value)}
onInputChange={(inputValue) => {
setFilteredLeagueOptions(
setupLeagueSelect.filter((option) =>
option.label
.toLowerCase()
.startsWith(inputValue.toLowerCase())
)
);
}}
/>
)}
// When filteredSeasonOptions is set through handleLeagueChange, show season combobox
{ filteredSeasonOptions && (
<>
<ComboboxControl
label="Choose season"
value={season}
options={filteredSeasonOptions}
onChange={(value) => handleSeasonChange(value)}
onInputChange={
(inputValue) => {
setFilteredSeasonOptions(
setupSeasonSelect.filter((option) =>
option.label
.toLowerCase()
.startsWith(inputValue.toLowerCase()
)
);
}
}
/>
// When season is set through handleSeasonChange, show the "Fetch data" button
{
season && (
<button className="fetch-data" onClick={() => getData()}>Fetch data</button>
)
}
</>
</>
)}
Here’s the result!
We’re in a very good place with our block. We can render it in the block editor and the front end of the site. We can fetch data from an external API based on a selection of settings we created that filters the data. It’s pretty darn functional!
But there’s another thing we have to tackle. Right now, when we save the page or post that contains the block, the settings we selected for the block reset. In other words, those selections are not saved anywhere. There’s a little more work to make those selections persistent. That’s where we plan to go in the next article, so stay tuned.
Creating a Settings UI for a Custom WordPress Block originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
from CSS-Tricks https://ift.tt/J2gcukh
via IFTTT
Mostly Clear today!
With a high of F and a low of 15F. Currently, it's 14F and Clear outside. Current wind speeds: 13 from the Southwest Pollen: 0 S...
-
So you want an auto-playing looping video without sound? In popular vernacular this is the very meaning of the word GIF . The word has stuck...
-
With a high of F and a low of 31F. Currently, it's 37F and Cloudy outside. Current wind speeds: 7 from the Northeast Pollen: 0 S...
-
Last year , we kicked out a roundup of published surveys, research, and other findings from around the web. There were some nice nuggets in ...