Drupal.displace() (see https://git.drupalcode.org/project/drupal/-/blob/9.4.x/core/misc/displac...) is a method that allows JavaScript to query for the offsets of fixed admin elements on the page.

For example,

  • if the Admin Toolbar is active, running Drupal.displace() will return {top: 79, right: 0, bottom: 0, left: 0}.
  • If the Settings Tray and Admin Toolbar are open, running Drupal.displace() will return {top: 79, right: 300, bottom: 0, left: 0}.

Problem

When creating themes for Drupal, themers frequently want to place fixed items against the top of the viewport (or other edges). This will cause the fixed element to overlap the toolbar (or other admin element). Themers frequently aren't aware of Drupal.displace() (I wasn't until @lauriii told me about it), so they either ignore the problem or hard code the values for the toolbars in their CSS.

Solution

Because Drupal 10 no longer supports IE, we can use CSS custom properties (aka CSS variables) to output the displacement values. This will allow themers to 1) discover that these CSS custom properties exist by looking in Developer Tools, and 2) easily hook into the values without having to write custom JavaScript through something like the following:

.my-fixed.header {
  position: fixed;
  top: var(--drupal-displace-offset-top, 0);
}

Comments

mherchel created an issue. See original summary.

mherchel’s picture

Status: Active » Needs review
StatusFileSize
new2.01 KB

This patch implements this with the namespace of --drupal-displace--offset-<edge>

mherchel’s picture

StatusFileSize
new2.1 KB
mherchel’s picture

StatusFileSize
new2.1 KB
nod_’s picture

+1, we should update the css variables before the event though

nod_’s picture

Not sure what happened with the files here.

nod_’s picture

StatusFileSize
new2.1 KB

reupdating the patch from #4

mherchel’s picture

Status: Needs review » Needs work

Thanks for looking at this!

It looks to me like you accidentally re-uploaded the patch from #4. You still have the correct patch? Or I can make the change, too.

nod_’s picture

it was on purpose, it got deleted somehow from the issue summary.

nod_’s picture

Status: Needs work » Needs review

moved the prop change before the event trigger + small refactor

I do wonder if there is a performance hit.

We have a debounce on the resize event but are the props updated fast enough. Going to the style props is pretty slow. Might want to figure out which edge changed (if any) to avoid needless updates.

nod_’s picture

StatusFileSize
new6.88 KB

forgot to update a patch for #10. anyway going with an other approach.

I tried to use the new css variable to handle the toolbar offset of the body/html element. Went mostly well but ran into troubles because of how tableheader interracts with the offsets object. That means i went with a different approach, making Drupal.displace.offsets smarter and making sure that whenever a value is assigned to top/left/bottom/right the corresponding CSS custom variable is also updated. With this code it's possible to replace a bit of code from the toolbar and move that piece from the JS to the CSS:

body { padding-top: var(--drupal-displace--offset-top, 0px); }
html { scroll-padding-top: var(--drupal-displace--offset-top, 0px); }

this is not part of this patch because toolbar should use it's own variable to mess with the body padding because not everything that displace the offset top might move the body down (I guess).

One question is around the naming. Do we have a naming convention for css variables yet? Should we use logical properties names (start/end) instead of left/right?

mherchel’s picture

One question is around the naming. Do we have a naming convention for css variables yet?

We do not yet. My hope is that we can solidify it in #3254529: [PLAN] Drupal CSS Modernization Initiative, but so far, I haven't seen too much traction.

That being said, I'm assuming it's possible to make the change here, and then when/if there are formal conventions for naming the CSS variables, we can then update the code at that time (assuming its before beta)?

Should we use logical properties names (start/end) instead of left/right?

I had the same thought. It really determines how the displace function works.

I'm going to step through the code to see if I can understand it better. It's still slightly opaque to me.

mherchel’s picture

Currently it seems that the component that sets its data-offset- edge is responsible for determining if the page is currently RTL.

You can see this in off-canvas.es6.js at https://git.drupalcode.org/project/drupal/-/blob/10.0.x/core/misc/dialog... , which is used to set the attribute for the settings tray.

 getEdge() {
      return document.documentElement.dir === 'rtl' ? 'left' : 'right';
    },

If we were to change the variable naming to start, end, it would imply to me that the components wouldn't need to manage that. ​

So, at this point it makes sense to me to keep the naming to left, and right. That being said, we should really refactor this now that we don't have to support IE11.

nod_’s picture

That being said, I'm assuming it's possible to make the change here, and then when/if there are formal conventions for naming the CSS variables, we can then update the code at that time (assuming its before beta)?

That works for me, we'll need to check with Lauriii. It opens the box of how to document/expose custom css variables names (scope?) and purpose

mherchel’s picture

StatusFileSize
new7.16 KB
new552 bytes

Patch in #11 looks great!

I'm personally not too familiar with OO JavaScript, so it was fun stepping through and following along. The patch works perfectly.

