Skip to content

[Bug] GDPR banner CSS global * selector in prefers-reduced-motion breaks third-party lightboxes #167

@parhumm

Description

@parhumm

Validation Result: Confirmed Bug

Verdict: VALID_BUG | Confidence: HIGH | Severity: Medium

Source: https://wordpress.org/support/topic/seemingly-unrelated-problem/

Summary

The GDPR banner stylesheet (assets/css/gdpr-banner.css) includes a global * selector inside a @media (prefers-reduced-motion: reduce) block that overrides animation-duration, animation-iteration-count, and transition-duration on every element on the page with !important. This breaks third-party plugins that rely on CSS transitions — notably FancyBox V2 used by the Firelight Lightbox plugin, causing images to display at incorrect (smaller) dimensions.

Root Cause

Fault Location: assets/css/gdpr-banner.css:466-476
Mechanism: Global * selector with !important overrides kills all CSS transitions site-wide when the user's OS has reduced-motion accessibility enabled.

/* Current — overly broad scope */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

Causal Chain:

Trigger: User upgrades SlimStat to v5.4.1
  → Entry Point: GDPR banner enabled by default (wp-slimstat.php — use_slimstat_banner => 'on')
    → CSS loaded: gdpr-banner.css enqueued on frontend (wp-slimstat.php:1129-1134)
      → Fault: Global * selector in @media (prefers-reduced-motion) (gdpr-banner.css:466-476)
        → Impact: All CSS transitions/animations on page killed with !important
          → FancyBox V2 lightbox can't resize to full image dimensions

5 Whys:

  1. Why do images display smaller in FancyBox? → Because FancyBox transitions are killed (0.01ms)
  2. Why are transitions killed? → Because a global * CSS rule overrides all transition-duration with !important
  3. Why is this global rule active? → Because gdpr-banner.css applies it to all elements when prefers-reduced-motion: reduce matches
  4. Why does prefers-reduced-motion match? → Because the user's laptop has OS-level reduced motion enabled — ROOT CAUSE (CSS scope too broad)

Reproduction Steps

Preconditions: WordPress with WP Slimstat v5.4.1 (GDPR banner enabled by default), any plugin using CSS transitions (e.g., Firelight Lightbox with FancyBox V2), OS reduced-motion setting enabled.

  1. Enable reduced motion in OS settings (macOS: System Settings > Accessibility > Display > Reduce motion; Windows: Settings > Ease of Access > Display > Show animations)
  2. Visit a page with gallery images using a lightbox plugin
  3. Click an image to open the lightbox
  4. Observe: image displays at smaller/incorrect size instead of full dimensions

Expected: Lightbox opens at full image size regardless of SlimStat being active
Actual: Lightbox shows smaller image due to killed CSS transitions

Note: This only manifests on devices with reduced-motion enabled, which explains why the reporter saw it on their laptop but not their desktop.

Proposed Fix

Scope the prefers-reduced-motion rule to SlimStat's own banner elements only:

/* Fixed — scoped to SlimStat banner only */
@media (prefers-reduced-motion: reduce) {
    #slimstat-gdpr-banner,
    #slimstat-gdpr-banner * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    #slimstat-gdpr-banner {
        animation: none;
    }
}

Code References

File Lines Description
assets/css/gdpr-banner.css 466-476 Global * selector in prefers-reduced-motion kills ALL transitions/animations
wp-slimstat.php 847 Default changed: use_slimstat_banner => 'on'
wp-slimstat.php 243-246 GDPR banner enqueue condition
wp-slimstat.php 1123-1134 enqueue_gdpr_assets() loads the CSS

Security Note

If implementing a fix based on this analysis:

  • Verify the fix doesn't introduce new vulnerabilities
  • Run security linting (SAST) on changed code
  • Check for OWASP Top 10 in any new code paths

Validated via qa-issue-validate skill (jaan.to plugin)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions