Open Closed

Angular Style Declaration Order is ignored when injecting styles into the DOM since upgrade to ABP 9.3.1 #9821


User avatar
0
mharnos created

Hi, while upgrading from 9.1.1 and 9.2.3 to 9.3.1 we're experiencing a regression in the angular frontend regarding the order of style injections. It seems that previously the injection order was preserved / similar to the one declared in angular.json which is good because we want to override some variables and styles from the lepton-x theme. This is no longer possible because the style injector is always injecting the lepton styles after the ones provided by angular.

Production (9.1.1):

Local (9.3.1):

Question 1) Do you know how I can load my style at the very bottom? Do I need to provide my own Style Load Factory / LPX_PRO_STYLE_TOKEN or LPX_LAYOUT_STYLE_FINAL or LPX_STYLE_FINAL?

Question 2) Is this something you're planning to fix? Because in the code I've seen this comment

      const linkElem = this.createLinkElem(style, direction, resolve);
      //TODO: find a better way for understand style laaded by angular json
      const appStyles = document.querySelector(
        'link[rel="stylesheet"][href*="styles"]'
      );

Which leads me to think that this could be improved.

Kind Regards, Marc


11 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • In ABP 9.3.x, the LeptonX theme and style injection mechanism for Angular was updated, and the order of style injection may no longer match the order in angular.json. This can affect your ability to override LeptonX theme variables/styles with your own styles.

    • To ensure your custom styles are loaded after the LeptonX theme, you should inject your override styles dynamically at runtime, or use higher CSS specificity or !important as a workaround. The current ABP LeptonX style loader does not provide a built-in configuration to guarantee your styles are injected last via angular.json order.

    • You do not need to provide your own LPX_PRO_STYLE_TOKEN, LPX_LAYOUT_STYLE_FINAL, or LPX_STYLE_FINAL unless you want to fully customize the style loading process. The current loader does not expose a public API for reordering, but you can create a custom provider to control style injection order if necessary.

    • The ABP team is aware of the limitation, as indicated by the //TODO comment in the code. However, there is no official fix or configuration for this in 9.3.x. You can follow the official LeptonX theme documentation and community article for best practices and updates:

      • To override LeptonX theme variables, add your custom CSS to styles.scss and use CSS variables as shown below:
    :root {
          --lpx-logo: url('/assets/images/logo.png');
          --lpx-logo-icon: url('/assets/images/logo-icon.png');
          --lpx-brand: #edae53;
        }
    
    • If you need to guarantee order, inject your custom style sheet dynamically after the app starts, or use a workaround like importing your CSS at the end of the main style file.

    • This is a known area for improvement, and you can track updates or provide feedback via the official channels.

    Sources:


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    mharnos created

    Hi,

    I didn't really get an answer for this topic before it was auto-closed. Could you have another look into this, or give me some feedback on what the right approach would be on providing global styling, that can override LeptonX Themes?

    Kind Regards, Marc

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Hi,

    I didn't really get an answer for this topic before it was auto-closed. Could you have another look into this, or give me some feedback on what the right approach would be on providing global styling, that can override LeptonX Themes?

    Kind Regards, Marc

    Hello Marc,

    The questions are automatically closed when we do not get interaction. Seeing that, we will be managing this issue internally. You can follow the process here https://github.com/abpframework/abp/releases

    Until we publish the fix, you can extend the default service to override the related function.

    import { DOCUMENT, inject, Injectable } from '@angular/core';
    import { LPX_STYLE_FINAL, LpxStyle, StyleService } from '@volo/ngx-lepton-x.core';
    @Injectable({
      providedIn: 'root',
    })
    export class MyStyleService extends StyleService {
      private myDocument = inject<Document>(DOCUMENT);
    
      constructor() {
        super(inject(LPX_STYLE_FINAL), inject(DOCUMENT));
      }
    
      override loadStyle(style: LpxStyle, direction: 'ltr' | 'rtl'): Promise<HTMLStyleElement | void> {
        return new Promise(resolve => {
          const linkElement = this.createLinkElem(style, direction, resolve);
          const styleLinks = Array.from(
            this.myDocument.head.querySelectorAll('link[rel="stylesheet"]')
          );
          const firstStyleLink = styleLinks[0];
    
          if (firstStyleLink) {
            firstStyleLink.insertAdjacentElement('beforebegin', linkElement);
          } else {
            this.myDocument.head.appendChild(linkElement);
          }
    
          this.lastInjectedStyle = linkElement;
          resolve(linkElement);
        });
      }
    }
    

    Then, in your app.config.ts

    export const appConfig: ApplicationConfig = {
      providers: [
        // ...
        {
          provide: StyleService,
          useClass: MyStyleService,
        },
      ],
    };
    
    

    You can let us know if you need further assistance. Thank you for your cooperation.

  • User Avatar
    0
    MichelZ created

    We have the same issue I think on the Lepton (non-X) theme... How would we resolve that?

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Your problem may not be related to this since it is already loaded at the end

  • User Avatar
    0
    MichelZ created

    Ours looks like this:

    <link rel="stylesheet" href="lepton4.css">
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="ngx-datatable-index.css">
    <link rel="stylesheet" href="ngx-datatable-icons.css">
    <link rel="stylesheet" href="ngx-datatable-material.css">
    <link rel="stylesheet" href="fontawesome-all.min.css">
    <link rel="stylesheet" href="fontawesome-v4-shims.min.css">
    

    And in production (with ABP 9.2) we have:

    <link rel="stylesheet" href="lepton4-X4OK76EB.css">
    <link rel="stylesheet" href="ngx-datatable-index-ALC7J2LN.css">
    <link rel="stylesheet" href="ngx-datatable-icons-YZZVGCGU.css">
    <link rel="stylesheet" href="ngx-datatable-material-QROZ42NV.css">
    <link rel="stylesheet" href="fontawesome-all.min-V43YH5Q7.css">
    <link rel="stylesheet" href="fontawesome-v4-shims.min-5GHJGPBV.css">
    <link rel="stylesheet" href="styles-3O3IHLFY.css">
    
  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Hello,

    I have tested the lepton theme to produce this. Here is my finding:

    • If styles.css is present, your injected styles go before it.
    • If not, your injected styles go at the end of <head>.
    • The sequence determines which styles take precedence (last loaded usually wins in CSS).

    This logic ensures your custom styles are positioned relative to the main stylesheet, affecting which styles are applied or overridden.

    You can also see it in the source code:

    //theme-lepton/src/lib/providers/styles.provider.ts
    export function injectStyle(injector: Injector) {
      const rendererFactory = injector.get(RendererFactory2);
      const domInsertion = injector.get(DomInsertionService);
    
      rendererFactory
        .createRenderer(document.body, null)
        .addClass(document.body, 'abp-application-layout');
    
      const appStyles: HTMLElement = document.querySelector('link[rel="stylesheet"][href*="styles"]');
      let content: StyleContentStrategy;
      if (appStyles) {
        const domStrategy = DOM_STRATEGY.BeforeElement(appStyles);
        content = new StyleContentStrategy(styles, domStrategy, undefined, {
          id: LEPTON_STYLE_ELEMENT_ID,
        });
      } else {
        content = CONTENT_STRATEGY.AppendStyleToHead(styles, { id: LEPTON_STYLE_ELEMENT_ID });
      }
    
      domInsertion.insertContent(content);
    }
    

    If you think that your version does not rely on this configuration, you can create a separate ticket and I can assist further in the thread. Thank you for your cooperation.

  • User Avatar
    0
    MichelZ created

    Thanks, I have created a new thread. https://abp.io/support/questions/9848/stylecss-loaded-in-wrong-order

  • User Avatar
    0
    MichelZ created

    I've fixed the issue now. We had a this in the styles array in angular.json: "node_modules/@yaireo/tagify/dist/tagify.css", after lepton4.css but before the ngx-datable one's.

    Moving it to the end, it worked

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you for the response. I am happy to hear that your problem has been solved. Is there anything I could assist besides?

  • User Avatar
    0
    MichelZ created

    Thanks, we're good. Have a nice day :)

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 04, 2025, 08:36