I believe that I found one nitpick with a change that needs to be made to the comments, and am fixing it and attaching an interdiff. Note there are no changes to the transpiled file.

The first parameter is not a regular DOM HTMLElement, and not a jQuery Element as specified in the next line.

  /**
   * Calculates displacement for element based on its dimensions and placement.
   *
   * @param {HTMLElement} el
   *   The jQuery element whose dimensions and placement will be measured.
   *
   * @param {string} edge
   *   The name of the edge of the viewport that the element is associated
   *   with.
   *
   * @return {number}
   *   The viewport displacement distance for the requested edge.
   */
  function getRawOffset(el, edge) {
    const $el = $(el);
    const documentElement = document.documentElement;
mherchel’s picture

Status: Needs review » Postponed
Issue tags: +Needs change record

Talked to @lauriii. He prefers that we postpone this until #3257287: [Policy] Create CSS standards for core use of CSS custom properties (aka CSS Variables) is resolved.

We also need a change record.

andy-blum’s picture

Reviewed patch #15 and +1 for RTBC, but leaving the status as postponed per #16.

There are 2 main followup issues I'd recommend here:

  1. Add support for CSS logical properties (block/inline-start/end). This would allow projects to utilize the displacement library without having to account for language direction differences.
  2. Use the calculated displacement values to set scroll-padding values, which would allow the displacment library to work more seamlessly with the CSS scroll-snap properties and JavaScript scrolling methods
mherchel’s picture

Issue summary: View changes
Status: Postponed » Needs work
Issue tags: +Needs tests

Talked with @lauriii about this today.

We can un-postpone this, and rename the variables to --drupal-displace-offset-top

We also need some basic tests (Drupal.displace() is currently untested as far as I can tell).

andregp’s picture

StatusFileSize
new1.59 KB
new7.24 KB

I updated the variable name on displace.es6.js and ran yarn run build:js to rebuild displace.js automatically.

Still needs work for adding tests though.

mherchel’s picture

According to Drupal.displace()'s CR,

Tests, utilizing the Testswarm project, can be found in the FAT module: http://drupal.org/project/fat

The tests are viewable at

https://git.drupalcode.org/project/fat/-/blob/8.x-1.x/tests/drupal.displ...

mherchel’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new12.92 KB
new5.69 KB

Note that this patch also includes the fix from #3272727: Nightwatch's drupalModuleInstall() doesn't handle test modules or modules w underscores in machine name, which I discovered when writing this patch.

This patch adds nightwatch tests for Drupal.displace() and is heavily influenced by the tests at https://git.drupalcode.org/project/fat/-/blob/8.x-1.x/tests/drupal.displ...

mherchel’s picture

StatusFileSize
new12.92 KB

Version that uses template literals in the JS tests

nod_’s picture

Tests looks good to me! can't RTBC the whole patch but the test part is good to go.

mherchel’s picture

andy-blum’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new587.38 KB
new689.74 KB
new547.22 KB
new71.62 KB
new91.63 KB

Screenshots of patch #24 in place:

Admin toolbar sets displacement of 39px.

Opening the manage menu adds another 40px to our custom property.

Shrinking the window reduces offset-top back to 39px and sets the offset-left to 240 (239px width + 1px border-right).

Inspecting Drupal.displace.offsets object shows 4 values with getters & setters.

Trying to add a new custom value doesn't error, but also doesn't succeed.

RTBC, pending tests

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 24: 3256768-24.patch, failed testing. View results

mherchel’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated failure

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 24: 3256768-24.patch, failed testing. View results

mherchel’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated failure.

lauriii’s picture

  1. +++ b/core/misc/displace.es6.js
    @@ -26,22 +26,64 @@
        *
    

    Nit: I guess we could remove the extra newline.

  2. +++ b/core/misc/displace.es6.js
    @@ -139,31 +181,21 @@
    +   * @param {bool} [broadcast=true]
        *   When true or undefined, causes the recalculated offsets values to be
        *   broadcast to listeners.
    

    The comment should be updated as well

mherchel’s picture

Unpublished change record created at https://www.drupal.org/node/3275981

mherchel’s picture

Issue tags: -Needs change record
mherchel’s picture

StatusFileSize
new13.87 KB
new750 bytes

Updated patch (and interdiff) attached.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 33: 3256768-33.patch, failed testing. View results

mherchel’s picture

Status: Needs work » Reviewed & tested by the community

Previous unrelated failure. Test is now passing.

mherchel’s picture

StatusFileSize
new12.06 KB

#33 had some unrelated changes relating to another issue. Attached is a patch with only the relevant files.

  • lauriii committed f8c91fd on 10.0.x
    Issue #3256768 by mherchel, nod_, andregp, andy-blum: Drupal.displace()...
lauriii’s picture

Status: Reviewed & tested by the community » Fixed

Committed f8c91fd and pushed to 10.0.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.