Skip to content

[Bug] Button's utility color classes seems to not hover properly due specificity issues #42

@Allyhere

Description

@Allyhere

First of all, congratulations on Matcha CSS; it has been very interesting to create projects using it. I was exploring the documentation and noticed that buttons with utility color classes turn blue on :hover.

Hovering on buttons with utility colors classes

If the example below is the expected behavior of these buttons, I believe this is a specificity bug:

GravacaodeTela2024-07-14as13 23 06-ezgif com-video-to-gif-converter

Bug description

Using the .default variant as an example, this is the CSS with the intended behavior:

button.default:not(:disabled):active,button.default:not(:disabled):hover {
    background: var(--default);
    color: var(--contrast)
}

It produces a 0,3,1 specificity and it is being overridden by this selector, which also has a specificity of 0.3.1 because its declared further on the code.

:is(button,input:is([type=submit],[type=reset],[type=button],[type=image])):not(:disabled):active,:is(button,input:is([type=submit],[type=reset],[type=button],[type=image])):not(:disabled):hover {
    border-color: transparent;
    background: var(--accent);
    color: var(--light)
}

Proposal

There are a few solutions for this bug, ranging from the highest to the lowest impact:

1 - Using an :where selector

Note

This solution is agnostic and non-obstrusive and have sufficient browser support. PR with proposal #43

In styles/forms/mod.css, L226

:where(button, input:is([type="submit"],[type="reset"],[type="button"],[type="image"])):not(:disabled):hover,
:where(button, input:is([type="submit"],[type="reset"],[type="button"],[type="image"])):not(:disabled):active {
  border-color: transparent;
  background: var(--accent);
  color: var(--light);
}

It lowers the specificity to 0,2,0 and it allows the button's utility CSS to take precedence.

2 - Using an :where selector as an architectural axiom

Note

This solution is agnostic and non-obstrusive and have sufficient browser support but it will require a more comprehensive change and may potentially lead to a major version increment. Proposal in this draft PR

Every CSS subdirectory acts as a module that serves both base styles and utility-oriented styles. For base styles related directly to HTML elements, you may want to maintain the lowest specificity possible to avoid collision with utility styles.
I suggest Elad Shechter approach on CSS Reset. This ensures that every "base" styles will be safely overridden.

3 - Using an @layer at rule to separate base and utility layers

Note

This solution is agnostic and non-obstrusive and have sufficient browser support but it will require a more comprehensive change and may potentially lead to a major or breaking version increment.

You may create two layers in every module, defining the layers in mod.css and appending the base styles to the base layer in the standalone version:

/* styles/forms/mod.css */

@layer base, components;

@layer base {
  /* Form */
  form {
    overflow: auto;
    padding: 1rem;
    border-radius: var(--bd-radius);
    margin: 0 auto 1rem;
    background: var(--bg-muted);
  }
}

And appending the utility code in the utility layer. If you re-declare this layer combination in multiple files, they will all append to the implicit layer with the same name, so there will be no drawback in declaring @layer base, components; in every mod file for À la carte build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions