CSS works in console but not from a CSS file

I have a Drupal website in which I edit some webpages with the Drupal Layout Builder tool.

The Drupal Layout Builder tool contains a frontend-loaded popup. This popup is a bit narrow for me so I want to broaden it a bit.

This CSS works in console:

#drupal-off-canvas-wrapper {
    width: 600px !important; /* Two times the native 300px */
}

My problem is that this CSS does not work from the website’s main CSS file (other CSS directives in that file do work so it’s not a problem of miscommunication between Drupal and that CSS file).

To try to cope with that problem I have tried the following JavaScript codes to force the CSS change but these work only from console and not from a relevant file which is the website’s main JavaScript file (other JavaScript does work from that file).

window.setInterval(()=>{
    if (window.location.href.includes('layout')) {
        document.querySelector('#drupal-off-canvas-wrapper').style.width = "600px";
    }
}, 1);
window.setTimeout(()=>{
    if (window.location.href.includes('layout')) {
        newStyle = document.createElement("style");
        newStyle.type = "text/css";
        newStyle.innerHTML +=`
        #drupal-off-canvas-wrapper {
            width: 600px !important;
        }
        `;
        document.head.appendChild(newStyle);
    }
}, 5000);

Why would the CSS work from console but not from the main website’s CSS file and what can be done to cope with that problem?

I have managed to somewhat solve this problem with a workaround:

I run the following code with a user script manager (Tampermonkey):

// ==UserScript==
// @name         Drupal Layout Builder Broadening
// @match        https://DOMAIN_NAME.TLD/*

// ==/UserScript==

window.setInterval(()=>{
    if (window.location.href.includes('layout')) {
        document.querySelector('#drupal-off-canvas-wrapper').style.width = "600px";
    }
}, 1);
1 Like

There has got to be a better solution, but if this workaround only needs to set the style once then you can remove that setInterval with clearInterval. Note: setInterval returns a unique ID number.

const intervalId = setInterval( () => {
    if (window.location.href.includes('layout')) {
        document.querySelector('#drupal-off-canvas-wrapper').style.width = "600px";
        clearInterval(intervalId);
    }
}, 100); // 100ms or 10th of a second enough?

Edit: Have you tried wrapping your code with the window load event? What does this output?

window.addEventListener('load', (evt) => {
  console.log(document.querySelector('#drupal-off-canvas-wrapper'))// null? or an element?
})

Is the CSS in the main CSS file being over written somehow?

As an alternative could you make use of specificity? (The more specific selector, winning over the less specific)

#parentElement maybeAnotherParentElement #drupal-off-canvas-wrapper {
  width: 600px !important;
}

It’s difficult to resolve without having hands on access.

1 Like

Here’s what you can try to resolve the issue:

  1. CSS Specificity: Increase the specificity of your CSS rule. For example:

    body path-to-element #drupal-off-canvas-wrapper {
        width: 600px !important;
    }
    

    Replace path-to-element with the actual path to the #drupal-off-canvas-wrapper element to increase specificity.

  2. CSS Load Order: Use Drupal’s hook_library_info_alter() or hook_css_alter() to ensure your CSS file is loaded last.

  3. JavaScript Execution Timing: Make sure your JavaScript code runs after the DOM is fully loaded and after Drupal’s scripts have run. You can use the Drupal.behaviors system to add your JavaScript code, ensuring it executes at the right time.

    (function ($, Drupal) {
      Drupal.behaviors.customOffCanvasWidth = {
        attach: function (context, settings) {
          $('#drupal-off-canvas-wrapper', context).once('custom-off-canvas-width').css('width', '600px');
        }
      };
    })(jQuery, Drupal);
    

    The .once() method ensures your code runs only once per element per page load.

  4. JavaScript Load Event: Instead of setInterval or setTimeout, use the DOMContentLoaded or load event to execute your JavaScript after the page has loaded:

    window.addEventListener('load', function() {
      if (window.location.href.includes('layout')) {
        document.querySelector('#drupal-off-canvas-wrapper').style.width = "600px";
      }
    });
    
  5. Event Delegation: Sometimes elements are dynamically added to the DOM after user interaction. If this is the case, you could listen for changes on the body and then apply your styles:

    document.body.addEventListener('DOMNodeInserted', function(event) {
      if (event.target && event.target.id === 'drupal-off-canvas-wrapper') {
        event.target.style.width = "600px";
      }
    });
    

Good luck.

1 Like
window.addEventListener('load', (evt) => {
  console.log(document.querySelector('#drupal-off-canvas-wrapper'))// null? or an element?
})

undefined

Before clicking the button that loads the popup.

:slight_smile:

#parentElement maybeAnotherParentElement #drupal-off-canvas-wrapper {
  width: 600px !important;
}

In that specific case, I prefer not to go after parent elements. Even more as a general rule, the moment something is loaded frontendly I just want to isolate it the best way I can.

const intervalId = setInterval( () => {
    if (window.location.href.includes('layout')) {
        document.querySelector('#drupal-off-canvas-wrapper').style.width = "600px";
        clearInterval(intervalId);
    }
}, 100); // 100ms or 10th of a second enough?

To test this, I have disabled the user script which I have presented above as a workaround-solution and also turned off the entire user script manager completely and I have also removed the relevant codes from the main CSS file and from the main JS file and then flushed all Drupal caches and then fully reloaded the webpage (CTRL+Shift+R).
I then ran this code in console and after running this code in console, I clicked the button that loads the popup.
For some reason which I don’t know to explain, that worked from console.
This is the first console-ran JavaScript that worked for me.
But, when I pasted this code in the main JS file and flushed all Drupal caches and then fully reloaded the webpage again and tested, it didn’t work.

I avoid using jQuery in every project :slight_smile:

The second code about load event didn’t work from the main JS file.
I actually didn’t use load for starters because even a “brutal” setInterval didn’t help from console before loading the popup.

The third code about even delegation didn’t work from console before loading the popup.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.