Wanna see a whiter white?

Category Image 052

Heck of a CSS trick here from Dongsung Kim.

There are hidden HDR videos playing at the corners of this page. When a HDR-capable browser encounters one, it switches to HDR mode. For some reason, CSS backdrop-filter + brightness >100% combo seems to behave like HDR—reaching beyond the user-controlled display brightness, up to the maximum HDR brightness—while the everything in between follow[s] along. At least that’s the overall idea, but I still don’t know exactly why it works; especially why with those two CSS properties.

As I look at that demo in Chrome, I see an extra-white text-shadow. In Safari, I see extra-white text. In Firefox, the whites match so I see nothing. Probably a bug.

I wouldn’t recommend actually using the trick, as I’d think the extra-whiteness almost certainly takes extra battery power that a user isn’t opting into, even without the video playing—even though it does feel like a bummer that our screens are capable of whiter whites than we normally have access to. The good news is that the gamut of color on the web is expanding, generally.

Direct Link to ArticlePermalink


The post Wanna see a whiter white? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Demystifying styled-components

Category Image 052

 Joshua Comeau digs into how styled-components works by re-building the basics. A fun and useful journey.

styled-components seems like the biggest player in the CSS-in-React market. Despite being in that world, I haven’t yet been fully compelled by it. I’m a big fan of the basics: scoped styles by way of unique class names. I also like that it works with hot module reloading as it all happens in JavaScript. But I get those through css-modules, and I like the file-separation and Sass support I get through css-modules. There are a few things I’m starting to come around on though (a little):

  • Even with css-modules, you still have to think of names. Even if it’s just like .root or whatever. With styled-components you attach the styles right to the component and don’t really name anything.
  • With css-modules, you’re applying the styles directly to an HTML element only. With styled-components you can apply the styles to custom components and it will slap the styles on by way of spreading props later.
  • Because the styles are literally in the JavaScript files, you get JavaScript stuff you can use—ternaries, prop access, fancy math, etc.

Direct Link to ArticlePermalink


The post Demystifying styled-components appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

What does `font: 110%/1.4 system-ui` mean?

Category Image 052

I use this line, or one like it, in a lot of quick demos. Not that it’s not a production-worthy line of code—I just tend to be a bit more explicit on bigger projects.

html {
  font: 110%/1.4 system-ui;
}

Someone wrote in confused by it, and I could see how a line like that is a bit bewildering at first.

The first thing to know is that it is called shorthand. The font property in CSS gives you the opportunity to set a bunch of font-* properties all at once. In this case, we’re setting:

html {
  font-family: system-ui;
  font-size: 110%;
  line-height: 1.4;
}

There are a few more little specific things to know. For example, the order matters.

/* invalid */
html {
  font: system-ui 100%/1.4;
}

You also can’t set the line-height without also setting the font-size. If you’re going to set line-height, you have to set both. Be extra careful there because something like 20px is both a valid line-height and font-size, and if you only set one, it’ll be the font-size. If you go for a unitless number, which is a great idea for line-height, and try to set it alone, it’ll just fail.

/* invalid */
html {
  font: 1.5 system-ui;
}

Of course, we’ve got all this detailed in the Almanac entry for font. But I’ll also give a shout to Mateusz Hadryś who has a detailed article titled “Full Text Styling With a Single Line of CSS” with some detailed figures like this that are helpful in understanding everything:

Showing the font property declaration. Style, variant and weight are in yellow with a label above that says order doesn't matter and a label beneath saying these have to be first. Next is size with a forward slash then line-height in red. Above them is a label that says these have to be next to each other. Next is family in light blue with a label that says it has to be last. There is an additional white label that connects size and family that says they are required.

Lastly, if system-ui was part of the confusion there, that’s one of those System Things.


The post What does `font: 110%/1.4 system-ui` mean? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Custom Property Brain Twisters

Category Image 052

I am part of that 82% that got it wrong in Lea’s quiz (tweet version).

Here’s the code:

:root {
  --accent-color: skyblue;
}

div {
  --accent-color: revert; 
  background: var(--accent-color, orange);
}

So what background do I expect <div> to have?

My brain goes like this:

  1. Well, --accent-color is declared, so it’s definitely not orange (the fallback).
  2. The value for the background is revert, so it’s essentially background: revert;
  3. The background property doesn’t inherit though, and even if you force it to, it would inherit from the <body>, not the root.
  4. So… transparent.

Nope.

Lea:

[Because the value is revert it] cancels out any author styles, and resets back to whatever value the property would have from the user stylesheet and UA stylesheet. Assuming there is no --accent-color declaration in the user stylesheet, and of course UA stylesheets don’t set custom properties, then that means the property doesn’t have a value.

Since custom properties are inherited properties (unless they are registered with inherits: false, but this one is not), this means the inherited value trickles in, which is — you guessed it — skyblue.

Stephen posted a similar quiz the other day:

Again, my brain does it totally wrong. It goes:

  1. OK, well, --color is declared, so it’s not blue (the fallback).
  2. It’s not red because the second declaration will override that one.
  3. So, it’s essentially like p { color: inherit; }.
  4. The <p> will inherit yellow from the <body>, which it would have done naturally anyway, but whatever, it’s still yellow.

Nope.

Apparently inherit there is actually inheriting from the next place up the tree that sets it, which html does, so green. That actually is now normal inheriting works. It’s just a brain twister because it’s easy to conflate color the property with --color the custom property.

It also might be useful to know that when you actually declare a custom property with @property you can say whether you want it to inherit or not. So that would change the game with these brain twisters!

@property --property-name {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

The post Custom Property Brain Twisters appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

“Weak declaration”

Category Image 052

PPK looks at aspect-ratio, a CSS property for layout that, for the most part, does exactly what you would think it does. It’s getting more interesting as it’s behind a flag in Firefox and Safari now, so we’ll have universal support pretty darn soon. I liked how he called it a “weak declaration” which I’m fairly sure isn’t an official term but a good way to think about it.

This will produce a 16 / 9 element:

.movie-card {
  aspect-ratio: 16 / 9;
}

This will too:

.movie-card {
  width: 50%;
  aspect-ratio: 16 / 9;
}

But this won’t:

.movie-card {
  width: 150px;
  height: 150px;
  aspect-ratio: 16 / 9;
}

Because you’ve explicitly set the height and width, that is what will be respected. The aspect-ratio is weak in that it will never override a dimension that is set in any other way.

And it’s not just height and width, it could be max-height that takes effect, so maybe the element follows the Aspect ratio sometimes, but will always respect a max-* value and break the Aspect ratio if it has to.

It’s so weak that not only can other CSS break the Aspect ratio, but content inside the element can break it as well. For example, if you’ve got a ton of text inside an element where the height is only constrained by aspect-ratio, it actually won’t be constrained; the content will expand the element.

I think this is all… good. It feels intuitive. It feels like good default behavior that prevents unwanted side effects. If you really need to force an Aspect ratio on a box with content, the padding trick still works for that. This is just a much nicer syntax that replaces the safe ways of doing the padding trick.

PPK’s article gets into aspect-ratio behavior in flexbox and grid, which definitely has some gotchas. For example, if you are doing align-content: stretch;—that’s one of those things that can break an Aspect ratio. Like he said: weak declaration.


The post “Weak declaration” appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

target=blank

Category Image 052

Does that make your eye twitch a little bit? Like… it’s a typo. It should be target="_blank" with an underscore to start the value. As in…

<a target="_blank" href="https://codepen.io">
  Open CodePen in a New Tab
</a>

Welp, that’s correct syntax!

In the case of the no-underscore target="blank", the blank part is just a name. It could be anything. It could be target="foo" or, perhaps to foreshadow the purpose here: target="open-new-links-in-this-space".

The difference:

  • target="_blank" is a special keyword that will open links in a new tab every time.
  • target="blank" will open the first-clicked link in a new tab, but any future links that share target="blank" will open in that same newly-opened tab.

I never knew this! I credit this tweet explanation.

I created a very basic demo page to show off the functionality (code). Watch as a new tab opens when I click the first link. Then, subsequent clicks from either also open tab open that link in that new second tab.

Why?

I think use cases here are few and far between. Heck, I’m not even that big of a fan of target="_blank". But here’s one I could imagine: documentation.

Say you’ve got a web app where people actively do work. It might make sense to open links to documentation from within that app in a new tab, so they aren’t navigating away from active work. But, maybe you think they don’t need a new tab for every documentation link. You could do like…

<a target="codepen-documentation" 
  href="https://blog.codepen.io/documentation/">
  View CodePen Documentation
</a> 

<!-- elsewhere -->

<a target="codepen-documentation" 
  href="https://blog.codepen.io/documentation/">
  About Asset Hosting
</a>

The post target=blank appeared first on CSS-Tricks.

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

A Crash Course in WordPress Block Filters

Category Image 052

Blocks in WordPress are great. Drop some into the page, arrange them how you like, and you’ve got a pretty sweet landing page with little effort. But what if the default blocks in WordPress need a little tweaking? Like, what if we could remove the alignment options in the Cover block settings? Or how about control sizing for the Button block?

There are plenty of options when it comes to extending the functionality of core blocks in WordPress. We can add a custom CSS class to a block in the editor, add a custom style, or create a block variation. But even those might not be enough to get what you need, and you find yourself needing to filter the core block to add or remove features, or building an entirely new block from scratch.

I’ll show you how to extend core blocks with filters and also touch on when it’s best to build a custom block instead of extending a core one.

A quick note on these examples

Before we dive in, I’d like to note that code snippets in this article are taken out of context on purpose to focus on filters rather than build tools and file structure. If I included the full code for the filters, the article would be hard to follow. With that said, I understand that it’s not obvious for someone who is just starting out where to put the snippets or how to run build scripts and make the whole thing work.

To make things easier for you, I made a WordPress plugin with examples from this article available on my GitHub. Feel free to download it and explore the file structure, dependencies and build scripts. There is a README that will help you get started.

Block filters in an nutshell

The concept of filters is not new to WordPress. Most of us are familiar with the add_filter() function in PHP. It allows developers to modify various types of data using hooks.

A simple example of a PHP filter could look something like this:

function filter_post_title( $title ){
  return '<strong>' . $title . '</strong>';
};

add_filter( 'the_title',  'filter_post_title' );

In this snippet, we create a function that receives a string representing a post title, then wrap it in a <strong> tag and return a modified title. We then use add_filter() to tell WordPress to use that function on a post title.

JavaScript filters work in a similar way. There is a JavaScript function called addFilter() that lives in the wp.hooks package and works almost like its PHP sibling. In its simplest form, a JavaScript filter looks something like this:

function filterSomething(something) {
  // Code for modifying something goes here.
  return something;
}

wp.hooks.addFilter( 'hookName', 'namespace', filterSomething );

Looks pretty similar, right? One notable difference is addFilter() has a namespace as a second argument. As per the WordPress Handbook, “Namespace uniquely identifies a callback in the the form vendor/plugin/function.” However, examples in the handbook follow different patterns: plugin/what-filter-does or plugin/component-name/what-filter-does. I usually follow the latter because it keeps the handles unique throughout the project.

What makes JavaScript filters challenging to understand and use is the different nature of what they can filter. Some filter strings, some filter JavaScript objects, and others filter React components and require understanding the concept of Higher Order Components.

On top of that, you’ll most likely need to use JSX which means you can’t just drop the code into your theme or plugin and expect it to work. You need to transpile it to vanilla JavaScript that browsers understand. All that can be intimidating at the beginning, especially if you are coming from a PHP background and have limited knowledge of ES6, JSX, and React.

But fear not! We have two examples that cover the basics of block filters to help you grasp the idea and feel comfortable working with JavaScript filters in WordPress. As a reminder, if writing this code for the Block Editor is new to you, explore the plugin with examples from this article.

Without any further ado, let’s take a look at the first example.

Removing the Cover block’s alignment options

We’re going to filter the core Cover block and remove the Left, Center, Right, and Wide alignment options from its block settings. This may be useful on projects where the Cover block is only used as a page hero, or a banner of some sort and does not need to be left- or right-aligned.

We’ll use the blocks.registerBlockType filter. It receives the settings of the block and its name and must return a filtered settings object. Filtering settings allows us to update the supports object that contains the array of available alignments. Let’s do it step-by-step.

We’ll start by adding the filter that just logs the settings and the name of the block to the console, to see what we are working with:

const { addFilter } = wp.hooks;

function filterCoverBlockAlignments(settings, name) {
  console.log({ settings, name });
  return settings;
}

addFilter(
  'blocks.registerBlockType',
  'intro-to-filters/cover-block/alignment-settings',
  filterCoverBlockAlignments,
);

Let’s break it down. The first line is a basic destructuring of the wp.hooks object. It allows us to write addFilter() in the rest of the file, instead of wp.hooks.addFilter(). This may seem redundant in this case, but it is useful when using multiple filters in the same file (as we’ll get to in the next example).

Next, we defined the filterCoverBlockAlignments() function that does the filtering. For now, it only logs the settings object and the name of the block to the console and returns the settings as is.

All filter functions receive data, and must return filtered data. Otherwise, the editor will break.

And, lastly, we initiated the filter with addFilter() function. We provided it with the name of the hook we are going to use, the filter namespace, and a function that does the filtering.

If we’ve done everything right, we should see a lot of messages in the console. But note that not all of them refer to the Cover block.

This is correct because the filter is applied to all blocks rather than the specific one we want. To fix that, we need to make sure that we apply the filter only to the core/cover block:

function filterCoverBlockAlignments(settings, name) {
  if (name === 'core/cover') {
    console.log({ settings, name });
  }
  return settings;
}

With that in place, we should see something like this now in the console:

Don’t worry if you see more log statements than Cover blocks on the page. I have yet to figure out why that’s the case. If you happen to know why, please share in the comments!

And here comes the fun part: the actual filtering. If you have built blocks from scratch before, then you know that alignment options are defined with Supports API. Let me quickly remind you how it works — we can either set it to true to allow all alignments, like this:

supports: {
  align: true
}

…or provide an array of alignments to support. The snippet below does the same thing, as the one above:

supports: {
  align: [ 'left', 'right', 'center', 'wide', 'full' ]
}

Now let’s take a closer look at the settings object from one of the console messages we have and see what we are dealing with:

All we need to do is replace align: true with align: ['full'] inside the supports property. Here’s how we can do it:

function filterCoverBlockAlignments(settings, name) {
  if (name === 'core/cover') {
    return assign({}, settings, {
      supports: merge(settings.supports, {
        align: ['full'],
      }),
    });
  }
  return settings;
}

I’d like to pause here to draw your attention to the assign and merge lodash methods. We use those to create and return a brand new object and make sure that the original settings object remains intact. The filter will still work if we do something like this:

/* 👎 WRONG APPROACH! DO NOT COPY & PASTE! */
settings.supports.align = ['full'];
return settings;

…but that is an object mutation, which is considered a bad practice and should be avoided unless you know what you are doing. Zell Liew discusses why mutation can be scary over at A List Apart.

Going back to our example, there should now only be one alignment option in the block toolbar:

I removed the “center” alignment option because the alignment toolbar allows you to toggle the alignment “on” and “off.” This means that Cover blocks now have default and “Full width” states.

And here’s the full snippet:

const { addFilter } = wp.hooks;
const { assign, merge } = lodash;

function filterCoverBlockAlignments(settings, name) {
  if (name === 'core/cover') {
    return assign({}, settings, {
      supports: merge(settings.supports, {
        align: ['full'],
      }),
    });
}
  return settings;
}

addFilter(
  'blocks.registerBlockType',
  'intro-to-filters/cover-block/alignment-settings',
  filterCoverBlockAlignments,
);

This wasn’t hard at all, right? You are now equipped with a basic understanding of how filters work with blocks. Let’s level it up and take a look at a slightly more advanced example.

Adding a size control to the Button block

Now let’s add a size control to the core Button block. It will be a bit more advanced as we will need to make a few filters work together. The plan is to add a control that will allow the user to choose from three sizes for a button: Small, Regular, and Large.

The goal is to get that new “Size settings” section up and running.

It may seem complicated, but once we break it down, you’ll see that it’s actually pretty straightforward.

1. Add a size attribute to the Button block

First thing we need to do is add an additional attribute that stores the size of the button. We’ll use the already familiar blocks.registerBlockType filter from the previous example:

/**
 * Add Size attribute to Button block
 *
 * @param  {Object} settings Original block settings
 * @param  {string} name     Block name
 * @return {Object}          Filtered block settings
 */
function addAttributes(settings, name) {
  if (name === 'core/button') {
    return assign({}, settings, {
      attributes: merge(settings.attributes, {
        size: {
          type: 'string',
          default: '',
        },
      }),
    });
  }
  return settings;
}

addFilter(
  'blocks.registerBlockType',
  'intro-to-filters/button-block/add-attributes',
  addAttributes,
);

The difference between what we’re doing here versus what we did earlier is that we’re filtering attributes rather than the supports object. This snippet alone doesn’t do much and you won’t notice any difference in the editor, but having an attribute for the size is essential for the whole thing to work.

2. Add the size control to the Button block

We’re working with a new filter, editor.BlockEdit. It allows us to modify the Inspector Controls panel (i.e. the settings panel on the right of the Block editor).

/**
 * Add Size control to Button block
 */
const addInspectorControl = createHigherOrderComponent((BlockEdit) => {
  return (props) => {
    const {
      attributes: { size },
      setAttributes,
      name,
    } = props;
    if (name !== 'core/button') {
      return <BlockEdit {...props} />;
    }
    return (
      <Fragment>
        <BlockEdit {...props} />
        <InspectorControls>
          <PanelBody
            title={__('Size settings', 'intro-to-filters')}
            initialOpen={false}
          >
            <SelectControl
              label={__('Size', 'intro-to-filters')}
              value={size}
              options={[
                {
                  label: __('Regular', 'intro-to-filters'),
                  value: 'regular',
                },
                {
                  label: __('Small', 'intro-to-filters'),
                  value: 'small'
                },
                {
                  label: __('Large', 'intro-to-filters'),
                  value: 'large'
                },
              ]}
              onChange={(value) => {
                setAttributes({ size: value });
              }}
            />
          </PanelBody>
      </InspectorControls>
      </Fragment>
    );
  };
}, 'withInspectorControl');

addFilter(
  'editor.BlockEdit',
  'intro-to-filters/button-block/add-inspector-controls',
  addInspectorControl,
);

This may look like a lot, but we’ll break it down and see how straightforward it actually is.

The first thing you may have noticed is the createHigherOrderComponent construct. Unlike other filters in this example, editor.BlockEdit receives a component and must return a component. That’s why we need to use a Higher Order Component pattern derived from React.

In its purest form, the filter for adding controls looks something like this:

const addInspectorControl = createHigherOrderComponent((BlockEdit) => {
  return (props) => {
    // Logic happens here.
    return <BlockEdit {...props} />;
  };
}, 'withInspectorControl');

This will do nothing but allow you to inspect the <BlockEdit /> component and its props in the console. Hopefully the construct itself makes sense now, and we can keep breaking down the filter.

The next part is destructuring the props:

const {
  attributes: { size },
  setAttributes,
  name,
} = props;

This is done so we can use name, setAttributes, and size in the scope of the filter, where:

  • size is the attribute of the block that we’ve added in step 1.
  • setAttributes is a function that lets us update the block’s attribute values.
  • name is a name of the block. which is core/button in our case.

Next, we avoid inadvertantly adding controls to other blocks:

if (name !== 'core/button') {
  return <BlockEdit {...props} />;
}

And if we are dealing with a Button block, we wrap the settings panel in a <Fragment /> (a component that renders its children without a wrapping element) and add an additional control for picking the button size:

return (
  <Fragment>
    <BlockEdit {...props} />
    {/* Additional controls go here */}
  </Fragment>
);

Finally, additional controls are created like this:

<InspectorControls>
  <PanelBody title={__('Size settings', 'intro-to-filters')} initialOpen={false}>
    <SelectControl
      label={__('Size', 'intro-to-filters')}
      value={size}
      options={[
        { label: __('Regular', 'intro-to-filters'), value: 'regular' },
        { label: __('Small', 'intro-to-filters'), value: 'small' },
        { label: __('Large', 'intro-to-filters'), value: 'large' },
      ]}
      onChange={(value) => {
        setAttributes({ size: value });
      }}
    />
  </PanelBody>
</InspectorControls>

Again, if you have built blocks before, you may already be familiar with this part. If not, I encourage you to study the library of components that WordPress comes with.

At this point we should see an additional section in the inspector controls for each Button block:

We are also able to save the size, but that won’t reflect in the editor or on the front end. Let’s fix that.

3. Add a size class to the block in the editor

As the title suggests, the plan for this step is to add a CSS class to the Button block so that the selected size is reflected in the editor itself.

We’ll use the editor.BlockListBlock filter. It is similar to editor.BlockEdit in the sense that it receives the component and must return the component; but instead of filtering the block inspector panel, if filters the block component that is displayed in the editor.

import classnames from 'classnames';
const { addFilter } = wp.hooks;
const { createHigherOrderComponent } = wp.compose;

/**
 * Add size class to the block in the editor
 */
const addSizeClass = createHigherOrderComponent((BlockListBlock) => {
  return (props) => {
    const {
      attributes: { size },
      className,
      name,
    } = props;

    if (name !== 'core/button') {
      return <BlockListBlock {...props} />;
    }

    return (
      <BlockListBlock
        {...props}
        className={classnames(className, size ? `has-size-${size}` : '')}
      />
    );
  };
}, 'withClientIdClassName');

addFilter(
   'editor.BlockListBlock',
   'intro-to-filters/button-block/add-editor-class',
   addSizeClass
);

You may have noticed a similar structure already:

  1. We extract the size, className, and name variables from props.
  2. Next, we check if we are working with core/button block, and return an unmodified <BlockListBlock> if we aren’t.
  3. Then we add a class to a block based on selected button size.

I’d like to pause on this line as it may look confusing from the first glance:

className={classnames(className, size ? `has-size-${size}` : '')}

I’m using the classnames utility here, and it’s not a requirement — I just find using it a bit cleaner than doing manual concatenations. It prevents me from worrying about forgetting to add a space in front of a class, or dealing with double spaces.

4. Add the size class to the block on the front end

All we have done up to this point is related to the Block Editor view, which is sort of like a preview of what we might expect on the front end. If we change the button size, save the post and check the button markup on the front end, notice that button class is not being applied to the block.

To fix this, we need to make sure we are actually saving the changes and adding the class to the block on the front end. We do it with blocks.getSaveContent.extraProps filter, which hooks into the block’s save() function and allows us to modify the saved properties. This filter receives block props, the type of the block, and block attributes, and must return modified block props.

import classnames from 'classnames';
const { assign } = lodash;
const { addFilter } = wp.hooks;

/**
 * Add size class to the block on the front end
 *
 * @param  {Object} props      Additional props applied to save element.
 * @param  {Object} block      Block type.
 * @param  {Object} attributes Current block attributes.
 * @return {Object}            Filtered props applied to save element.
 */
function addSizeClassFrontEnd(props, block, attributes) {
  if (block.name !== 'core/button') {
    return props;
  }

  const { className } = props;
  const { size } = attributes;

  return assign({}, props, {
    className: classnames(className, size ? `has-size-${size}` : ''),
  });
}

addFilter(
  'blocks.getSaveContent.extraProps',
  'intro-to-filters/button-block/add-front-end-class',
  addSizeClassFrontEnd,
);

In the snippet above we do three things:

  1. Check if we are working with a core/button block and do a quick return if we are not.
  2. Extract the className and size variables from props and attributes objects respectively.
  3. Create a new props object with an updated className property that includes a size class if necessary.

Here’s what we should expect to see in the markup, complete with our size class:

<div class="wp-block-button has-size-large">
  <a class="wp-block-button__link" href="#">Click Me</a>
</div>

5. Add CSS for the custom button sizes

One more little thing before we’re done! The idea is to make sure that large and small buttons have corresponding CSS styles.

Here are the styles I came up with:

.wp-block-button.has-size-large .wp-block-button__link {
  padding: 1.5rem 3rem;
}
.wp-block-button.has-size-small .wp-block-button__link {
  padding: 0.25rem 1rem;
}

If you are building a custom theme, you can include these front-end styles in the theme’s stylesheet. I created a plugin for the default Twenty Twenty One theme, so, in my case, I had to create a separate stylesheet and include it using wp_enqueue_style(). You could just as easily work directly in functions.php if that’s where you manage functions.

function frontend_assets() {
  wp_enqueue_style(
    'intro-to-block-filters-frontend-style',
    plugin_dir_url( __FILE__ ) . 'assets/frontend.css',
    [],
    '0.1.0'
  );
}
add_action( 'wp_enqueue_scripts', 'frontend_assets' );

Similar to the front end, we need to make sure that buttons are properly styled in the editor. We can include the same styles using the enqueue_block_editor_assets action:

function editor_assets() {
  wp_enqueue_style(
    'intro-to-block-filters-editor-style',
    plugin_dir_url( __FILE__ ) . 'assets/editor.css',
    [],
    '0.1.0'
  );
}
add_action( 'enqueue_block_editor_assets', 'editor_assets' );

We should now should have styles for large and small buttons on the front end and in the editor!

As I mentioned earlier, these examples are available in as a WordPress plugin I created just for this article. So, if you want to see how all these pieces work together, download it over at GitHub and hack away. And if something isn’t clear, feel free to ask in the comments.

Use filters or create a new block?

This is a tricky question to answer without knowing the context. But there’s one tip I can offer.

Have you ever seen an error like this?

It usually occurs when the markup of the block on the page is different from the markup that is generated by the block’s save() function. What I’m getting at is it’s very easy to trigger this error when messing around with the markup of a block with filters.

So, if you need to significantly change the markup of a block beyond adding a class, I would consider writing a custom block instead of filtering an existing one. That is, unless you are fine with keeping the markup consistent for the editor and only changing the front-end markup. In that case, you can use PHP filter.

Speaking of which…

Bonus tip: render_block()

This article would not be complete without mentioning the render_block hook. It filters block markup before it’s rendered. It comes in handy when you need to update the markup of the block beyond adding a new class.

The big upside of this approach is that it won’t cause any validation errors in the editor. That said, the downside is that it only works on the front end. If I were to rewrite the button size example using this approach, I would first need to remove the code we wrote in the fourth step, and add this:

/**
 * Add button size class.
 *
 * @param  string $block_content Block content to be rendered.
 * @param  array  $block         Block attributes.
 * @return string
 */
function add_button_size_class( $block_content = '', $block = [] ) {
  if ( isset( $block['blockName'] ) && 'core/button' === $block['blockName'] ) {
    $defaults = ['size' => 'regular'];
    $args = wp_parse_args( $block['attrs'], $defaults );

    $html = str_replace(
      '<div class="wp-block-button',
      '<div class="wp-block-button has-size-' . esc_attr( $args['size']) . ' ',
      $block_content
    );

    return $html;
}
  return $block_content;
}

add_filter( 'render_block', 'add_button_size_class', 10, 2 );

This isn’t the cleanest approach because we are injecting a CSS class using str_replace() — but that’s sometimes the only option. A classic example might be working with a third-party block where we need to add a <div> with a class around it for styling.

Wrapping up

WordPress block filters are powerful. I like how it allows you to disable a lot of unused block options, like we did with the Cover block in the first example. This can reduce the amount of CSS you need to write which, in turn, means a leaner stylesheet and less maintenance — and less cognitive overhead for anyone using the block settings.

But as I mentioned before, using block filters for heavy modifications can become tricky because you need to keep block validation in mind.

That said, I usually reach for block filters if I need to:

  • disable certain block features,
  • add an option to a block and can’t/don’t want to do it with custom style (and that option must not modify the markup of the block beyond adding/removing a custom class), or
  • modify the markup only on the front end (using a PHP filter).

I also usually end up writing custom blocks when core blocks require heavy markup adjustments both on the front end and in the editor.

If you have worked with block filters and have other thoughts, questions, or comments, let me know!

Resources


The post A Crash Course in WordPress Block Filters appeared first on CSS-Tricks.

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

2021 Design Systems (Survey/Courses)

Category Image 052

My friends at Sparkbox are doing a survey on design systems, as they do each year. Go ahead and fill it out if you please. Here are the results from last year. In both 2019 and 2020, the vibe was that design systems (both as an idea and as a real thing that real companies really use) are maturing. But still, it was only a quarter of folks who said their actual design system was mature. I wonder if that’ll go up this year.

In my circles, “design system” isn’t the buzzword it was a few years ago, but it doesn’t mean it’s less popular. If anything, they are more popular almost entering the territory of assumed, like responsive design is. I do feel like if you’re building a website from components, well, you’ve got a component library at least, which is how I think of design systems (as a dude who pretty much exclusively works on websites).

I’d better be careful though. I know design systems mean different things to different people. Speaking of which, I’d be remiss if I didn’t also shout out the fact that Ethan has a handful of totally free courses he’s created on design systems.

As you might have guessed from the titles, we’ve broadly organized the courses around roles: whether you’re a designer, a developer, or a product manager, we’ve got something for you. Each course focuses on what I think are the fundamentals of design systems work, so I’ve designed them to be both high-level and packed with information


The post 2021 Design Systems (Survey/Courses) appeared first on CSS-Tricks.

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

16px or Larger Text Prevents iOS Form Zoom

Category Image 052

This was a great “Today I Learned” for me from Josh W. Comeau. If the font-size of an <input> is 16px or larger, Safari on iOS will focus into the input normally. But as soon as the font-size is 15px or less, the viewport will zoom into that input. Presumably, because it considers that type too small and wants you to see what you are doing. So it zooms in to help you. Accessibility. If you don’t want that, make the font big enough.

Here’s Josh’s exact Pen if you want to have a play yourself.

In general, I’d say I like this feature. It helps people see what they are doing and discourages super-tiny font sizes. What is a slight bummer — and I really don’t blame anyone here — is that not all typefaces are created equal in terms of readability at different sizes. For example, here’s San Francisco versus Caveat at 16px.

San Francisco on the left, Cavet on the right. Caveat looks visually much smaller even though the font-size is the same.

You can view that example in Debug Mode to see for yourself and change the font size to see what does and doesn’t zoom.


The post 16px or Larger Text Prevents iOS Form Zoom appeared first on CSS-Tricks.

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

Let’s use (X, X, X, X) for talking about specificity

Category Image 052

I was just chatting with Eric Meyer the other day and I remembered an Eric Meyer story from my formative years. I wrote a blog post about CSS specificity, and Eric took the time to point out the misleading nature of it (I remember scurrying to update it). What was so misleading? The way I was portraying specificity as a base-10 number system.

Say you select an element with ul.nav. I insinuated in the post that the specificity of that selector was 0011 (eleven, essentially), which is a number in a base-10 system. So I was saying tags = 0, classes = 10, IDs = 100, and a style attribute = 1000. If specificity was calculated in a base-10 number system like that, a selector like ul.nav.nav.nav.nav.nav.nav.nav.nav.nav.nav.nav (11 class names) would have a specificity of 0111, which would be the same as ul#nav.top. That’s not true. The reality is that it would be (0, 0, 11, 1) vs. (0, 1, 0, 1) with the latter easily winning.

That comma-separated syntax like I just used solves two problems:

  1. It doesn’t insinuate a base-10 number system (or any number system)
  2. It has a distinct and readable look

I like the (X, X, X, X) look. I could see limiting it to (X, X, X) since a style attribute isn’t exactly a selector and usually isn’t talked about in the same kind of conversations. The parens make it more clear to me, but I could also see a X-X-X (dash-separated) syntax that wouldn’t need them, or a (X / X / X) syntax that probably would benefit from the parens.

Selectors Level 3 uses dashes briefly. Level 2 used both dashes and commas in different places.

Anyway, apparently I get the bug to mention this every half-decade or so.


The post Let’s use (X, X, X, X) for talking about specificity appeared first on CSS-Tricks.

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

Jenny B Kowalski’s A-Z (and a-z) as Variable Letterforms

Category Image 052

Jenny B Kowalski has been posting a-letter-a-day on Instagram exploring multi-axis variable/responsive letterforms. They are very clever in that one of the axes controls an uppercase-to-lowercase conversion, literally morphing the shape of the letters from an uppercase version to a lowercase version. The other axis is a stroke weight, which also dramatically changes the feel of the letters.

Here’s Q, one of my favorites:

She’s using p5.js, but I don’t see any reason these couldn’t be made into a variable font with custom axes.

OK here’s one more. I find the I/i very clever:


The post Jenny B Kowalski’s A-Z (and a-z) as Variable Letterforms appeared first on CSS-Tricks.

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

How to Improve CSS Performance

Featured Imgs 25

There is no doubt that CSS plays a huge role in web performance. Milica Mihajlija puts a point on exactly why:

When there is CSS available for a page, whether it’s inline or an external stylesheet, the browser delays rendering until the CSS is parsed. This is because pages without CSS are often unusable.

The browser has to wait until the CSS is both downloaded and parsed to show us that first rendering of the page, otherwise browsing the web would be a terribly visually jerky to browse. We’d probably write JavaScript to delay page rendering on purpose if that’s how the native web worked.

So how do you improve it? The classics like caching, minification, and compression help. But also, shipping less of it, and only loading the bit you need and the rest after the first render.

It’s entirely about how and how much CSS you load, and has very little to do with the contents of the the CSS.

Direct Link to ArticlePermalink


The post How to Improve CSS Performance appeared first on CSS-Tricks.

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

Hiding Content Responsibly

Featured Imgs 25

We’ve covered the idea of hiding things in CSS many times here, the most recent post being Marko Ilic’s “Comparing Various Ways to Hide Things in CSS” which did a nice job of comparing different techniques which you’d use in different situations. Hugo “Kitty” Giraudel has done something similar in “Hiding Content Responsibly” which looks at 10 methods—and even those, you could say, aren’t totally comprehensive.

Does this mean CSS is messy and incomprehensible? Nah. I feel like all the methods are logical, have good use cases, and result in good outcomes. Allow me to do a have a pretend conversation walking through my thought process here.

I need to hide this thing completely. For everyone.

No problem, use display: none;.

I need to hide this thing, but only hide it for screen readers, not visually. (For example, an icon that has no additional meaning for screen readers, as there is an accessible label nearby.)

No problem, that’s what the aria-hidden attribute is for.

I need to hide this thing, but only visually, not for screen readers. (For example, the contents of non-active tabs.)

No problem, use a .sr-only class. That leaves it accessible but hides it visually until you remove that class.

Oops, I actually want to hide this thing visually, but I still want it to take up physical space, not collapse. (For example, say a button has a loading spinner icon that is only needed when performing an action. The size of the button should factor in the size of that icon all the time, not just when the spinner is visible. That way, there’s no layout shifting when that icon comes and goes.)

No problem, use transform: scale(0) which will visually collapse it, but the original space will remain, and will leave it accessible to screen readers.

Oh nice, I could transition the transform, too, I suppose. But actually, that transition doesn’t fit my site well. I just want something I can fade out and fade in.

The opacity property is transitional, so transition that between 0 and 1 for fades. The good news is that visibility is also transitional. When fading out, use visibility: hidden, and when fading in, use visibility: visible to hide and unhide the thing from screen readers.


That’s not entirely comprehensive, but I find that covers 95% of hiding cases.


The post Hiding Content Responsibly appeared first on CSS-Tricks.

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

You want…

Category Image 052

I’ve been enjoying these little “You want…” style posts. Post titles like that are a little more… forceful for my normal taste, but I like the spirit of sharing a best practice that perhaps isn’t well-known-enough.

Got an idea along these lines? You should blog it! Here or elsewhere.


The post You want… appeared first on CSS-Tricks.

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

Maximally optimizing image loading for the web in 2021

Featured Imgs 25

Malte Ubl’s list for:

8 image loading optimization techniques to minimize both the bandwidth used for loading images on the web and the CPU usage for image display.

  1. Fluid width images in CSS, not forgetting the height and width attributes in HTML so you get proper aspect-ratio on first render.
  2. Use content-visibility: auto;
  3. Send AVIF when you can.
  4. Use responsive images syntax.
  5. Set far-out expires headers on images and have a cache-busting strategy (like changing the file name).
  6. Use loading="lazy"
  7. Use decoding="async"
  8. Use inline CSS/SVG for a blurry placeholder.

Apparently, there is but one tool that does it all: eleventy-high-performance-blog.

My thoughts:

  • If you are lazy loading, do you really need to do the content-visibilty thing also? They seem very related.
  • Serving AVIF is usually good, but it seems less cut-and-dry than WebP was. You need to make sure your AVIF version is both better and smaller, which feels like a manual process right now.
  • The decoding thing seems weird. I’ll totally use it if it’s a free perf win, but if it’s always a good idea, shouldn’t the browser just always do it?
  • I’m not super convinced blurry placeholders are in the same category of necessary as the rest of this stuff. Feels like a trend.

Direct Link to ArticlePermalink


The post Maximally optimizing image loading for the web in 2021 appeared first on CSS-Tricks.

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

Styling Web Components

Category Image 052

Nolan Lawson has a little emoji-picker-element that is awfully handy and incredibly easy to use. But considering you’d probably be using it within your own app, it should be style-able so it can incorporated nicely anywhere. How to allow that styling isn’t exactly obvious:

What wasn’t obvious to me, though, was how to allow users to style it. What if they wanted a different background color? What if they wanted the emoji to be bigger? What if they wanted a different font for the input field?

Nolan list four possibilities (I’ll rename them a bit in a way that helps me understand them).

  1. CSS Custom Properties: Style things like background: var(--background, white);. Custom properties penetrate the Shadow DOM, so you’re essentially adding styling hooks.
  2. Pre-built variations: You can add a class attribute to the custom elements, which are easy to access within CSS inside the Shadow DOM thanks to the pseudo selectors, like :host(.dark) { background: black; }.
  3. Shadow parts: You add attributes to things you want to be style-able, like <span part="foo">, then CSS from the outside can reach in like custom-component::part(foo) { }.
  4. User forced: Despite the nothing in/nothing out vibe of the Shadow DOM, you can always reach the element.shadowRoot and inject a <style>, so there is always a way to get styles in.

It’s probably worth a mention that the DOM you slot into place is style-able from “outside” CSS as it were.

This is such a funky problem. I like the Shadow DOM because it’s the closest thing we have on the web platform to scoped styles which are definitely a good idea. But I don’t love any of those styling solutions. They all seem to force me into thinking about what kind of styling API I want to offer and document it, while not encouraging any particular consistency across components.

To me, the DOM already is a styling API. I like the scoped protection, but there should be an easy way to reach in there and style things if I want to. Seems like there should be a very simple CSS-only way to reach inside and still use the cascade and such. Maybe the dash-separated custom-element name is enough? my-custom-elemement li { }. Or maybe it’s more explicit, like @shadow my-custom-element li { }. I just think it should be easier. Constructable Stylesheets don’t seem like a step toward make it easier, either.

Last time I was thinking about styling web components, I was just trying to figure out how to it works in the first place, not considering how to expose styling options to consumers of the component.

Does this actually come up as a problem in day-to-day work? Sure does.

I don’t see any particularly good options in that thread (yet) for the styling approach. If I was Dave, I’d be tempted to just do nothing. Offer minimal styling, and if people wanna style it, they can do it however they want from their copy of the component. Or they can “force” the styles in, meaning you have complete freedom.


The post Styling Web Components appeared first on CSS-Tricks.

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

On Auto-Generated Atomic CSS

Featured Imgs 23

Robin Weser’s “The Shorthand-Longhand Problem in Atomic CSS” in an interesting journey through a tricky problem. The point is that when you take on the job of converting something HTML and CSS-like into actual HTML and CSS, there are edge cases that you’ll have to program yourself out of, if you even can at all. In this case, Fela (which we just mentioned), turns CSS into “atomic” classes, but when you mix together shorthand and longhand, the resulting classes, mixed with the cascade, can cause mistakes.

I think this whole idea of CSS-in-JS that produces Atomic CSS is pretty interesting, so let’s take a quick step back and look at that.

Atomic CSS means one class = one job

Like this:

.mb-8 {
  margin-bottom: 2rem;
}

Now imagine, like, thousands of those that are available to use and can do just about anything CSS can do.

Why would you do that?

Here’s some reasons:

  • If you go all-in on that idea, it means that you’ll ship less CSS because there are no property/value pairs that are repeated, and there are are no made-up-for-authoring-reasons class names. I would guess an all-atomic stylesheet (trimmed for usage, which we’ll get to) is a quarter the size of a hand-authored stylesheet, or smaller. Shipping less CSS is significant because CSS is a blocking resource.
  • You get to avoid naming things.
  • You get some degree of design consistency “for free” if you limit the available classes.
  • Some people just prefer it and say it makes them faster.

How do you get Atomic CSS?

There is nothing stopping you from just doing it yourself. That’s what GitHub did with Primer and Facebook did in FB5 (not that you should do what mega corporations do!). They decided on a bunch of utility styles and shipped it (to themselves, largely) as a package.

Perhaps the originator of the whole idea was Tachyons, which is a just a big ol’ opinionated pile of classes you can grab as use as-is.

But for the most part…

Tailwind is the big player.

Tailwind has a bunch of nice defaults, but it does some very smart things beyond being a collection of atomic styles:

  • It’s configurable. You tell it what you want all those classes to do.
  • It encourages you to “purge” the unused classes. You really need to get this part right, as you aren’t really getting the benefit of Atomic CSS if you don’t.
  • It’s got a UI library so you can get moving right away.

Wait weren’t we talking about automatically-generated Atomic CSS?

Oh right.

It’s worth mentioning that Yahoo was also an early player here. Their big idea is that you’d essentially use functions as class names (e.g. class="P(20px)") and that would be processed into a class (both in the HTML and CSS) during a build step. I’m not sure how popular that got really, but you can see how it’s not terribly dissimilar to Tailwind.

These days, you don’t have to write Atomic CSS to get Atomic CSS. From Robin’s article:

It allows us to write our styles in a familiar “monolithic” way, but get Atomic CSS out. This increases reusability and decreases the final CSS bundle size. Each property-value pair is only rendered once, namely on its first occurence. From there on, every time we use that specific pair again, we can reuse the same class name from a cache. Some libraries that do that are:

Fela
Styletron
React Native Web
Otion
StyleSheet

In my honest opinion, I think that this is the only reasonable way to actually use Atomic CSS as it does not impact the developer experience when writing styles. I would not recommend to write Atomic CSS by hand.

I think that’s neat. I’ve tried writing Atomic CSS directly a number of times and I just don’t like it. Who knows why. I’ve learned lots of new things in my life, and this one just doesn’t click with me. But I definitely like the idea of computers doing whatever they have to do to boost web performance in production. If a build step turns my authored CSS into Atomic CSS… hey that’s cool. There are five libraries above that do it, so the concept certainly has legs.

It makes sense that the approaches are based on CSS-in-JS, as they absolutely need to process both the markup and the CSS — so that’s the context that makes the most sense.

What do y’all think?


The post On Auto-Generated Atomic CSS appeared first on CSS-Tricks.

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

Fixing Smooth Scrolling with Find-on-Page

Category Image 052

Back when we released the v17 design (we’re on v18 now) of this site. I added html { scroll-behavior: smooth; } to the CSS. Right away, I got comments like this (just one example):

… when you control+f or command+f and search on CSS-Tricks, it’ll scroll very slowly instead of snapping to the result, which makes finding information and keywords on CSS-Tricks much slower. As someone who uses this shortcut frequently, this is a usability issue for me.

Not terribly long after, I just removed it. I didn’t feel that strongly about it, and the fact that you have almost zero control over it, made me just can the idea.

I see it come up as a “CSS tip” a lot, so I chimed in with my experience:

After mentioning that, Christian Schaefer chimed in with a great idea:

Love that!

Christian blogged it:

Smooth scrolling is consequently applied to everything. Always. Even when cycling through the browser’s page search results. At least that’s the case for Chromium. So for the page search it would be desirable for the browser to make an exception to that rule and to deactivate smooth scrolling. Until the Chromium team fixes it, here is a trick how to solve the problem on your own with a little bit of extra CSS and HTML.

I’m not sure if Chrome (or any other browser) would consider that a bug or not. I doubt it’s specced since find-on-page isn’t really a web technology feature. But anyway, I much prefer find-on-page without it.

html:focus-within {
  scroll-behavior: smooth;
}

It mostly works. The bummer part about it is situations like this…

<a href="#link-down-the-page">Jump down</a>

...

<h2 id="link-down-the-page">Header</h2>

That will jump the page down. With scroll-behavior: smooth; in place, that’s kinda nice. But <h2> is typically not a “focusable” element. So, with the trick above, there is now no focus within <html> anymore, and the smooth scrolling is lost. If you want to preserve that, you’d have to do:

<h2 tabindex="-1" id="link-down-the-page">Header</h2>

The post Fixing Smooth Scrolling with Find-on-Page appeared first on CSS-Tricks.

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