Skip to content

[Bug]: CSS: @value replacement in keyframes/animation produces broken output #15612

Closed

Description

@Knagis

System Info

rspack 2.2.3

Details

@value replacement for animation + @keyframes produce broken output:

===== input =====
@value animName: pulseAnim;

.anim {
    animation: animName 2s linear;
}

@keyframes animName {
    from { opacity: 0; }
}

===== rspack (native css/module) output =====
.css-modules-value-animation-src_index_css-anim {
    animation: pulseAnim 2s linear;
}

@keyframes css-modules-value-animation-src_index_css-animName {
    from { opacity: 0; }
}

note - webpack native css also has an issue, though with different output: webpack/webpack#22030

Reproduce link

https://github.com/Knagis/rspack-webpack-css-value-animation

Reproduce Steps

npm install
npm run build

Activity

  1. added theissue type on Sep 10, 2026
  2. Knagis commented on Sep 10, 2026

    @Knagis
    Author

    Expected Behavior... Needs to be aligned with webpack.

    Likely to keep consistency with how @value are used (not hashed) in selectors:

    .anim_hash {
        animation: pulseAnim 2s linear;
    }
    
    @keyframes pulseAnim {
        from { opacity: 0; }
    }
  3. self-assigned this
    on Sep 10, 2026
  4. intellild commented on Sep 10, 2026

    @intellild
    Contributor

    I checked css-loader and the name is hashed.
    localIdentName: "[path][name]__[local]--[hash:base64:5]"

    .src-index__anim--aDRCe {
        animation: 2s linear src-index__pulseAnim--rpbwN;
    }
    @keyframes src-index__pulseAnim--rpbwN {
        0% {
            opacity: 0;
        }
    }

    I will align with css-loader first.

  5. Knagis commented on Sep 10, 2026

    @Knagis
    Author

    css-loader is deprecated now, and it doesn't even support values in selectors that webpack and rspack native css support does support.

    /* input */
    @value sel: .globalThing;
    
    sel {
        color: blue;
    }
    
    /* output */
    .XbSZ44YRvgGzLB6rR_A1 {
        color: blue;
    }
  6. intellild commented on Sep 10, 2026

    @intellild
    Contributor

    Emmm, latest webpack emits a warning for re-declaration while the generated name is incorrect.
    If we treat at-value and at-keyframes as variable declarations, this is actually correct output.

    @value animName: pulseAnim; // <- first declaration
    
    .anim {
        animation: animName 2s linear; // <- deref first declaration here
    }
    
    @keyframes animName { // <- declare the second one, the first declaration is shadowed
        from { opacity: 0; }
    }
    
  7. intellild commented on Sep 10, 2026

    @intellild
    Contributor

    If you want to keep the animation name, at-value is not needed. Just set parser['css/module'].animation = false
    https://rspack.rs/config/module-parser#cssautoanimation

  8. Knagis commented on Sep 10, 2026

    @Knagis
    Author

    @intellild If the logic that @keyframes override @value holds (why not, seems logical) then would it be expected that for

    @value animName: pulseAnim;
    
    @keyframes animName {
        from { opacity: 0; }
    }
    
    .anim {
        animation: animName 2s linear;
    }

    this produces the same output - the animation reference uses the first declaration, not the second.

    @keyframes css-modules-value-animation-src_index_css-animName {
        from { opacity: 0; }
    }
    
    .css-modules-value-animation-src_index_css-anim {
        animation: pulseAnim 2s linear;
    }

    Perhaps the better approach is to throw an error when such conflict is encountered to make it explicitly not supported?

    I personally don't have clear preference, we don't use this case, it was something that i found while making sure @value for typical cases work for us, and thought it worth reporting - primarily because of the inconsistency with webpack.

  9. intellild commented on Sep 10, 2026

    @intellild
    Contributor

    Thanks for reporting, this I will add a warning

  10. locked and limited conversation to collaborators on Sep 10, 2026
  11. converted this issue into a discussion #15621 on Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions