As far as I can see all 7x versions have had this problem; but I haven't tested further back than 7.32 since that's when I discovered it. Haven't tested other major versions.

Description: On page load the admin toolbar adds padding-top to the body element so it is not (partially) hidden under the toolbar. The toolbar is responsive so if the screen size changes the height of the toolbar may change; however the padding-top value is never updated.

Platforms/Browser: Should be replicateable/fixed by patch on all but tested with: Windows 7, Firefox 35.0(a2), IE 9 & 10, Chrome 38.

Replication:

  • Load minimal site (any site will do really)
  • Change viewport size or zoom - ie from maximized to one half of the screen in vertical orientation. Has to be big enough change to to change how many rows of buttons are on the toolbar.
  • Now the toolbar will overlay or have a big gap between it and the content because it still has the original padding-top value.

Fix is very simple; just adding resize handler to update the padding-top value; patch file attached.

Comments

xjm’s picture

Version: 7.33 » 7.x-dev
Issue tags: +Needs manual testing
dawehner’s picture

Issue tags: +JavaScript

.

nickdickinsonwilde’s picture

Tested and I can confirm it is not a problem in 8.x - the toolbar being very different.

nickdickinsonwilde’s picture

Screenshots:
Load maximized window:
load maximized window
resize window:
toolbar floats adjust and the toolbar is now taller. However the padding that is applied to the body is not updated so it pushes down over the header/title/top content (depending on site):
resize window
with patch on resize:
body padding is adjust to move up/down as required:
resize window with patch

nod_’s picture

Status: Needs review » Needs work
Issue tags: -Needs manual testing

Well that works very well.

There has been so much frustration with this, yet the patch is that simple :p

The binding isn't done in the right place though. We'll end up binding it a lot of times for nothing when ajax is involved. please move that code to Drupal.toolbar.init

nickdickinsonwilde’s picture

StatusFileSize
new461 bytes

Moved (and since I'm generally bad about not documenting also added a little comment). Updated patch attached.

nickdickinsonwilde’s picture

Status: Needs work » Needs review
nod_’s picture

Status: Needs review » Needs work

Looked a bit more into it, because resize is used a lot it's worth spending some time on optimizations.

  1. Can you add some lines to make sure we change the body padding value when that value actually changes? Right now we're trashing things and it makes the browser recalculate a lot of stuff it shouldn't have to.
  2. Can you cache $('body') in a variable outside the resize callback? Don't need to query it at every resize.
  3. And use 'padding-top' instead of 'paddingTop', saves jQuery from doing some work as well.

After that we're good to go. Ideal would be to add debouncing but it's a bit out of scope I think.

nickdickinsonwilde’s picture

Status: Needs work » Needs review
StatusFileSize
new806 bytes
new1.54 KB

Yeah optimization is always a good idea, thanks for help.
1. Oh yes; make the script itself take more time but compared to the browser recalcing a lot of extra probably better I'm assuming.
2. Yes. I need to do this more in all my projects, I'm good at always chaining if possible but I definitely should cache more. I gave a quick look and $(body) was used a couple other times (in onClick) handlers in the toolbar module so I replaced them as well, since that wasn't far out of scope.
3. Sure, I didn't actually know that was any performance difference, thanks for the tip.

nickdickinsonwilde’s picture

nickdickinsonwilde’s picture

@Nod_: anything else I should do on this?
Thanks;
Nick

nod_’s picture

Status: Needs review » Needs work

wow long overdue review, sorry.

  1. +++ b/modules/toolbar/toolbar.js
    @@ -2,6 +2,8 @@
    +Drupal.toolbar.body = $('body');
    

    You can make it a local $body variable. There is no need to expose this in the Drupal object.

  2. +++ b/modules/toolbar/toolbar.js
    @@ -35,6 +37,13 @@ Drupal.toolbar.init = function() {
    +    if (parseInt(Drupal.toolbar.body.css('padding-top')) !== Drupal.toolbar.height()) {
    

    The issue with this is that we're still hitting the DOM to get the size of body padding. We can know this value. I would rather create a new local variable and cache that padding value, updating it and the padding-top value only when it changes.

    // in toolbar.init().
    var paddingTop = parseInt($body.css('padding-top'), 10);
    
    // Inside the resize handler.
    var height = Drupal.toolbar.height()
    if (paddingTop !== height) {
      paddingTop = height;
      $body.css('padding-top', paddingTop);
    }
    

    That way we limit our interactions with the DOM to the minimum.

nickdickinsonwilde’s picture

Status: Needs work » Needs review
StatusFileSize
new3.33 KB

Fine, not like you're being paid. (I have lots of open source experience working at various positions within projects so I totally understand).
Re #1: okay sure, done.
Re #2: This one I can think of possible cases that would conflict (if something else is JavaScript modifying the Body's padding-top at somepoint after toolbar init); however I think the risk of that is pretty low. So did almost exactly the changes you suggested.

After doing those two things I did notice some other optimizations possible; Same as the body height check it was using $() so I cached that. Also a bunch of code was being run in the toolbar.height() function, that only needed to be run once on init (that was already being run unnecessarily whenever the lower toolbar was added/removed). So the patch has grown a fair bit actually and now despite the added resize processing the whole toolbar.js should be faster.

Status: Needs review » Needs work

The last submitted patch, 13: patchv5.patch, failed testing.

nickdickinsonwilde’s picture

Status: Needs work » Needs review
StatusFileSize
new3.33 KB

oops typo in the patch somehow.
Merry Christmas/Happy Holidays btw.

nod_’s picture

Status: Needs review » Needs work

It goes a little bit beyond a simple change but it makes a lot of sense.

It'll need to be profiled to check whether the additional changes have some visible (to the profiler, not user) perf improvements compared to the naive approach. I'm pretty sure it'll be the case because we get rid of a call to .css() in all browsers.

Provided the profiling shows improvement big +1 from me.

few nitpicks:

  1. +++ b/modules/toolbar/toolbar.js
    @@ -2,6 +2,11 @@
    +//since some selectors are being used in a resize handler lets cache them.
    

    space and capital here: // Since…

  2. +++ b/modules/toolbar/toolbar.js
    @@ -2,6 +2,11 @@
    +var $body = $('body');
    +var $toolbar = $('#toolbar');
    +var toolbarHeightModifier = 0;
    

    This should be initialized in Drupal.behavior, we can't be sure the DOM is loaded outside a behavior. Edgecase-y but still.

nickdickinsonwilde’s picture

StatusFileSize
new3.75 KB

1. Fixed capitalization
2. Moved to behaviour for setting the value; of course had to leave the variable declaration up at the top there so as to have them available inside the different functions.

Profiling; is that something I should be doing? If so got any instructions/links to instructions? I did a quick search and could only find PHP profilers for Drupal.
Thanks for your help improving both this and my JavaScript/Drupal skills :)

nickdickinsonwilde’s picture

Status: Needs work » Needs review
nod_’s picture

Status: Needs review » Needs work
+++ b/modules/toolbar/toolbar.js
@@ -1,6 +1,12 @@
+var $body
+var $toolbar

It's missing ";" on each line. Otherwise it's RTBC.

Profiling shows that Drupal.toolbar.height cost less than 1ms on a recent browser, I'm comfortable with that. Some of the slowness comes from the old version of jQuery, can't do much about it. I guess the only thing left if we want to be extra sure is to fire up IE6 and see how it goes. I don't have it though.

nickdickinsonwilde’s picture

Status: Needs work » Needs review
StatusFileSize
new3.74 KB

huh that's odd... Sublime *should* have warned me since I have jshint active but ah well, fixed that and review for any other typos or oddities and couldn't find any.
IE6... yes I have often done extra junk work to make websites support IE6 but I hate it and now that it is below 1% market I'm doing nothing extra to support it unless I absolutely have to.
Thanks for your help, Nod!
Happy New year!

nickdickinsonwilde’s picture

Status: Needs review » Reviewed & tested by the community

Since the two errors that nod_ found were fixed 10 days and he said other than that it was RTBC, I'm marking it RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: patch8.patch, failed testing.

Status: Needs work » Needs review

David_Rothstein queued 20: patch8.patch for re-testing.

David_Rothstein’s picture

Status: Needs review » Reviewed & tested by the community

Looks like a testbot fluke.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: patch8.patch, failed testing.

Status: Needs work » Needs review

David_Rothstein queued 20: patch8.patch for re-testing.

David_Rothstein’s picture

Status: Needs review » Reviewed & tested by the community

Testbot fluke.

nod_’s picture

For the record, #20 is indeed RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: patch8.patch, failed testing.

nickdickinsonwilde’s picture

Status: Needs work » Reviewed & tested by the community

What is with that Test bot fluke silly thing!

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs review
 (function ($) {

 Drupal.toolbar = Drupal.toolbar || {};
+// Since some selectors are being used in a resize handler lets cache them.
+// Need them available to all functions in the file so define here but for
+// edge-case of DOM not being loaded yet, set the selectors in Drupal.behaviors.
+var $body;
+var $toolbar;
+var toolbarHeightModifier = 0;

This seems really non-standard. Won't it break other code outside the toolbar module that is trying to use the Drupal.toolbar object?

For example, if you call Drupal.toolbar.height() from another module's behaviors, it seemed to work before but breaks after this patch...

A couple more minor notes:

  1. The above code comment really needs some improvement for grammar, etc. I tried to rewrite it a bit while trying to understand what it does and came up with this potential replacement:
    +// Since some selectors are used in a resize handler, they should be cached.
    +// Define them here since they need to be available to all functions in the
    +// file, but handle the edge case of the DOM not being loaded yet by waiting
    +// until Drupal.behaviors.toolbar.attach() is called to set their values.
    
  2. +  var bodyPaddingTop = parseInt($body.css('padding-top'),10);
    

    Should have a space between the comma and the "10".

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.